注:文中的Bitmap data和BMD均为同一意思BitmapData ,BMD为其缩写
------------------------------------------------------------------------------------------------------------
今天介绍另外一个比较常用和中高级难度的类:BitmapData
用好这个类,可以说是半支脚踏入了Flash 高手 的大门···(主要是不是太多的人精通这个··呵呵··)我也可以趁这篇文章的机会好好巩固+学习···
好,长话短说··马上进入正题:
一,概括:
Bitmapdata继承Object对象,实现IBitmapDrawable接口,这个接口有什么用,你可以理解为Drawable,能被画。官方介 绍是:IBitmapDrawable 接口由可作为 BitmapData 类draw()方法的source参数传递的对象来实现。 这些对象的类型为 BitmapData 或 DisplayObject。 其实就是能被“画”,这点我在一会的公共方法中会详细介绍。
个人理解来说,BitmapData主要提供的是对图像的“像素级”的操作,如果你想切实感受一下,有个挺好的办法,打开FLASH IDE(其实就是Flash),然后CTRL+R导入一张图片,然后再按CTRL+B打散,这时得到的图片状态就有点BitmapData的味道了··· 而其他用FLASH矢量 工具 画出来的都可以理解为BitmapData的一种···
刚刚说只是想大家对BitmapData有模糊的了解,下面再深一步说,BitmapData的名字可以拆开来看,就是Bitmap+Data,翻译成中文就是:位图 数据 ,所以它可以看作数据储存的一种,而不是真正的显示对象,要想看到BitmapData,我们需要把Bitmapdata赋到一个Bitmap对象中,然后addChild(Bitmap),那么就能看到具体的画面了···
那么BitmapData的像素级操作作用在哪呢?比较大家喜欢津津乐道的就是粒子 效果 ,作为一个需要大量计算的应用 来 说,1像素长宽的粒子无疑是能存在的最小的粒子;另外一个是作为数据传输,大家如果想实现上传图片或者下载图片的效果,基本的理念就是将 Bitmapdata使用JPEGEncoder编码成二进制数据,把二进制发送给服务器端;第三种是滤镜视觉特效,例如一些水波划动特效;第四种是视频 摄像头的视频检测;当然还有很多有趣的玩法,例如通过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个数组的映射保存好,作为参数传入就可以了。
24,柏林噪声函数
perlinNoise(baseX:Number, baseY:Number, numOctaves:uint, randomSeed:int, stitch:Boolean, fractalNoise:Boolean, channelOptions:uint = 7, grayScale:Boolean = false, offsets:Array = null):void
上网查了一下··这个柏林噪声函数好像是蛮出名的一个函数···同样是产生噪点,从视觉效果来说,柏林函数的效果更漂亮,蒙胧很多(很像PS里的云彩滤镜),而noise的话就很想电视机的杂点。
说说这里的九个参数:
baseX,baseY:帮助里说的是X和Y轴上的频率,可以理解为噪声的区域的长和宽···注意,这里的长和宽不是总的长宽,总的长宽由bitmapdata的长宽决定,这里说的噪声区域的长宽说的是单个噪声区域的长宽,总的图像由很多个这样的噪声区域组成
numOctaves:uint — 要组合以创建此杂点的 octave 函数或各个杂点函数的数目。 octave 的数目越多,创建的图像越细腻。 octave 的数目越多,需要的处理时间也会越长。 (专业术语我也看不太懂··好像是用来控制生成杂点函数octave的数量的 )
randomSeed:随机种子,通过这个生成不同的分布
stitch:中文意思是缝合,当设为true时将对不同的噪声区域进行无缝拼合。但是老实说,我设了一下false,也没看出什么区别嘛………
fractalNoise:另外一个参数,这个蛮明显的,设为true时图像将显得有种烟雾的效果,渐变比较连续。而为false时,则显得有些锐利,帮助说可以用来制作火焰和海浪效果··这个,怎么做呢???
channelOptions:跟之前的noise一样,都是把几个通道的数值进行与或非之类的操作吧···
grayScale:与之前的noise一样,设为true将生成灰度图。
offsets:一个数组,长度对应之前设置的numOctaves,定义了每个点的x,y偏移量。
25,像素溶解(听名字不懂,看解释吧)
pixelDissolve(sourceBitmapData:BitmapData, sourceRect:Rectangle, destPoint:Point, randomSeed:int = 0, numPixels:int = 0, fillColor:uint = 0):int
这个函数很迷糊,但是很有意思。如果你打开帮助看看他的例子就会发现了。动画效果还是蛮Cool的(其实Cool在哪??汗··可能只有我们程序员觉得Cool吧··)
总的来说就是每次随机取几个点,然后填充过去,然后再取几个点,继续填充,一直到完全填充完成为止。因此需要不停的调用。
解释解释参数和返回值,还有两种情况的运作方式。
6个参数,头3个还是老三样(又来了,汗),那我们从第四个开始说起吧
randomSeed:产生随机数的随机种子
numPixels:每次变化的像素数目
fillColor:要填充的颜色
返回的是后续调用需要用的新的随机种子,这个可用可不用了
这个函数分两种情况,当sourceBitmapData就是原BMD时,用fillColor定义的颜色进行填充,不考虑destPoint的偏移。当sourceBitmapData不是原BMD时,用sourceBitmapData对原BMD进行填充。
26,滚动Bitmapdata
scroll(x:int, y:int):void
对BMD水平和垂直移动,这个很好理解。
注意!!滚动的只是原来定义的Bitmapdata,对于由于X,Y移出区域的Bitmapdata的位置,将按边缘像素进行填充。但是新填充的区域,不会参与同一次的X,Y滚动。
即scroll(40,40)和scroll(40,0);scroll(0,40)得到的结果不同。
27,设置某点颜色(16位)
setPixel(x:int, y:int, color:uint):void
像素级的操作来了(其实之前也有的··),这个函数可以单独设置BMD某个点的颜色,三个参数分别是x,y,颜色。对应位置和颜色,很好理解吧,不多说了。
28,设置某点颜色(32位)
setPixel32(x:int, y:int, color:uint):void
跟上面的setPixel非常类似,只是设置的颜色是32位(包含Alpha通道)而已。
29,二进制数组(ByteArray)填充
setPixels(rect:Rectangle, inputByteArray:ByteArray):void
这个函数跟setPixel的区别在于多了一个“s”,这个s嘛,在英语里就是复数的意思,所以此函数的作用是同时设置多个像素。其中一个作用可以是在接 收到服务器传来的图像的二进制数据并将其转化为BitmapData数据。当然这个目前就无法做DEMO了,但是我们可以用自带的API自娱自乐一把。还 记得set的好兄弟get吗?我们之前就介绍过setPixels函数,这两个可以配套使用。
输入的参数:
rect:输入数据填充的区域。至于是从左到右还是从右到左还是从上往下还是从下往上,我也不太清楚。其实我还是清楚一点的,应该是从左往右,从上往下填 (做了实验的),如果有错请高手指出。注:如果二进制数值不足以填充矩型区域,会引发错误。所以记得用try,catch包好。
inputByteArray:输入的二进制数组。
30,Vector数组填充
setVector(rect:Rectangle, inputVector:Vector.<uint>):void
跟ByteArray填充差不多,不过这次用的是Vector数组。测试也可以用set的好搭档:getVector。
注:Vector是FP10的新数据结构,使用要用FlashPlayer10或以上版本。
31,颜色阈值函数(比较函数)
threshold(sourceBitmapData:BitmapData, sourceRect:Rectangle, destPoint:Point, operation:String, threshold:uint, color:uint = 0, mask:uint = 0xFFFFFFFF, copySource:Boolean = false):uint
这个也是个功能很强大的函数,在摄像头应用中会用到,用来简化颜色。
作用概括来说,就是设定比较的条件,对符合条件的像素颜色,统统设置为一个新的值。
有8个参数,头3个老三样(我又来了),让我们来说后五个:
operation:比较条件,“<”、“<=”、“>”、“>=”、“==”“!=”
threshold:这个单词大家不是很熟,是阙值,就是我们要用来进行比较的颜色值。
color:比较结果为true之后,像素颜色设置的新值。
mask:掩码。可以把你不想比较的通道屏蔽掉。
copySource:当sourceBitmapData不等于原BMD的时候有用。设置为true时,当比较失败时仍将sourceBitmapData的数据Copy过去原BMD。而false时就不Copy。
返回值是已改变像素的数目,也可以用来做判断结果,有多少像素达到了某某要求。
32,解锁
unlock(changeRect:Rectangle = null):void
配合之前的lock()来用,目的是为了在多次操作过程中停止更新,节省CPU效率。附带了一个参数changeRect,是可以设定解锁的区域,可以只将变化了的区域解锁,这样就不用更新整张BMD,进一步节省了CPU。
总结:
Bitmapdata的API很多,而且也有很多的自己也不熟悉,断断续续的写了三天多,之间又有其他事情做。所以可能有些名词没有深入解释,只是一笔带过;或者语言风格的不统一;可能还有些地方自己也没弄明白讲的也不太好,缺陷还有很多。以后还需要继续努力。
这次也是对Bitmapdata的一个基础介绍,具体的应用可以上网看到很多,而且这个类的玩法也很多。只有掌握扎实了基础知识,才能看懂学习别人精彩的算法。