canvas JavaScript API学习(五)

canvas JavaScript API学习(五)

写在前面
我们了解了canvas用来处理图像的两个简单的方式:拉伸和裁切。这次我们来挑战像素级的图像处理,这话看起来挺唬人的,不过不用担心,它并没有那么可怕。

像素处理API
你可以通过ImageData对象在字节级的水平来处理图像数据,先看看与此相关的一些API属性及方法:

imagedata = context . createImageData(sw, sh)
根据给定的尺寸返回一个ImageData对象,该尺寸为CSS像素值(CSS Pixel),返回的对象中的像素点都是黑色透明的,即rgba(0,0,0,0)。

imagedata = context . createImageData(imagedata)
返回一个跟参数所指对象大小一致的ImageData对象,返回的对象中的像素点都是黑色透明的。

imagedata = context . getImageData(sx, sy, sw, sh)
返回包含canvas指定区域图像数据的ImageData对象

imagedata . width
imagedata . height
返回ImageData对象数据的实际尺寸,该值为设备像素值(Device Pixel)。

imagedata . data
返回一个一维数组,该数组包含按照RGBA顺序排列的范围从0到255的数据

context . putImageData(imagedata, dx, dy [, dirtyX, dirtyY, dirtyWidth, dirtyHeight ])
将指定的ImageData对象的数据绘制到canvas上。

备注:globalAlpha,globalCompositeOperation,还有shadow属性在调用该方法时会被忽略。

createImageData()方法会根据所给的参数创建一个以sw为宽,sh为高的空白ImageData对象,当该方法只有imagedata 参数时,它将返回一个与参数所指的ImageData对象一样大小的ImageData对象,并且返回的ImageData对象是被填充为透明黑色的(transparent black)。

getImageData(sx, sy, sw, sh)方法返回包含在canvas坐标系中由(sx, sy), (sx+sw, sy),(sx+sw, sy+sh), (sx, sy+sh)四个坐标在canvas上所围成区域的基本像素数据的ImageData对象,如果该区域超出了canvas范围,超出的部分被填充为透明黑色的(transparent black)。

如果createImageData()和getImageData()的参数值是无穷的或NaN,或者createImageData()只有一个参数值为null,方法会抛出NOT_SUPPORTED_ERR异常,如果值为0则抛出INDEX_SIZE_ERR异常。

ImageData对象必须被初始化,有宽度和高度,data属性值被初始化为一个CanvasPixelArray对象用来存放图像数据,至少要返回一个有效的一像素图像数据。

CanvasPixelArray对象包含了图像数据每个像素点有序的可索引的色值数据。这些数据从上到下,从左到右(即从左上角开始)描述了各个像素点的红,绿,蓝还有alpha值,它们的取值范围从0到255,用8个比特的数据描绘一个值。因此,该CanvasPixelArray对象包含了w×h× 4字节的数据,一个CanvasPixelArray对象的length属性必须返回这个数字。因为该对象可索引的范围就是[0,w×h× 4-1]。

注意:这里所说的宽(w)和高(h)有别于sw和sh,比如当canvas支持高分辨率的位图或sw与sh为负数时。

putImageData(imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight)方法把ImageData结构的数据描绘在canvas上,如果任一参数值是无穷或NaN的,它将抛出NOT_SUPPORTED_ERR异常;如果第一个参数不是ImageData对象或为null它将抛出TYPE_MISMATCH_ERR异常;如果最后四个参数被省略,那它们将分别被赋值为0,0,imagedata的width和imagedata的height值。

像素处理实例
看了上面那么大一段的描述,估计你也头晕了,我也是,我想来看几个例子比较有助于理解。先来看第一个Demo。查看Demo

XHTML

<!DOCTYPE html><html><head><meta  charset= »utf-8″ /><title>Canvas javascript api demo</title><style type= »text/css »>canvas { border:1px #000 solid;}</style></head><body><h1>this is a canvas api test page!</h1><canvas id= »canvas » width= »300″ height= »300″>this browser does not support canvas…</canvas><a href= »http://blog.wanz.im/2010/04/28/canvas_javascript_api_learning_five/ »>返回文章</a><script type= »text/javascript »>var $=function(id){ return document.getElementById(id);}window.onload=function(){ var ctx=$(‘canvas’).getContext(‘2d’); var img=new Image(); img.src=’firefox.jpg’; img.onload=function(){ ctx.drawImage(img,0,0,240,240,30,10,120,120); //for security reason,you should turn on UniversalBrowserRead in Firefox. //netscape.security.PrivilegeManager.enablePrivilege(« UniversalBrowserRead »); imgData=ctx.getImageData(30,10,120,120); ctx.putImageData(imgData,30,160); }}</script></body></html>

这段代码很简单,在上篇文章的Demo中加入了getImageData和putImageData两个函数实现了图像的复制。如果你将代码保存到本地测试了并且没有效果那就对了,在Firefox的错误控制台中你会看到:

错误: uncaught exception: [Exception… “Security error” code: “1000” nsresult: “0x805303e8 (NS_ERROR_DOM_SECURITY_ERR)” location: “file:///C:/Documents%20and%20Settings/Administrator/%E6%A1%8C%E9%9D%A2/html5_canvas.html Line: 30”]

在Chrome的JavaScript控制台你会看到:

Uncaught Error: SECURITY_ERR: DOM Exception 18

而在Safari中,该代码是可以正常运行的,原因在于:Firefox与Chrome对本地文件JavaScript访问权限控制比较严格。Demo中的注释去掉后,可以在Firefox中看到我们实际想得到的结果,但其实这是没必要的,因为在服务器环境下代码是可以正常运行的。

通过下面的例子,我们来看如何操作图像数据。

XHTML

<!DOCTYPE html><html><head><meta  charset= »utf-8″ /><title>Canvas javascript api demo</title><style type= »text/css »>canvas { border:1px #000 solid;}</style></head><body><h1>this is a canvas api test page!</h1><canvas id= »canvas » width= »300″ height= »300″>this browser does not support canvas…</canvas><a href= »http://blog.wanz.im/2010/04/28/canvas_javascript_api_learning_five/ »>返回文章</a><script type= »text/javascript »>var $=function(id){ return document.getElementById(id);}window.onload=function(){ var ctx=$(‘canvas’).getContext(‘2d’); var img=new Image(); img.src=’firefox.jpg’; img.onload=function(){ ctx.drawImage(img,0,0,240,240,30,10,120,120); imgData1=ctx.getImageData(30,10,120,120); imgData2=ctx.createImageData(50,50); for(var i=0;i<imgData2.data.length/4;i++){ //set the rgba to 255,0,0,255 imgData2.data[i*4]=0xfff; imgData2.data[i*4+1]=0; imgData2.data[i*4+2]=0; imgData2.data[i*4+3]=255; } ctx.putImageData(imgData1,30,160); ctx.putImageData(imgData2,50,200); }}</script></body></html>

我们通过给每个像素点的红,绿,蓝和alpha赋值为255,0,0,255,得到一块不透明的红色矩形,并把这块区域的数据放到指定的位置,效果如Demo所示,正如开始所说的那样,globalAlpha,globalCompositeOperation,还有shadow属性在调用putImageData时会被忽略,因此不管你给的alpha值是否是透明的,指定的区域的数据是被覆盖了,而不是层叠的,即使你设置了透明也无法看到覆盖前的图像。

写在后面
其实,这部分的函数使用起来并不会难,难的是对图像操作的效率问题的优化,这次的内容只是简单的介绍函数的用法,如果你有足够的图形学的理论知识,你可以用已学的这些知识对图像进行灰度变换、线性和非线性空间滤波、频率域滤波、图像恢复与配准、彩色图像处理、小波、图像数据压缩、形态学图像处理、图像分割、区域和边界表示与描述,以及目标识别等操纵。本人所学知识有限,在这里只起抛砖引玉的作用,希望本文对入门的朋友有帮助。

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *