学习了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/

posted on 2015-11-04 17:40  SUperman-苏智敏  阅读(26420)  评论(1编辑  收藏  举报