前面給大家帶來了操作像素的API,此時此刻,我覺得應該配以小執行個體來進行進一步的說明和示範,以便給大家帶來更寬廣的視野和靈感,你們看了我的那麼多的文章,應該是懂我的風格,廢話不多說,進入正題:
這次給大家帶來的是圖檔的馬賽克效果,這種效果你們應該很熟悉了,比如看到一些較污的新聞,關鍵的地方總是有這萬惡的馬賽克擋着,咱們今天就來剖析一下這馬賽克到底是撒東西,是一個什麼原理:

大家看看這張圖,這就是馬賽克的效果,整個圖就是一顆顆很大的像素點構成的,當然這裡說的像素點指的不是一像素,而是一個像素點可能是由幾個像素或者是十幾個像素構成的,像素點越大,圖像就約模糊,像素點越小,圖檔越清晰,什麼,你對上圖無感?好吧,我們看一下現實生活中你見過的馬賽克:
看,左邊的大美女,打上馬賽克,立馬變神秘了,那馬賽克糾結是一個什麼原理呢?
對比上圖的左右兩個臉,右邊的臉雖然看不清,但還是能看清輪廓的,而且右邊的馬賽克部分像素點非常大,而左邊的呢,幾乎看不到像素點,那麼左邊的是不是就不是由像素點構成的呢?我們把圖放大n倍來看看:
上圖是截圖的馬賽克圖檔的一部分,放大後可以清除的看到,圖像是由一個個像素點構成的,可以發現,馬賽克的像素顆粒也是由許多的像素點構成的,隻是這些顆粒的顔色是一個的,縮小就感覺是一個大的像素顆粒,而偏不的則是一個個小的像素點,各自顔色不一樣,才形象非常細膩的圖像,由此可見,要想做馬賽克效果,隻需要将一個區域内的像素的的顔色用裡面一個随機的顔色替代,就會使得圖像模糊,這樣縮小了看就是馬賽克效果了,而且這個區域也大,圖像越模糊,越小,則圖像越清晰!
知道了馬賽克的原理,那麼我們就可以通過操作像素來制作馬賽克效果了,怎麼做呢?比如将一整張圖做成馬賽克效果,那麼,如果我們将這張圖等分成n份,且每一份随機在這個區域裡找一個像素點的顔色,然後将這個區域的顔色都設為這個顔色,全部操作完,馬賽克就做完了,哈哈,挺抽象的,那老規矩,跟着我一步一步的做吧:
首先我們在畫布上引進來一張圖,然後我們建一個函數,用于繪制馬賽克(其目的我再說一般,一是圖檔必須加裝完成,才能進行像素操作,二是結構更清晰,便于了解)
var aImg = new Image();
aImg.src = \'1.jpg\';
aImg.onload = function(){
draw(this);
}
//此函數用于後面的像素操作
function draw(obj){
ctx.drawImage(obj,0,0,400,400);
}
我們将畫布的大小設為圖檔的2倍,右邊用于顯示馬賽克的圖
下面就該擷取像素了,不清楚的同學可以先去看看前文的API的第5篇,工欲善其事必先利其器
function draw(obj){
ctx.drawImage(obj,0,0,400,400);
var oImg = ctx.getImageData(0,0,400,400);
var w = oImg.width;
var h = oImg.height;
ctx.putImageData(oImg,w,0);
}
在右側把圖檔用像素操作複制一個放到右邊
一模一樣雙胞胎,哈哈,接下來就是醉關鍵的地方了,就是如何将一個區域的像素點用一個顔色替代,我們畫一個圖來示意一下:
看看上圖,圖畫的很粗糙哈(俗話說圖糙理不糙),比如說圖檔是100*100像素的圖,那麼原來是由1*1像素的點構成的,現在我們等分成10份,一份的像素點就是10*10,那麼這份的像素點在裡面随機設定一個顔色,然後同理操作所有的,就成了一個隻顯示10分之一圖像的馬賽克了
這裡引用我們原來寫的擷取某一點的顔色的函數和設定某一點的顔色的函數,可以作為通用方法:
function getXY(obj,x,y){
var w = obj.width;
var h = obj.height;
var d = obj.data;
var color = [];
color[0] = obj.data[4*(y*w+x)];
color[1] = obj.data[4*(y*w+x)+1];
color[2] = obj.data[4*(y*w+x)+2];
color[3] = obj.data[4*(y*w+x)+3];
return color;
}
function setXY(obj,x,y,color){
var w = obj.width;
var h = obj.height;
var d = obj.data;
obj.data[4*(y*w+x)] = color[0];
obj.data[4*(y*w+x)+1] = color[1];
obj.data[4*(y*w+x)+2] = color[2];
obj.data[4*(y*w+x)+3] = color[3];
}
接下來就是操作像素了,我們在一個新的ImageData上操作
//建立一個新的ImageData對象
var newImg = ctx.createImageData(obj.width,obj.height);
//馬賽克的程度,數字越大越模糊
var num = 5;
//等分畫布
var stepW = w/num;
var stepH = h/num;
//這裡是循環畫布的像素點
for(var i=0;i<stepH;i++){
for(var j=0;j<stepW;j++){
//擷取一個小方格的随機顔色,這是小方格的随機位置擷取的
var color = getXY(oImg,j*num+Math.floor(Math.random()*num),i*num+Math.floor(Math.random()*num));
//這裡是循環小方格的像素點,
for(var k=0;k<num;k++){
for(var l=0;l<num;l++){
//設定小方格的顔色
setXY(newImg,j*num+l,i*num+k,color);
}
}
}
}
整理所有的代碼就是:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var aImg = new Image();
aImg.src = \'1.jpg\';
aImg.onload = function(){
draw(this);
}
function draw(obj){
ctx.drawImage(obj,0,0,400,400);
var oImg = ctx.getImageData(0,0,400,400);
var w = oImg.width;
var h = oImg.height;
//建立一個新的ImageData對象
var newImg = ctx.createImageData(obj.width,obj.height);
//馬賽克的程度,數字越大越模糊
var num = 5;
//等分畫布
var stepW = w/num;
var stepH = h/num;
//這裡是循環畫布的像素點
for(var i=0;i<stepH;i++){
for(var j=0;j<stepW;j++){
//擷取一個小方格的随機顔色,這是小方格的随機位置擷取的
var color = getXY(oImg,j*num+Math.floor(Math.random()*num),i*num+Math.floor(Math.random()*num));
//這裡是循環小方格的像素點,
for(var k=0;k<num;k++){
for(var l=0;l<num;l++){
//設定小方格的顔色
setXY(newImg,j*num+l,i*num+k,color);
}
}
}
}
ctx.putImageData(newImg,w,0);
}
function getXY(obj,x,y){
var w = obj.width;
var h = obj.height;
var d = obj.data;
var color = [];
color[0] = obj.data[4*(y*w+x)];
color[1] = obj.data[4*(y*w+x)+1];
color[2] = obj.data[4*(y*w+x)+2];
color[3] = obj.data[4*(y*w+x)+3];
return color;
}
function setXY(obj,x,y,color){
var w = obj.width;
var h = obj.height;
var d = obj.data;
obj.data[4*(y*w+x)] = color[0];
obj.data[4*(y*w+x)+1] = color[1];
obj.data[4*(y*w+x)+2] = color[2];
obj.data[4*(y*w+x)+3] = color[3];
}
得到的效果:
為了顯得好看一點,我們隻是取了一個比較小的值,現在五分之一的像素點,如果是十分之一,得到是就是這樣的,值在num的地方修改:
具體效果看這裡——canvas馬賽克效果
這是整張圖做成馬賽克,能不能跟上面的美女一樣,做成局部的馬賽克呢?其實也很簡單,我們起初擷取的是整張圖的像素,現在我們隻擷取局部我們想要的部分的像素就可以了:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var aImg = new Image();
aImg.src = \'1.jpg\';
aImg.onload = function(){
draw(this);
}
function draw(obj){
//繪制第一張圖
ctx.drawImage(obj,0,0,400,400);
//繪制第二張圖,用作對比
ctx.drawImage(obj,400,0,400,400);
//擷取坐邊圖像的局部坐标的部分像素(左圖位置在258,為友善示範,這裡設成和馬賽克顯示位置一樣的坐标)
var oImg = ctx.getImageData(650,60,50,50);
var w = oImg.width;
var h = oImg.height;
//馬賽克的程度,數字越大越模糊
var num = 10;
//等分畫布
var stepW = w/num;
var stepH = h/num;
//這裡是循環畫布的像素點
for(var i=0;i<stepH;i++){
for(var j=0;j<stepW;j++){
//擷取一個小方格的随機顔色,這是小方格的随機位置擷取的
var color = getXY(oImg,j*num+Math.floor(Math.random()*num),i*num+Math.floor(Math.random()*num));
//這裡是循環小方格的像素點,
for(var k=0;k<num;k++){
for(var l=0;l<num;l++){
//設定小方格的顔色
setXY(oImg,j*num+l,i*num+k,color);
}
}
}
}
ctx.putImageData(oImg,650,60);
}
function getXY(obj,x,y){
var w = obj.width;
var h = obj.height;
var d = obj.data;
var color = [];
color[0] = obj.data[4*(y*w+x)];
color[1] = obj.data[4*(y*w+x)+1];
color[2] = obj.data[4*(y*w+x)+2];
color[3] = obj.data[4*(y*w+x)+3];
return color;
}
function setXY(obj,x,y,color){
var w = obj.width;
var h = obj.height;
var d = obj.data;
obj.data[4*(y*w+x)] = color[0];
obj.data[4*(y*w+x)+1] = color[1];
obj.data[4*(y*w+x)+2] = color[2];
obj.data[4*(y*w+x)+3] = color[3];
}
是不是跟剛開始的那個美女很像了,可能有的同學注意到,我有時候建立了一個新的ImageData對象,有的時候沒有,那到底什麼時候需要建立新的ImageData對象,什麼時候不需要呢?原則上說,如果你操作的像素不在原圖上,則需要新建立一個ImageData對象,但是也不是絕對的,你在原圖上操作像素,也是可以建立一個新的ImageData對象的,具體還是看需要!
上面的局部馬賽克效果看這裡—— canvas圖檔局部馬賽克效果
今天就講到這裡,後面要是有時間,在給幾個例子給大家學習一下!