利用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位颜色0xRRGGBB和32位颜色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个数组的映射保存好,作为参数传入就可以了。