Macromedia Flash8 Image API 描述了一个的新的actionscirpt class类BitmapData 以及与其相关的各式各样的方法所带来的新的特性。这些新的方法使flash开发人员通过Actionscript在运行时创建并操作32位图像。这些Image Api非常类似于macromedia的产品Director中的lingo api.然而在flash8 的image api更细致准备,有更强的功能。在这篇文章中,我们将来研究如何开始使用Image Api并讨论它的一些能力。
在Actionscript 中使用Bitmaps
新的BitmapData 类用来描述在内存中的bitmap对象,当你创建一个新的类实例时,一个空的图像就已经保存在内存中了,你可以使用BitmapData类所提供的各种方法来操作这个原始的bitmap.在你开始应用BitmapData类之前,你需要先了解一个关于bitmaps的前前后后。
Bitmap是一个数字格式图形,它使用色彩数据网格来描述一张图像,在网格中的每一个单元格代表一个像素,每一个像素是都是由指定的色值渲染成的一个图像。Bitmap在flash player中被保存成32位色彩深度。这意味着每一个被指定了色彩的像素都是以二进制数保存,它的长度为32bit.在32位图像中的一个像素的颜色它可能只是16.7万色中的一种。每一种颜色又是由四种颜色通道如红,绿,蓝和alpha通道组成。
16进制颜色值
在Actionscript中与BitmapData类相关联的颜色值是以32位的十六进制数形式表示的。一个32位的十六进制数包含了4个十六进制数对,每一对是两个数。每一对十六进制数定义4色通道(红,绿,蓝,alpha)之中一种通道的强度,每一个颜色通道的强度是一个十六进制数,强度范围是0-255的十进数,FF代表最强(255),00代到在这个通道中没有颜色(0)。正如你所看的,每一个通道是两个数的长度,例如是01而不能写成1,这样确保在一个十六进制数中你总是有8个数,同时不要忘记需要加上十六进制数的前缀0x,例如纯白色用十六进制表示为0xFFFFFFFF。黑色正好相反,在红,绿蓝三个通道中都没有颜色所以我们写成0xFF000000。注意alpha通道,在十六进制数对中,它是第一对,它仍处于最强状态,alpha通道为FF为最强状态意味着没有alpha,也就是说完全不透明,00意味着完全alpha,也就是说完全透明。所以一个透明像素的颜色值为0x00FFFFFF。
ARGB转换为十六进制值
在通常情况下大多数人熟知的颜色值是ARGB格式也说每个值都使用的是0-255之前的数值,如果是这样,你需要知道如何将ARGB值转换为十六进制值,下面的代码告诉你如何来转换它们:
演示文件:
如下代码:
as 代码
- function argbtohex(a:Number, r:Number, g:Number, b:Number)
- {
- return (a<<24 | r<<16 | g<<8 | b)
- }
使用方法:
as 代码
- hex=argbtohex(255,0,255,0)
十六进制转换为ARGB值
演示文件:
要将十六进制值转换为ARGB十进制形式,使用下面的代码:
as 代码
- function hextoargb(val:Number)
- {
- var col={}
- col.alpha = (val >> 24) & 0xFF
- col.red = (val >> 16) & 0xFF
- col.green = (val >> 8) & 0xFF
- col.blue = val & 0xFF
- return col
- }
使用方法:
as 代码
- argb=hextoargb(0xFFFFCC00);
- alpha=argb.alpha;
- red=argb.red;
- green=argb.green;
- blue=argb.blue;
使用actionscirpt创建Bitmap
在actionscrpt运行创建bitmap,需要我们先创建bitmap类实例,如下代码:
as 代码
- myBitmap=new flash.display.BitmapData(width,height,transparent,fillColor)
Bitmap类存在于flash.display类包中,为了减少我们的输入量,在创建类实例时可以先导入类,如下代码:
as 代码
- import flash.display.BitmapData;
然后你就可以创建bitmap类的实例了,如下代码:
as 代码
- var myBitmap = new BitmapData(width,height,transparent,fillcolor);
BitmapData类构造函数接收四个参数分别是width(宽),height(高),transparent(透明度)和fillcolor(添充色)。Width和height用来指定所创建的bitmap的大小,如果你把bitmap想象为一个网格,那么宽就是水平方向的像素个数,高就是垂直方的像素个数。Tansparent是一个布尔值(true/false),它用来指定你是否打算让bitmap包含透明。Fillcolor参数用来指定在bitmap中每个像素的32位颜色。然而,如果你设置你的transparent值为false,那么前8bit所指定的颜色就会被忽略,因为在那种情况下就没有必要在传输32位的十六进制数了。取而代之的是,你可以传传输24位的十六进制数如0xFFFFFF的白色像素。Transparent和fillcolor两个参数是可选参数,如果你忽略他们,那么在内存中的bitmap就不会有透明并且每个像素都默认是白色如0xffffffff.
例如,你要创建一个黑色的100*100大小的,完全不透明的bitmap. 你需要用到如下代码:
as 代码
- import flash.display.BitmapData;
- myBitmap = new BitmapData(100,100,false,0Xff00000000);
注意:bitmap在flash player的限制大小为2880像素,如果你想创建超过这个大小的bitmap,那么bitmap是不会被创建的。因为创建超过限制大小的bitmap的会吞掉许掉客户端的RAM.
一旦你创建完了bitmapData 类的实例,你就有了众多的bitmapData方法可以使用,用来操作你的bitmap。例如,你可以指定滤镜效果,添充色彩,编辑色彩,使某个区域透明等等,可能性是无穷的。然而在这篇文章中我们主要研究一些基础的内容,帮助你开始,并发现。
清除BitmapData
一个BitmapData对象实例可以很快的吃掉访问者的内存,bitmap中的每个像素都要使用内存中的4个字节来保存。如果你创建的bitmap有500*500的大小,它将消耗掉1M左右的内存,如果你不在需要一个Bitmap对象,那最好的习惯是释放Bitmap所使用的内存,BitmapData提供了一个方法,帮你处理此事,dispose()方示,你只需要如下操作:
as 代码
记得要在你不使用BitmapData时,清掉bitmapData.以释放内存。
显示图像
一个BitmapData类的实例保存在内存中,它是不可见的直到你决定是时候让它显示时,你需要将bitmap贴加(attche)到舞台(stage)上以使它可以被渲染。你可以使用方法MovieClip.attachBitmap让BitmapData对象显不在任何movieclip当中。
as 代码
- import flash.display.BitmapData;
- myBitmap = new BitmapData(100,100,false,0Xff000000);
- this.createEmptyMovieClip(“holder_mc”,1);
- holder_mc.attachBitmap(myBitmap,1);
创建一个空的影片剪辑来显示bitmap是一个不错的主意,当你贴加bitmap到你的影片剪辑中时,是没有方法移除的,而如果你单独创建了一个空影片剪辑用来显示bitmap,那么你在不需要时可能通过移除movieclip来移除bitmap.
如下代码:
as 代码
- holder_mc.removeMovieClip();
当你贴加bitmap到影片剪辑时,你对bitmapData的任何修改,影片剪辑中的bitmap都会自动的更新,你不需要每次都重新贴加。
快照
BitmapData类有一个非常好的特性是它可以对任何动态的视觉元素做快照生成一个bitmap实例,如影片剪辑,video对象,文本域,这种特性可以让我们针对流式视频,摄像头或影片剪辑制作出一系列的静帧。
从一个movieClip或舞台上的其它实例对象创建bitmap,你需要使用BitmapData的draw()方法。默认情况下,这个方法绘制一个表现对象当前状态并且没有进行任何变形的bitmap,这意味着如果你正在获取一个视频对象的快照,视频对象发生了旋转,但是创建出来的bitmap是没有被旋转的。我们将在后面讨论它的细节。
现在,我们把精力完全集中在BitmapData.draw()方法上,从它的简单结构上看,这个方法只是用矢量渲染来绘制指定对象的bitmap.这个方法还可以用来指定融合模式给一个bitmap或是通过ColorTransform类来计算颜色的bitmap.
例如,假设你有一个movieclip对象存在于场景中名称为animation_mc,在它的内部有一些矢量动画。当在动画时,你可以获取到当前动画状态的bitmap.如下代码:
as 代码
- import flash.display.BitmapData;
- myBitmap = new BitmapData(animation_mc._width,animation_mc._height,true,0x00ffffff);
- myBitmap.draw(animation_mc);
变换矩阵
在flash8中增加了一个新的Matrix ActionScript类它可以把我们从创建变换矩阵的困难中摆脱出来。一个变换矩阵是一个3行*3列的数字,它反映的是从一个位置到哪一个的点阵图。使用变换矩阵,你可以在同一时间内进斜切,旋转,缩放和移动bitmap或是movieclip.仔细讨论Matrix 类已经超出了此文的范围。这里将介绍给你Matrix 类的一些方法,以满足你的日常应用。它是draw()方法中的第二个参数。
要创建变换矩阵,需要你先导入Matrix类,matrix类存在于flash.geom类包中。如下代码:
as 代码
- import flash.geom.Matrix;
然后你就可以创建Matrix类实例:
as 代码
这样我们就创建了一个默认单位矩阵,当指定给对象时,矩阵并没有改变对象的缩放,旋转,斜切和位置。
当你创建了一个矩阵之后,你可以使用矩阵所带的各种方法来编辑对象的属性和指定各种变换给对象。
你可以使用Matrix.scale()方法来编辑矩阵,当它指定给对象时,它就会针对对象进行缩放。例如,创建一个变换矩阵它将缩放对象到它之前两倍的大的大小,使用下面的代码:
as 代码
- import flash.display.Matrix;
- m = new Matrix();
- m.scale(2,2);
如果当你在变换矩阵时你想旋转你的对象,那么你可以使用Matrix.rotate()方法。这个方法接受弧度。要将旋转角度值转换弧度你需要用到下面的简单的数学方法:
as 代码
- radians =(degree/180)*Math.PI;
下面代码编辑变换矩阵,当你将这段代码应用到对象时,它将旋转对象45度。
as 代码
- .rotate((45/180)*Math.PI);
要移动一个指定了矩阵的对象,你可以使用Matrix.translate()方法,当你指定给一个对象时,对象就会显示在指定位置上。
as 代码
现在你已经有了一个矩阵,当它指定给一个对象时,缩放到对象的两倍大小,旋转45度,并设定它的位置为x=100,y=100.
变换快照
我们注意到之前我们提到的BitmapData.draw()方法接受一个变换矩阵做为第二参数。这使得你可以获取屏幕上的对象的快照,并且可能通过matrix对它进行编辑。
当你获取到一个影片剪辑的快照,在默认状态绘制的快照是没有应用过任何变换的。这意味着如果你旋转了场景中的movieclip并且缩放它的大小,但是快照并不会旋转或是缩放。然而,如果你指定了变换矩阵作为matrix.draw()的第二个参数,那么你就可以将上述的这些变换应用到绘制出来快照bitmap上。
当你缩放,旋转或是使用Actionscripta移动一个影片剪辑时。在flash player内部是使用变换矩阵来显示movieclip的正确位置。在flash8 播放器中你可以使用Movieclip.transform.matrix属性访问低级变换矩阵,这个属性返回正确变换值的Matrix类的实例。你可以使用这个属性来决定哪一种变换被应用到影片剪辑上。你还可创建与另一具有相同变换的影片剪辑。如下代码:
as 代码
- Movieclip1.transform.matrix=movieclip2.transform.matrix
下面的代码创建了一个包含square三角块的影片剪辑,使用Actiosncript对它进行缩放和旋转。如下代码:
as 代码
- import flash.display.BitmapData
-
- this.createEmptyMovieClip("square_mc",1)
-
- with(square_mc)
- {
- beginFill(0xFFCC00)
- lineStyle(1,0x000000)
- lineTo(0,100)
- lineTo(100,100)
- lineTo(100,0)
- lineTo(0,0)
- endFill()
- }
-
- square_mc._rotation=45
-
- square_mc._xscale=square_mc._yscale=200
如果你要获取上面影片剪辑的快照,这个三角形bitmap不会被旋转和缩放,除非你指定了matarix变换。如果你想让这个矩形影片剪辑在bitmap中呈现出与场景中一样的状态,你需要指定影片剪辑的变换矩阵做为draw()方法的第二个参数。
如下代码:
as 代码
-
- myBitmap =new BitmapData(square_mc._width,square_mc._height,true,0x00FFFFFF)
-
-
- myBitmap.draw(square_mc,square_mc.transform.matrix)
如果你不想让绘制的影片剪辑与场景中的一模一样,例如你可能想让bitmap的大小是movieclip大小的一半,你可以访问影片剪辑的变换矩阵编辑它,当它指定给对象时,你所做的编辑就会生效:
如下代码:
as 代码
- myBitmap = new BitmapData(square_mc._width/2,square_mc._height/2,true,0x00FFFFFF)
-
- m=square_mc.transform.matrix
-
-
- m.scale(0.5,0.5)
-
- myBitmap.draw(square_mc,m)
使用载入的图像
直接载入外部文件如(jpeg,gif,png或是flash影片)做为BitmapData类的实例是不可能的事情,你能做的就是将这些外部文件载入到一个影片剪辑中,当它载入完成后,然后你才能对影片剪辑应用bitmap快照。
as 代码
- import flash.display.BitmapData;
-
- this.createEmptyMovieClip("holder_mc", this.getNextHighestDepth());
-
- this.createEmptyMovieClip("show_mc",this.getNextHighestDepth());
-
- loader = new MovieClipLoader();
-
- loader.addListener(this);
-
- loader.loadClip("flower.jpg", holder_mc);
-
- function onLoadInit() {
-
- myBitmap = new BitmapData(holder_mc._width, holder_mc._height, true, 0x00FFFFFF);
-
- myBitmap.draw(holder_mc);
-
- holder_mc.removeMovieClip();
-
- show_mc.attachBitmap(myBitmap,this.getNextHighestDepth());
- }
-
- function onLoadError(){
- holder_mc.removeMovieClip();
- }
应用滤镜
完全讨论滤镜超出了这篇教程的范围。然而通过图片为了减少锯齿或是硬边,我们一般情况要针对图像就用模糊,因此我们来看如何针对bitmap应用滤镜。你可以使用BitmapData.applyFilter()方法直接对bitmap应用各种各样的滤镜,Flash player支持各种滤镜如Displacement,Blur,Glow,DropShadow,和Bevel.你可应用所有的滤镜到bitmap中的一个矩形区域或是整个bitmap对象。下面的代码针对从库中载入的bitmap应用模糊滤镜。如下代码:
as 代码
- import flash.display.BitmapData;
- import flash.filters.BlurFilter;
-
- myBitmap = BitmapData.loadBitmap("flower");
-
- blur = new BlurFilter(10, 10, 5);
-
- myBitmap.applyFilter(myBitmap,myBitmap.rectangle,myBitmap.rectangle.topLeft,blur);
-
- this.createEmptyMovieClip("holder_mc", 0);
- holder_mc.attachBitmap(myBitmap, 1);
ApplyFilter()方法的第二个参数可以让你在指定的矩形区域上应用滤镜,在上面的例子中,我们使用的是bitmap的rectangle属性,它返回的是flash.geom..Rectangle类实例,它的大小就是图像的大小,因此我们可以对整个图像应用滤镜。然而,在你需要的时候你可以改这这个矩形区域的大小来指定滤镜,你需要创建一个Rectangle类的实例并将它传给applyFilter方法做为第二个参数。如下代码:
as 代码
- import flash.display.BitmapData;
- import flash.filters.BlurFilter;
- import flash.geom.Rectangle;
- import flash.geom.Point;
-
- myBitmap = BitmapData.loadBitmap("flower");
-
- blur = new BlurFilter(10, 10, 5);
- rectangle = new Rectangle(50,50,200,100);
-
- myBitmap.applyFilter(myBitmap,rectangle,myBitmap.rectangle.topLeft,blur);
-
- this.createEmptyMovieClip("holder_mc", 0);
- holder_mc.attachBitmap(myBitmap, -1);
当你针对整个bitmap应用滤镜时,最终结果的bitmap可能要大于源图bitmap,例如,DropShadow滤镜要在bitmap四周增加像素.这使得生成的bitmap图像大于源bitmap图像,假设我们应用DropShadow滤镜到一个100像素宽高的bitmaph 上,它的距离是20像素45度角,当应用完滤镜后,结果的bitmap图像会超出16像素的大小,但是在这之前你并不清楚,只到你创建完bitmap对象之后,可能才会发现,当BitmapData对象创建完成后你是无法去修改它的。
还好有一种方式可以让你在应用滤镜之前决定最终bitmap的大小,因此你可以根据它来定义你的最终bitmap的大小。
as 代码
- import flash.display.BitmapData;
- import flash.filters.DropShadowFilter;
-
- myBitmap = BitmapData.loadBitmap("logo");
-
- dropShadow = new DropShadowFilter(5,45);
-
- filteredSize = myBitmap.generateFilterRect(myBitmap.rectangle, dropShadow);
- trace(filteredSize);
-
- w = (filteredSize.x<0) ? filteredSize.width-filteredSize.x : filteredSize.width;
- h = (filteredSize.y<0) ? filteredSize.height-filteredSize.y : filteredSize.height;
-
- fillColor = (myBitmap.transparent) ? 0x00FFFFFF : 0xFFFFFFFF;
-
- filteredBitmap = new BitmapData(w, h, myBitmap.transparent, fillColor);
-
- filteredBitmap.applyFilter(myBitmap, myBitmap.rectangle, myBitmap.rectangle.topLeft, dropShadow);
获取像素的颜色
你可以获取到bitmap中的任意像素的颜色,使用BitmapData.getPixel()方法可以返回以十进制式表示的指定x/y位置的RGB颜色值
as 代码
- import flash.display.BitmapData;
- myBitmap = new BitmapData(100,100,false,0xFFCC00);
- pixelColor = myBitmap.getPixel(50,50);
- trace(pixelColor);
要获得16进制格式表示的数值,们可以使用toString()方法:
as 代码
- trace("0x"+pixelColor.toString(16))
然而,你可能会现,当我们使用getPixel()方法处理包含alpha通道(BitmapData.transparent==true)的bitmap时,你可能会获得意想不到的结果.
BitmapData.getPixel32()方法返回基于十进制表示的指定x/y位置的ARGB像素颜色值。这种方法也会返加alpha通道的数据与getPixel()不同。
as 代码
- import flash.display.BitmapData
- myBitmap = new BitmapData(100,100,true,0x11FFCC00)
- pixelColor=myBitmap.getPixel32(50,50)
- trace("0x"+pixelColor.toString(16))
设置像素颜色
要设置像素颜色,你可以使用BitmapData.setPixel()方法。这个方法可以改变指定了x/y位置的像素颜色值。你指定的颜色是以24bit的十六进制形式表现的如0xFFCC00,alpha通道字节将被忽略。
as 代码
- myBitmap = BitmapData.loadBitmap("photo")
-
- for(i=0;i<1000;++i)
- {
-
- rx1=Math.floor(Math.random()*myBitmap.width)
- rx2=Math.floor(Math.random()*myBitmap.width)
- ry1=Math.floor(Math.random()*myBitmap.height)
- ry2=Math.floor(Math.random()*myBitmap.height)
-
- myBitmap.setPixel(rx1,ry1,myBitmap.getPixel(rx2,ry2))
- }
对于当前这个方法你只能用在不包含alpha透明通道(BitmapData.transparent)的图像上,否则你需要使用BitmapData.setPixel32()方法。SetPixel32()方法可以使你指定包含alpha通道数据的32位十六进制数据。
as 代码
- myBitmap.setPixel32(50,50,0xFFFFCC00)
设置像素组颜色
你可以使用fillRect()方法为一个矩形区域内的像素指定颜色。这个方法通常会用在还原最初bitmap块的颜色。因为你可以添充整个bitmap块的颜色,比擦除的效率要高的多。
这个方法的第一个参数是你想要添充的矩形区域。它是flash.geom.Rectangle类的实例。第二个参数是你想要改变的颜色。
要指定一个矩形区域,首先要先导入Rectangle类,Rectangle类存在于flash.geom.类包中:
as 代码
- import flash.geom.Rectangle;
- myRect = new Rectangle(0,0,100,100);
前两个参数是矩形的左上角x/y的位置,后两个参数是矩形的宽和高,你可以添充一个指定的颜色在矩形区域内。
如下代码:
as 代码
- myBitmap.fillRect(myRect,0xFFFF0000);
注意每一个BitmapData类都有一个返回bitmap对象大小和位置的属性。Bitmap对象的位置总在处在0,0的位置,因此它最有用的地方是供bitmap类的方法用来检测位置。这个属称为BitmapData.rectangle它返加一个Rectangle 类实例。
as 代码
-
- myBitmap.fillRect(myBitmap.rectangle,0xFF00FF00);
改变颜色范围
对你来说可能还有一件最复杂的事就是循环出每一像素的颜色然后改变它为其它颜色,如果你发现你需要改变颜色的位置是在同一色系的范围内,那么你不需要循环出每一像素的颜色,你可以使用BitmapData.threshold()方法,你可以分离和替换在同一色域范围内像素颜色。例如你想要一张图像上的所有红色像素透明,你可以使用下面的代码:
as 代码
- import flash.display.BitmapData
- import flash.geom.Rectangle
-
- myBitmap = new BitmapData(100,100,true,0xFFFF0000)
-
- centeredRectangle=new Rectangle(40,40,20,20)
-
- myBitmap.fillRect(centeredRectangle,0xFF000000)
-
- redPixelCount=myBitmap.threshold(myBitmap,myBitmap.rectangle,myBitmap.rectangle.topLeft,"==",0xFFFF0000,0x00FFFFFF)
BitmapData.threshold()方法返回是受影响的所有像素点的数值。
as 代码
你可以通过threshold来改变操作结果,threshold有四个参数:
as 代码
上面的打操作参数用于测试阈值的.你可以通过帮助文档来查看threshold,你还可以这样.如下:
as 代码
- myBitmap.threshold(myBitmap,myBitmap.rectangle,myBitmap.rectangle.topLeft,"!=",0xFFFF0000,0x00FFFFFF)
操作的结果与”==”的结果正是相反的.
复制像素
复制像素在我们的图像操作中是常用的.你可以使用BitmapData.copyPixels()从一个bitmap复制像素到另一个bitmap.这个方法从源bitmap复制你指定的矩形区域的像素到目标bitmap.你还可以使用一张带有alpha通道的图像做为遮罩来进行复制操作,这可以使用所复制的不是矩形而是一个区域。
下面的例子复制一个矩形区域从一个bitmap到另一个bitmap.
as 代码
- import flash.display.BitmapData
- import flash.geom.Rectangle
-
-
- myBitmap = BitmapData.loadBitmap("logo")
-
-
- area=new Rectangle(10,10,50,50)
-
-
- bitmapSlot=new BitmapData(50,50)
-
-
- bitmapSlot.copyPixels(myBitmap,area,bitmapSlot.rectangle.topLeft)
下面的这个例子是使用包含有一个圆形透明区域用做alpha遮罩来复制圆形区域的像素到另一个bitmap.
as 代码
- import flash.display.BitmapData
- import flash.geom.Rectangle
- import flash.geom.Matrix
-
-
- myBitmap = BitmapData.loadBitmap('logo')
-
-
- this.createEmptyMovieClip('mask_mc',1)
- mask_mc.lineStyle(75,0x00FF00)
-
- mask_mc.lineTo(0,1)
-
- maskBitmap = new BitmapData(100,100,true,0x00FFFFFF)
-
- m=new Matrix()
-
- m.translate(50,50)
-
- maskBitmap.draw(mask_mc,m)
-
- mask_mc.removeMovieClip()
-
- circleBitmap=new BitmapData(100,100,true,0x00FFFFFF)
-
- circleBitmap.copyPixels(myBitmap,myBitmap.rectangle,circleBitmap.rectangle.topLeft,maskBitmap,maskBitmap.rectangle.topLeft)
-
- this.attachBitmap(circleBitmap,1)
-
- maskBitmap.dispose()
ps by egoldy: flash8 BitmapData可以说是自flashmx2004升级为flash8后的最常用的类之一,但Bitmap的应用并不是纯Actionscirpt的应用。需要有一此相关的图像理论知识,比如颜色,alpha通道,threshold,像素,此文多少有一些偏向理论,所以发现过程文件无法在页面上展示,如果你遇到问题请在论坛里发问。