<!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实现的)
感觉挺有意思的,上面解释很详细,直接看代码