
masic.gif
展示demo用一張我家孝敏美美的畫報(bào)>w<~
介紹下這款基于js和canvas實(shí)現(xiàn)的前端馬賽克畫筆,每次執(zhí)行步驟都可以撤銷,可反復(fù)繪制
實(shí)現(xiàn)原理分以下幾個(gè)步驟:
- 將圖片導(dǎo)入到canvas中:
var imgObj = new Image();
imgObj.crossOrigin = "Anonymous"; //用于解決圖片跨域問題,但在chrome下依舊無效,建議起個(gè)node服務(wù)或者用safari打開
imgObj.src = 'timg.jpeg';
//待圖片加載完后,將其顯示在canvas上
imgObj.onload = function(){
context.drawImage(this, 0, 0,canvas.width,canvas.height);//this即是imgObj,保持圖片的原始大小
/**
步驟二
*/
}
這里注意下關(guān)于圖片跨域的報(bào)錯(cuò),可以在網(wǎng)上找些解決方案:http://www.cnblogs.com/haimingpro/p/6098204.html
- 開始處理畫筆事件:觸發(fā)-移動-提筆
var quan = 3; //馬賽克的大小
var num = 9; //一次操作包含馬賽克的個(gè)數(shù)
canvas.onmousedown = function(ev){
var ev=ev || window.event;
var dx = ev.clientX-canvas.offsetLeft;
var dy = ev.clientY-canvas.offsetTop;
drawLine(obj,dx,dy); //開始畫馬塞克
document.onmousemove = function(ev){
var ev = ev || window.event;
var mx = ev.clientX-canvas.offsetLeft;
var my = ev.clientY-canvas.offsetTop;
//當(dāng)拖拽的距離超過馬賽克的直徑再畫下一個(gè)馬賽克
if(Math.pow(dx-mx,2)+Math.pow(dy-my,2)>= Math.pow(quan*num,2)){ //
drawLine(obj,mx,my);
dx = mx;
dy = my;
}
};
document.onmouseup = function(){
document.onmousemove = null;
document.onmouseup = null;
};
}
馬賽克大小和數(shù)量可自定義,馬賽克大小越大,那么圖像模糊化會越重,數(shù)值越小,則越接近原圖;兩者的數(shù)值直接影響畫筆的大小。
- 生成馬賽克
//原始圖像
var originalImgData = context.getImageData(0,0,canvas.width,canvas.height);
var originalPxData = originalImgData.data;
//用于循環(huán)修改
var modifyImgData = context.getImageData(0,0,canvas.width,canvas.height);
var modifyPxData = modifyImgData.data;
for(var i=dx-quan*num;i<dx+quan*num;i = i+2*quan+1){
for(var j=dy-quan*num;j<dy+quan*num;j = j+2*quan+1){
//中心點(diǎn)(dx,dy)
//注意!這里的if判斷是為了把畫筆處理成圓的,有兩種方案,下面細(xì)述,如果把if判斷去掉,畫筆默認(rèn)是正方形的
// if(Math.pow(i-dx,2)+Math.pow(j-dy,2) <= Math.pow(quan*num/2,2)){
if(!((i==dx-quan*num&&j==dy-quan*num)||(i==dx-quan*num&&j==dy-quan*num+2*quan+1)||
(i==dx-quan*num&&j==dy-quan*num+4*quan+2)||(i==dx-quan*num&&j==dy-quan*num+12*quan+6)||
(i==dx-quan*num&&j==dy-quan*num+14*quan+7)||(i==dx-quan*num&&j==dy-quan*num+16*quan+8)||
(i==dx-quan*num+16*quan+8&&j==dy-quan*num)||(i==dx-quan*num+16*quan+8&&j==dy-quan*num+2*quan+1)||
(i==dx-quan*num+16*quan+8&&j==dy-quan*num+4*quan+2)||(i==dx-quan*num+16*quan+8&&j==dy-quan*num+12*quan+6)||
(i==dx-quan*num+16*quan+8&&j==dy-quan*num+14*quan+7)||(i==dx-quan*num+16*quan+8&&j==dy-quan*num+16*quan+8)||
(i==dx-quan*num+2*quan+1&&j==dy-quan*num)||(i==dx-quan*num+4*quan+2&&j==dy-quan*num)||
(i==dx-quan*num+12*quan+6&&j==dy-quan*num)||(i==dx-quan*num+14*quan+7&&j==dy-quan*num)||
(i==dx-quan*num+2*quan+1&&j==dy-quan*num+16*quan+8)||(i==dx-quan*num+4*quan+2&&j==dy-quan*num+16*quan+8)||
(i==dx-quan*num+12*quan+6&&j==dy-quan*num+16*quan+8)||(i==dx-quan*num+14*quan+7&&j==dy-quan*num+16*quan+8))){
var sumR = 0;
var sumG = 0;
var sumB = 0;
//找他周圍的元素
for(var x = -quan;x<=quan;x++){
for(var y = -quan;y<=quan;y++){
var xx = i+x;
var yy = j+y;
var pp = yy*canvas.width+xx; //周圍的元素。
sumR += originalPxData[pp*4+0];
sumG += originalPxData[pp*4+1];
sumB += originalPxData[pp*4+2];
}
}
var totlal = (2*quan+1)*(2*quan+1);
var avgR = sumR/totlal;
var avgG = sumG/totlal;
var avgB = sumB/totlal;
for(var x = -quan;x<=quan;x++){
for(var y = -quan;y<=quan;y++){
var xx = i+x;
var yy = j+y;
var pp = yy*canvas.width+xx; //周圍的元素。
modifyPxData[pp*4+0] = avgR;
modifyPxData[pp*4+1] = avgG;
modifyPxData[pp*4+2] = avgB;
}
}
}
}
}
context.putImageData(modifyImgData,0,0,0,0,canvas.width,canvas.height);
原理是通過循環(huán)找到馬賽克區(qū)域的每個(gè)像素點(diǎn)中心的顏色,將其覆蓋到整塊像素區(qū)域,簡單畫個(gè)草圖示意下,馬賽克畫筆區(qū)域默認(rèn)是正方形:

草圖1.jpeg
接下來我們將畫筆處理為圓形:
有兩種方案:1. 將距離超過馬賽克畫筆區(qū)域半徑的像素點(diǎn)過濾掉,如圖:

草圖2.jpeg
-
直接過濾掉不需要的點(diǎn),使馬賽克畫筆接近成圓形
草圖3.jpeg
一共要過濾20個(gè)點(diǎn),比較繁瑣,但測試了下效果,感覺還是方案二比較好
到這里,我們實(shí)現(xiàn)馬賽克畫筆功能的流程就走完了 最后說下撤銷功能
我們只需要在每次繪畫之前,先把圖像做個(gè)保存,存入到緩存數(shù)組中,撤銷的時(shí)候,根據(jù)堆棧原理,一步步還原:
//修改緩存
var lastImgArr = [];
canvas.onmousedown = function(ev){
//每次下筆前先保存
lastImgArr.push(context.getImageData(0,0,canvas.width,canvas.height));
}
//撤銷修改
document.getElementById('revoked').onclick = function(){
if(lastImgArr && lastImgArr.length){
context.putImageData(lastImgArr.pop(), 0, 0);
}
}
查看完整源碼:[github-link]:https://github.com/yomonah/mosaic-js
感謝閱讀。
