學習了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/