學習了canvas的基本繪圖功能後,驚喜的發現canvas對圖片數據也有至關強大的處理功能,可以從像素級別操做位圖,固然[lte ie8]不支持。javascript
主要的函數有三個:html
ctx.createImageData(width,height); // 用於建立ImageData對象java
ctx.getImageData(x,y,width,height); // 用於從canvas中獲取ImageData對象web
ctx.putImageData(imagedata, x, y, dx, dy, width, height); // 用於將ImagaData對象的數據填寫到canvas中,起到覆蓋canvas中原圖像的做用,能夠只輸入前三個參數。參數分別是:用於提供填充圖像數據的imagedata對象,imagedata對象左上角相對於canvas左上角的座標x,y,在canvas上用來填充imagedata區域的左上角相對imagedata對象左上角的座標x,y(相對於canvas左上角),填充區域的長度和寬度。具體用法效果往下看。chrome
我是想給圖片來個局部反相效果,就是那種有點嚇人的膠捲底片的效果。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/