简易版美图秀秀

<!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实现的)

感觉挺有意思的,上面解释很详细,直接看代码

posted @ 2016-10-30 19:05  wangziye  阅读(380)  评论(0编辑  收藏  举报