BitmapData的整理

最近在看BitmapData这个类,对这个东西也不是很熟悉,所以在网上看了一些资料,现在把他们都整理了一下,我想通过以下这些会让大家会对BitmapData这东西有个深刻的了解,对大家的理解有所帮助。

利用BitmapData的优势: 

我们知道传统的矢量渲染模式下,任何元件的位移和变型以及任何改变显示的变化都会使得Flashplayer对其进行绘制,并渲染到显示器。(Fl9以后有所优化,但改变不了根本)而BitmapData可以先进行像素数据的操作,操作之后在进行渲染。并且跳过FP的绘制,直接将像素数据交给显示渲染。 

开发游戏的角色使用mc(影片)还是BitmapData?

很多的游戏,都是使用mc的,mc的优点是很直观,所见即所得,占用内存很少,缺点是效率不高(当效率是瓶颈的时候是缺点,其他时候可能也不算)。

BitmapData的优点是效率高,管理有些麻烦,占用内存高。

小问题,为什么mc效率没Bitmap高呢?
mc中的位图在编译后,是以shape形式存在,也就是说,使用的是矢量渲染器渲染,进行位图填充,效率很低。
mc中的矢量图片,也是用矢量渲染器渲染,复杂的图像,非常耗cpu。
BitmapData的是将数据存在内存中,真正的位图渲染,效率非常高。

BitmapData的理解

 

BitmapData主要提供的是对图像的“像素级”的操作,如果你想切实感受一下,有个挺好的办法,打开Flash,然后CTRL+R导入一张图片,然后再按CTRL+B打散,这时得到的图片状态就有点BitmapData的味道了···而其他用FLASH矢量工具画出来的都可以理解为BitmapData的一种。

下面再深一步说,BitmapData的名字可以拆开来看,就是Bitmap+Data,翻译成中文就是:位图数据,所以它可以看作数据储存的一种,而不是真正的显示对象,要想看到BitmapData,我们需要把Bitmapdata赋到一个Bitmap对象中,然后addChild(Bitmap),那么就能看到具体的画面了

那么BitmapData的像素级操作作用在哪呢?比较大家喜欢津津乐道的就是粒子效果,作为一个需要大量计算的应用来说,1像素长宽的粒子无疑是能存在的最小的粒子;另外一个是作为数据传输,大家如果想实现上传图片或者下载图片的效果,基本的理念就是将Bitmapdata使用JPEGEncoder编码成二进制数据,把二进制发送给服务器端;第三种是滤镜视觉特效,例如一些水波划动特效;第四种是视频摄像头的视频检测;当然还有很多有趣的玩法,例如通过Bitmapdata压缩数据之类的。

(注:从上面性能来看,对数据的传输,对数据的压缩,和运用的效率来看,利用BitmapData还是一种很有效的方式。);

 

使用Bitmap和BitmapData时很容易犯一个错误

flash.display.Bitmap
The Bitmap class represents display objects that represent bitmap images.

flash.display.BitmapData
The BitmapData class lets you work with the data (pixels) of a Bitmap object.

由此可知Bitmap Class的主要功能是显示点阵影像,而BitmapData Class的功能主要是处理Bitmap每个像素资料
所以当我们要处理影像时千千万万不要对Bitmap下手,因为Bitmap的功能只能把影像的资料显示出來,而要处理影像必須先把Bitmap的次料交給BitmapData,再由BitmapData来对每个pixels处理才行,还有一个也是经常有人会发生的错误是直接把BitmapA的bitmapData Assign給BitmapB的bitmapData,当对BitmapB的BitmapData做更动时BitmapA也会跟著更动因为这两个Bitmap根本就Bindding同一个BitmapData,就像两个DataGrid Bindding同一份DataProvider的意思是一样的,当其中的DataGrid的dataProvider做修改,两个同时都会修改,所以当希望两个影像能各做各的事的话记得要再new一个新的BitmapData才行,否则只会把两个影像的资料绑死在一起。

二,公共属性

BitmapData的公共属性很少,只有4种,而且都属于Read-Only(只读),只读的意思就是“只能读”(好废话),所以我们可以取出BitmapData的属性来做运算,但是却不能赋值给它们,跟只读区别的就是Read-Write(读写)

有时程序有莫名其妙的问题,可以查看帮助文档,是不是因为你尝试对只读属性进行了赋值导致的。

1,height

就是Bitmapdata存储像素数据的高度

2,width

同理,就是Bitmapdata存储数据的宽度,这里扯多一句,一般保存长宽的都是Number属性,因为长宽可能存在小数点,而有些其他的属性可能是int的,把带有小数点的值赋值给int的属性的话,会自动把小数点后面的数值去掉,造成一些莫名其妙的错误,所以写代码的时候要多注意看代码提示里的属性说明。

3,transparent

是一个Boolen值,表示此Bitmapdata是否支持透明像素,一般的颜色分为16位颜色0xRRGGBB32位颜色0xAARRGGBB。其中0x是16进制数字的意思,后面的每两位都代表着0~F,16个范围,所以每个颜色通道都有16*16=256位的数值,其中32位颜色就是多了一个AA(透明度)通道。

4,rect

返回BiamapData所占的矩形对象(Rectangle),你可以暂时理解为一个对象,这个对象储存了x,y,width,height等数值。

三,公共方法

BitmapData一共有32个公共方法,当然一部分是成对出现的get/set方法,让我们来一一介绍。

1,构造方法

BitmapData(width:int, height:int, transparent:Boolean = true, fillColor:uint = 0xFFFFFFFF)

构造方法有4个参数,其中两个必填,就是长宽,这两个值的输入保持“用多少填多少”的原则,因为Bitmapdata也是一种形式的内存开销,所以能省就省。第三个是transparent,就是是否允许透明像素,原则同上,如果能确定不用的话,最好关掉,默认为允许,第四个为填充颜色,bitmapdata既然是data,那肯定要有初始数据的存在,一开始是一些纯色的填充,默认为白色。

2,应用滤镜

applyFilter(sourceBitmapData:BitmapData, sourceRect:Rectangle, destPoint:Point, filter:BitmapFilter):void

这个函数很有意思,在我的印象里,bitmapdata.applyFilter就是直接对bitmapdata进行一次滤镜算法,然后把其中的像素进行从新赋值,那为什么会有这么四个参数呢。

我印象中的处理过程是:BMD--->滤镜算法--->得到的新BMD

而实际上确是:

Step1:

sourceBitmapData--->(sourceRect滤镜的作用矩形区域)--->filter(滤镜)--->新的BMD(长宽为作用矩形区域sourceRect的长宽)

Step2:

原来的BitmapData--->在destPoint的x,y位置上--->画上新的BMD

这样一来,除了可以实现对自己实施滤镜,还有了更多的可操作性。

3,复制

clone():BitmapData

这个与之前介绍的复杂类型一样,这里就不多说了,详情可参考之前的Matrix的clone方法介绍部分。

4,变色

colorTransform(rect:Rectangle, colorTransform:ColorTransform):void

这个有点头疼,牵扯到ColorTransform类,也是一个大家比较陌生的类,那么这个hold一hold,大家先知道这个函数作用就是将某一rect的区域按colorTransform的定义进行变色。

5,与其他BitmapData进行像素值的"比较",其实就是求差异(或者叫各像素相减得的差)

compare(otherBitmapData:BitmapData):Object

首先这两个BMD的比较分为几种情况:

(1)如果宽度不相同,函数返回-3。

(2)如果高度不相同,函数返回-4;

(3)如果宽高都不相同,先算宽,即函数返回-3;

(4)如果两个BMD完全相同,函数返回0;

(5)如果两个BMD长宽相同,颜色不同,则返回一个新的Bitmapdata对象,新BMD对象特征如下:

bmd1.compare(bmd2);

新BMD的每一点像素值为bmd1减bmd2所得,由于有Alpha存在,当RRGGBB不相同时,忽略Alpha的比较,新值为0xFF(RRGGBB差);当RRGGBB相同时,则返回Alpha的差,新值则为0xZZ(Alpha差)XXXXX(RGB值)。

总的来说就是先比较颜色,颜色不同的情况下就不考虑透明度。颜色相同就看透明度的差异。不修改原对象,只返回一个新的BitmapData对象。具体玩法还不明,呵呵。

6,复制通道

copyChannel(sourceBitmapData:BitmapData, sourceRect:Rectangle, destPoint:Point, sourceChannel:uint, destChannel:uint):void

这个就是对某一区域内所有像素的颜色通道的替换。sourceBitmapData:BitmapData, sourceRect:Rectangle, destPoint:Point这三个参数分别对应作用BMD,作用区域,和生成图在原BMD的位置。sourceChannel:uint, destChannel:uint这两个参数就是分别对应用哪个通道的值,去替换哪个通道。具体的通道保存在BitmapDataChannel类中。

注意,这类替换过程并不影响sourceBitmapData的像素信息,他只是将计算的结果重新赋值到原BMD的对应位置上。

7,复制像素

copyPixels(sourceBitmapData:BitmapData, sourceRect:Rectangle, destPoint:Point, alphaBitmapData:BitmapData = null, alphaPoint:Point = null, mergeAlpha:Boolean = false):void

sourceBitmapData, sourceRect, destPoint老三样,就不说了,说说其他三个参数。

alphaBitmapData和alphaPoint貌似是在Copy时有关Alpha通道的Map映射,作为Alpah通道值传入,而mergeAlpha则为是否复制Alpha通道的开关。

后面三个参数其实也不是太确定用法···不过平常的使用前面的就可以了,在涉及到Alpha通道的复制时可以再深入研究。这个函数可以用作截图,当然另外的一个draw方法也可以。

8,释放内存

dispose():void

这个主要作用是释放掉分配给BitmapData的内存,并将宽高设置为0,此后的所有对BitmapData的操作都将不生效。

9,draw方法,显示对象BitmapData化

draw(source:IBitmapDrawable, matrix:Matrix = null, colorTransform:ColorTransform = null, blendMode:String = null, clipRect:Rectangle = null, smoothing:Boolean = false):void

这里的六个参数,除了第一个是必选外,其余的都是可选:

source:要被“画”的对象。

matrix:一个变型矩阵,作用于BitmapData。

colorTransform:一个颜色变换,作用于BitmapData。

blendMode:图层叠加模式。具体的模式可以在BlendMode 类中找到。将BitmapData与source进行图层叠加。

clipRect:定义了draw source的区域。

smoothing:定义是否进行图像平滑。只对source是BitmapData时起作用。

这个绝对是BitmapData的重头戏,非常常用的方法。画一切可以“画”的对象,就是文章开头提到的实现了IBitmapDrawable接口的对象都可被“画”。BitmapData和DisplayObject都实现了这个接口。

这样做的好处是可以在显示对象不需要被使用的时候Draw一个假的放在舞台上,或者有很多元件在舞台上运动的时候,统一把结果Draw在一张BitmapData上,节省CPU的开销,实现用内存换取CPU性能

注意,如果跨域没有安全文件的话,draw方法是无法draw到内容的,不过这种情况在一般的内容里不会出现。

10,填充矩形

fillRect(rect:Rectangle, color:uint):void

这个应该很好理解,就是输入一个矩形对象,然后用对应的颜色填充这块矩形对象的区域就OK了。

11,颜料桶填充

floodFill(x:int, y:int, color:uint):void

这个也是另外的一种填充,模拟的是我们平常在IDE里进行的颜料桶填充方式(选中颜色,选中填充的点,就会将所有附近相同颜色的像素一起填充)。对应的x,y就是点的坐标,color自然就是颜色啦。

12,计算滤镜作用区域

generateFilterRect(sourceRect:Rectangle, filter:BitmapFilter):Rectangle

因为滤镜的作用区域不一定总等于输入的作用区域,所以这个函数是用来计算滤镜的实际作用区域的,输入的是一个矩形区域sourceRect和需要作用的滤镜filter,返回的是实际滤镜会影响到的矩形。

13,获取颜色区域

getColorBoundsRect(mask:uint, color:uint, findColor:Boolean = true):Rectangle

这个在做摄像头应用的常用来检测颜色的区域。返回的是由所有符合条件的像素组成的最大矩形

color:就是要查找的颜色

findColor:为true时,是查找与color相同的颜色;为false则是查找与color不相同的颜色。

mask:是一个与输入color的掩码操作,作用是例如我只想进行某个通道的颜色比对时,可以不必管其他通道的的具体值。具体的运算方法是&(按位 AND),即逻辑与或非中的“与”操作,具体的结果是1&1=1,1&0=0&1=0&0=0,是二进制下的运算。

至于怎么比对?其实0xF = 二进制下的1111,类似的转化而已。

14,取得某点颜色(16位版)

getPixel(x:int, y:int):uint

很简单,就是取得x,y点的颜色(不包含Alpha通道)。

15,取得某点颜色,(32位版)

getPixel32(x:int, y:int):uint

同上,不过这次包含了Alpha通道

16,取得区域的像素二进制信息

getPixels(rect:Rectangle):ByteArray

这个函数是将一片区域rect内的所有图形信息,打包成一个二进制数组类ByteArray,作用是可以在头像上传时上传用户选择的部分。二进制数组类ByteArray也是一个高级的类,以后会有介绍。

17,获取区域内的像素矢量数组Vector

getVector(rect:Rectangle):Vector.<uint>

Vector这种数据结构是FP10以后新加的,那么这个方法对应的也只能在FP10或以上版本里使用。学过Java的同学可能很熟悉,其实Vector是一种固定数据类型的数组。即这个数组里的所有内容都必须是某种数据类型的。这样做的好处是因为事先规定好了数组的类型,那么在使用时不用花时间去判断弱类型,大大提高了运行效率,其他的使用方法大概跟Array一样。

那么这个函数其实没有太多的难点,就是返回一个Vector,里面包含的都是每一个像素的颜色信息而已。

18,获取区域内通道信息矢量数组Vector

histogram(hRect:Rectangle = null):Vector.<Vector>

这个也是FP10的新API,具体作用跟getVector很像,只是将getVector的结果继续拆分了而已。

返回的Vector里面有4个Vector,4个Vector里面装的是4个通道(Alpha,Red Green,Blue)的值0~255。再巩固一下Vector是有类型的数组,所以返回的是Vector.<Vector>,而4个Vector则是Vector.<Number>。

19,不规则碰撞检测(高级碰撞检测)

hitTest(firstPoint:Point, firstAlphaThreshold:uint, secondObject:Object, secondBitmapDataPoint:Point = null, secondAlphaThreshold:uint = 1):Boolean

详细的介绍可以参考《ActionScript Animation》,中文译名好像就Flash高级动画教程还是啥的,封面是个长颈鹿的··这本书挺出名的···

这里转一些介绍(其实配合上调用函数的对象,是6个参数)高手介绍的比我清楚得多:

注意到这5个参数被分成了两组:一个和另一个。每组都需要一个点来确定位图的左上角起点。

接着每组都还有一个透明阈值。之前提到过,支持透明的位图对象,每个像素的透明度取值范围在0(完全透明)到255(完全不透明)。参数透明阈值即指定, 透明度在多少的时候就算碰撞。

最后还剩一个参数,另一个对象。注意它的类型是Object。允许传递的可以是一个点(Point),一个矩形(Rectangle)或者另一个位图对象 (BitmapData)。如果传一个点或者一个矩形,那么后面的两个参数可以忽略。

到此,测试都是围绕着Bitmap对象。而大多情况下的MovieClip,Sprite和Shape对象是没法用hitTest的。有个办法就是暗中准备一些BitmapData,不把它们加入到显示列表。当要对两个显示对象进行碰撞检测时,先把它们分别绘制到一个准备好的位图对象中,然后如法炮制。要知道,这不是唯一的办法,却是个不错的办法。

20,锁定变化

lock():void

因为对像素的操作涉及很多中间步骤,如果每操作一次都更新一次,那么如此大的计算量会把CPU拖垮的,这个函数的作用就是把BMD锁住,只保存更新步骤,而不更新实际像素。在做粒子效果时如果没有这一步绝对卡死人。

21,图像合并

merge(sourceBitmapData:BitmapData, sourceRect:Rectangle, destPoint:Point, redMultiplier:uint, greenMultiplier:uint, blueMultiplier:uint, alphaMultiplier:uint):void

头三个参数又是老三样,不多说。

后面的4个参数分别是AARRGGBB通道Multiplier

计算方法为新值=Source通道*Multiplier;

22,生成噪点

noise(randomSeed:int, low:uint = 0, high:uint = 255, channelOptions:uint = 7, grayScale:Boolean = false):void

生成一堆杂乱无章的图像填充BMD,意义何在??一般是做贴图的MAP映射吧···创造出凹凸不平的效果,一般很少人会直接用吧···

randomSeed:随机的一个种子,就是从这个数字生成一大堆噪点图

low,high各通道在0~255区间取的最低和最高值

channelOptions:uint (default =7) — 一个数字,可以是四个颜色通道值的任意组合。 您可以使用逻辑 OR 运算符(|)来组合通道值。 (谁看的懂谁告诉我···我是不知道他想怎样了)

grayScale:这个如果设为true,则生成像素的RGB值将相等,即生成“灰度图”。如果是false则是为有色彩的。

23,调色板

paletteMap(sourceBitmapData:BitmapData, sourceRect:Rectangle, destPoint:Point, redArray:Array = null, greenArray:Array = null, blueArray:Array = null, alphaArray:Array = null):void

这个API在摄像头检测中有很重要的应用,回想刚刚的getColorBoundsRect(不用回想了,如果你能看一次就记住才有鬼了,还是拖上去看看吧),:D,检测一个0xRRGGBB的颜色?见鬼!256x256x256=16777216种颜色,才定义其中一种??除非是我自己填的,不然找啥啊~~

paletteMap函数的作用就是重新映射各个通道的范围,例如你可以把Red通道的颜色区间从原来的256种红映射成16种红,大大提高了你的检测成功率。

头三个参数还是老三样(我发现这句都成我口头禅了,哈)。不多说。

后面4个参数其实是一类的,四个通道AARRGGBB。

那么我们应该输入什么进这些数组呢·?答案是256长度的内容,对应各个通道的256个值,但是这个值是我们来定义的。

这里注意的是,由于最后的颜色是四个通道相加出来的,所以redArray的值应该是0x00000000~0x00FF0000,要将具体的值移位到正确的位置上。这里介绍两个大家平常很少用的二进制位操作符<<和>>,作用就是将二进制数全部向左或者向右移一位。

只要按你想要的把4个数组的映射保存好,作为参数传入就可以了。

posted @ 2011-02-17 17:38  as爱好者  阅读(7546)  评论(1编辑  收藏  举报