<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>简易板美图秀秀</title> </head> <body> <canvas id="canvas1" width="500" height="500" style="border: 1px red solid;"></canvas> <canvas id="canvas2" width="500" height="500" style="border: 1px solid blue;"></canvas> <button id="huidu">灰度</button> <button id="heibai">黑白</button> <button id="suibian">底片</button> <button id="mohu">模糊</button> <button id="mask">马赛克</button> </body> <script type="text/javascript"> var context1 = canvas1.getContext("2d"); var context2 = canvas2.getContext("2d"); var img = new Image(); img.src = "img/1.jpg"; img.onload = function() { context1.drawImage(img, 0, 0, canvas1.width, canvas1.height); } //给对应的按钮设置点击事件,并将对应的事件进行封装 huidu.onclick = function() { grayOperation(); } heibai.onclick = function() { heibaiOperation(); } suibian.onclick = function() { suibianOperation(); } mohu.onclick = function() { mohuOperation(); } mask.onclick = function() { maskOperation(); } //灰度处理函数 //让每一个像素块里面的r,g,b值等于r,g,b三个值得平均值 function grayOperation() { //获取画布里面的图片数据 var imgData = context1.getImageData(0, 0, 500, 500); //获取所有的像素块信息,以rgba依次排列. var px = imgData.data; for(var i = 0; i < canvas1.width * canvas1.height; i++) { //因为px里面存的每一个像素块都是以rgba依次排列,我们在找到对应的色素每次的i都应该乘4 var r = px[i * 4 + 0]; var g = px[i * 4 + 1]; var b = px[i * 4 + 2]; var avg = (r + g + b) / 3; px[i * 4 + 0] = avg; px[i * 4 + 1] = avg; px[i * 4 + 2] = avg; } // 像素值已经发生改变 // 把改变过的像素信息 绘制到 canvas2上面 context2.putImageData(imgData, 0, 0, 0, 0, 500, 500); } //黑白处理 //如果r,g,b三个值得和大于(255 * 3 / 2),我们就让这三个值都变成255反之都为零(不懂r,g,b可以百度) function heibaiOperation() { var imgData = context1.getImageData(0, 0, 500, 500); var px = imgData.data; for(var i = 0; i < canvas1.width * canvas1.height; i++) { var r = px[i * 4 + 0]; var g = px[i * 4 + 1]; var b = px[i * 4 + 2]; var sum = r + g + b; var a = 0; if(sum > 255 * 3 / 2) { a = 255; } else { a = 0; } px[i * 4 + 0] = a; px[i * 4 + 1] = a; px[i * 4 + 2] = a; } // 像素值已经发生改变 // 把改变过的像素信息 绘制到 canvas2上面 context2.putImageData(imgData, 0, 0, 0, 0, 500, 500); } //实现底片的效果 //底片效果就是让r,g,b的每个值都反过来,即让每一个的值变为(255-本身)的值 function suibianOperation() { var imgData = context1.getImageData(0, 0, 500, 500); var px = imgData.data; for(var i = 0; i < canvas1.width * canvas1.height; i++) { var r = px[i * 4 + 0]; var g = px[i * 4 + 1]; var b = px[i * 4 + 2]; px[i * 4 + 0] = 255 - r; px[i * 4 + 1] = 255 - g; px[i * 4 + 2] = 255 - b; } // 像素值已经发生改变 // 把改变过的像素信息 绘制到 canvas2上面 context2.putImageData(imgData, 0, 0, 0, 0, 500, 500); } //实现模糊的效果 //首先我们要实现模糊就得让你获取的每一个色素信息的值(r或g或b)等于周围一圈的色素信息(r或g或b)值得平均值,模糊的程度取决于你选取的圈的大小(一圈的颜色信息加上自己本身等于9个,同理两圈就是25个,n圈(2n+1)的平方) function mohuOperation() { //因为我们要修改每一个色素信息,避免让前一个修改的信息干扰到下一个修改,我们将画布里面的数据拷贝两份,一份用来修改,一份用来获取色素信息 var imgData1 = context1.getImageData(0, 0, 500, 500); var px1 = imgData1.data; var imgData2 = context1.getImageData(0, 0, 500, 500); var px2 = imgData2.data; //blur 就是我说的 圈的大小 这就表示两圈(即25个色素信息的平均值) var blur = 2; var blurNumber = (2 * blur + 1) * (2 * blur + 1); //如果和上面一样直接遍历所有的像素,我们在获取周围的色素信息的值会变得比较困难,在这里我们使用循环嵌套的方法,让i表示行,j表示列这样有利于我们获取周围的色素信息 //注意:这里我们的i,j都是从blur开始 for(var i = blur; i < canvas1.height - blur; i++) { for(var j = blur; j < canvas1.width - blur; j++) { var sumR = 0; var sumG = 0; var sumB = 0; //这里的ii,jj和外面的循环一样,让ii和jj分别表示行和列,去获取周围的元素,这样有利于维护,如果直接用下标来获取,会显得复杂 for(var ii = -blur; ii <= blur; ii++) { for(var jj = -blur; jj <= blur; jj++) { var x = i + ii; var y = j + jj; //根据二维数组坐标换算成一维数组的坐标 //因为px里面存的色素信息都是以r,g,b,a依次排列,这里我们用变量p*4来表示每个像素r通道的位置 var p = x * canvas1.width + y; //我们让sumR,sumG,sumB这三个的值去存储对应色素的信息 sumR += px1[p * 4 + 0]; sumG += px1[p * 4 + 1]; sumB += px1[p * 4 + 2]; } } //算出这一圈的数据的平均值 var avgR = sumR / blurNumber; var avgG = sumG / blurNumber; var avgB = sumB / blurNumber; //找到我们要修改的点,将我们准备的第二份数据进行修改 var pp = i * canvas1.width + j; px2[pp * 4 + 0] = avgR; px2[pp * 4 + 1] = avgG; px2[pp * 4 + 2] = avgB; } } // 像素值已经发生改变 // 把改变过的像素信息 绘制到 canvas2上面 context2.putImageData(imgData2, 0, 0, 0, 0, 500, 500); } //马赛克 //马赛克和模糊的原理基本一致,只是马赛克是将你获取的的一圈的所有色素信息都进行修改 function maskOperation() { var imgData1 = context1.getImageData(0, 0, 500, 500); var px1 = imgData1.data; var imgData2 = context1.getImageData(0, 0, 500, 500); var px2 = imgData2.data; var blur = 2; var blurNumber = (2 * blur + 1) * (2 * blur + 1); //注意:和模糊不同的是,我们不能获取每一个色素信息周围的周围信息,如果这样做的话后面一个点修改的信息会将前一个修改覆盖,所以 (i += 2 * blur)让他每次修改的时候跳过这一圈,避免后面的将前面的修改(或得到和模糊一模一样的效果) for(var i = 1; i < canvas1.height - blur; i += 2 * blur) { for(var j = 1; j < canvas1.width - blur; j += 2 * blur) { var sumR = 0; var sumG = 0; var sumB = 0; for(var ii = -blur; ii <= blur; ii++) { for(var jj = -blur; jj <= blur; jj++) { var x = i + ii; var y = j + jj; //根据二维数组坐标换算成一维数组的坐标 var p = x * canvas1.width + y; sumR += px1[p * 4 + 0]; sumG += px1[p * 4 + 1]; sumB += px1[p * 4 + 2]; } } var avgR = sumR / blurNumber; var avgG = sumG / blurNumber; var avgB = sumB / blurNumber; for(var iii = -blur; iii <= blur; iii++) { for(var jjj = -blur; jjj <= blur; jjj++) { var a = i + iii; var b = j + jjj; var pp = a * canvas1.width + b; px2[pp * 4 + 0] = avgR; px2[pp * 4 + 1] = avgG; px2[pp * 4 + 2] = avgB; } } } } // 像素值已经发生改变 // 把改变过的像素信息 绘制到 canvas2上面 context2.putImageData(imgData2, 0, 0, 0, 0, 500, 500); } </script> </html>
简单的实现了 灰度,黑白,底片,模糊,马赛克(代码比较简单,通过canvas实现的)
感觉挺有意思的,上面解释很详细,直接看代码