学习了canvas的基本绘图功能后,惊喜的发现canvas对图片数据也有相当强大的处理功能,能够从像素级别操作位图,当然[lte ie8]不支持。
主要的函数有三个:
ctx.createImageData(width,height); // 用于创建ImageData对象
ctx.getImageData(x,y,width,height); // 用于从canvas中获取ImageData对象
ctx.putImageData(imagedata, x, y, dx, dy, width, height); // 用于将ImagaData对象的数据填写到canvas中,起到覆盖canvas中原图像的作用,可以只输入前三个参数。参数分别是:用于提供填充图像数据的imagedata对象,imagedata对象左上角相对于canvas左上角的坐标x,y,在canvas上用来填充imagedata区域的左上角相对imagedata对象左上角的坐标x,y(相对于canvas左上角),填充区域的长度和宽度。具体用法效果往下看。
我是想给图片来个局部反相效果,就是那种有点吓人的胶卷底片的效果。
实现思路是将图片画到canvas上,获取canvas的ImageData对象,对每个像素的颜色值进行反相处理。
代码如下:
<script type="text/javascript">
/*
* @param {object} img 展示反相的图片
*/ function showRevertPic(img){ img.color = img.src; // 给img添加属性指向源文件 img.revert = createRevertPic(img); // 给img添加属性指向反相图片 img.onmouseout = function(){ this.src = img.revert; } img.onmouseover = function(){ this.src = img.color; } img.onmouseout(); // 默认展示一次图片反相 }
/*
* @param {object} img 要实现反相的图片
*/ function createRevertPic(img){ var canvas = document.createElement("canvas"); canvas.width = img.width; canvas.height = img.height; var ctx = canvas.getContext("2d"); ctx.drawImage(img,0,0); var c = ctx.getImageData(0, 0, img.width, img.height); //chrome浏览器报错,ie浏览器报安全错误信息,原因往下看 for(var i = 0; i < c.height; ++i){ for(var j = 0; j < c.width; ++j){ var x = i*4*c.width + 4*j, //imagedata读取的像素数据存储在data属性里,是从上到下,从左到右的,每个像素需要占用4位数据,分别是r,g,b,alpha透明通道 r = c.data[x], g = c.data[x+1], b = c.data[x+2]; c.data[x+3] = 150; //透明度设置为150,0表示完全透明
//图片反相: c.data[x] = 255-r; c.data[x+1] = 255-g; c.data[x+2] = 255-b; } } //ctx.putImageData(c, 40, 40); ctx.putImageData(c,0,0,40,40,200,300); //裁剪效果见图1 return canvas.toDataURL(); //返回canvas图片数据url } window.onload=function() { var img = new Image(); img.src = "boy.png"; img.isLoad = false; document.body.appendChild(img); img.onload=function(){ if(!img.isLoad){ showRevertPic(img); img.isLoad=true; } } } </script>
间以上js文件复制到html文件中,然后在firefox浏览器打开就能看到一个漂亮的男孩(是的,不是女孩orz),底片一样的区域就是putImageData放置的区域,鼠标移上去就能看到原来的图片:
为什么img的onload函数要设置一个isLoad属性呢,原因你去掉isLoad的判断就知道了,你会发现,我擦咧,图片忽闪忽闪的,这个onload函数居然一直不断的执行下去。
为什么呢,因为showRevertPic(img)默认运行一次mouseout函数,而鼠标移入移出会导致图片的src的改变,每次src改变就会触发onload事件,而onload会导致图片再次反相,于是图片就一直忽闪忽闪的。而查看控制台,img的src一直指向64位编码的png图片数据而没有一次指向原图片地址,原因是当出发了一次mouseout函数img的src就不再指向源文件了,之后的变化是源图片的反相和源图片的反相的反相交替进行。所以给img设置了个isLoad属性是为了只触发一次showRevertPic()函数。
当然去掉showRevertPic()函数中的默认执行一次的mouseout函数也行,但是就不能立马看到图片的反相了。
这里其实存在跨域的问题,当用chrome浏览器或ie浏览器打开(9+)就会报错,
chrome:Uncaught SecurityError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.
ie:SCRIPT5022: DOM Exception: SECURITY_ERR (18)
指向错误愿意来自于getImageData只能操作与脚本位于同一个域中的图片,获取的图片是本地文件夹的,没有域名,所以浏览器认为跨域操作了。所以要感慨下,chrome和ie更注重安全性的问题啊。
解决方法是搭建服务器环境,将文件放到服务器目录下,通过服务器访问,这样就不会报错了。
现在说下createRevertPic()中的返回值canvas.toDataURL()。
这个方法返回的是canvas编码为图片数据的url,用来生成图片的,默认png格式,也可以通过传递参数改变图片格式,还能改变图片保存的质量。如:canvas.toDataURL("images/jpeg",0) ,第一个参数就是把图片编码为jpeg格式,第二个参数(0-1)就是指定图片质量,数值越大质量越高,不过对于image/png格式没得设置图片质量orz。另外,chrome还支持自家的image/webp格式图片,也能设置图片质量。
canvas.toDataURL("images/jpeg",0) 图片如下,这码打的可以吧:
拖延症的自救旅程之----新的篇章,但愿如此orz。
-------------------------------转载注明出处: http://www.cnblogs.com/suspiderweb/