摘要:[HTML5]使用Canvas處理濾鏡效果
Canvas是HTML中的一個元素<canvas>,跟<img>有點像,但<img>只是用來顯示圖片,<canvas>卻可以用來對圖片進行加工處理。既然可以對圖片進行加工,所以用Canvas做濾鏡效果,也是很合理的一件事。這次要做的事情,是透過file input來選取電腦上的圖片檔,在透過canvas加上不同濾鏡,顯示在網頁上。其效果如下所示:
Canvas概念
在實作之前,要瞭解一些基本的Canvas概念。<casvas>是畫布的概念,可以在上面繪製圓形、長方形,也可以把圖片檔畫上去。這些繪製的動作,其實是交由一個由canvas產生的Context物件進行處理。因為我們繪製的是平面的圖片,所以是透過以下的參數以取得Context物件。
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
取得Context物件後,就可以開始在畫布上畫些東西。如果要把圖片檔畫在畫布上,就需要使用Context物件的drawImage() 函數。drawImage()可以接受以下幾種資料型態作為繪圖的來源:
- <img> element:除了<img>元素外,也包含用Image() 建立的Image物件
- <video> element:可抓取影片的畫格畫在canvas上
- <canvas> element:可把另一個canvas元素內容畫在目前的canvas上
讀取本機圖片檔
除了由<img>取得Image物件外,另一個更自由的方式是透過file input來選取自己電腦上的圖片檔。只要透過HTML5的FileReader API的readAsDataURL(),就可以輕鬆地將本機的圖片檔讀進瀏覽器中。之後,就可以把該圖片檔當作drawImage()的資料來源,畫在<canvas>畫布上。
var reader = new FileReader();
var file = document.getElementById("fileUploadBtn").files[0];
reader.readAsDataURL(file);
reader.onload = function(e){
//讀取檔案完成後,繼續進行圖片的處理工作
}
建立縮圖用的Canvas
取得檔案後,考量到圖片的尺寸可能很大,所以可以使用Canvas把影像畫得小一點。Canvas可以指定把影像畫成不同尺寸,利用這個特性,就可以做到縮圖的效果。
var tempCanvas = document.createElement('canvas');
var thumbnailsSize = getSizeByMaxLength(img.width,img.height,200);
tempCanvas.width = thumbnailsSize.width;
tempCanvas.height = thumbnailsSize.height;
tempCanvas.getContext('2d').drawImage(img, 0, 0, thumbnailsSize.width, thumbnailsSize.height);
濾鏡效果
想要做到濾鏡效果,就需要透過Context物件的getImageData()函式以取得ImageData物件。ImageData物件定義了canvas 上的pixel資訊,它是一個陣列,內容記錄了每個pixel的RGBA值。透過數學函式運算這些RBGA值,就可以做到濾鏡的效果。這個網頁-Image Filters with Canvas介紹了一些簡單的濾鏡效果的處理方式。我將其中幾個列出如下:
var Filters = {
getPixels: function(img) {
var c = this.getCanvas(img.width, img.height);
var ctx = c.getContext('2d');
ctx.drawImage(img,0,0);
return ctx.getImageData(0,0,c.width,c.height);
},
getCanvas: function(w,h) {
var c = document.createElement('canvas');
c.width = w;
c.height = h;
return c;
},
filterImage: function(filter, image, var_args) {
var args = [this.getPixels(image)];
for (var i=2; i<arguments.length; i++) {
args.push(arguments[i]);
}
return filter.apply(null, args);
},
grayscale: function(pixels, args) {
var d = pixels.data;
for (var i=0; i<d.length; i+=4) {
var r = d[i];
var g = d[i+1];
var b = d[i+2];
var v = 0.2126*r + 0.7152*g + 0.0722*b;
d[i] = d[i+1] = d[i+2] = v;
}
return pixels;
},
brightness: function(pixels, adjustment) {
var d = pixels.data;
for (var i=0; i<d.length; i+=4) {
d[i] += adjustment;
d[i+1] += adjustment;
d[i+2] += adjustment;
}
return pixels;
},
threshold: function(pixels, threshold) {
var d = pixels.data;
for (var i=0; i<d.length; i+=4) {
var r = d[i];
var g = d[i+1];
var b = d[i+2];
var v = (0.2126*r + 0.7152*g + 0.0722*b >= threshold) ? 255 : 0;
d[i] = d[i+1] = d[i+2] = v;
}
return pixels;
}
}
最後,將以上的資訊全部集合在一起,就可以做到我們所要的功能。這個Demo放在以下的JS Bin中
參考資訊: