canvas马赛克

马赛克思路

像素说明

一张图片的宽高积为像素个数:像素个数 = width * height

canvas中的ImageData中的 ImageData.data 数组,包含了图片的所有像素点。而一个像素点就是一个 rgba ,就是四个元素。所以Image.data中的元素,每四个元素为一组,为一个像素点

步骤

  1. 第一步要把图片插入到 canvas 中

    const image = new Image()
    image.src = '图片地址'
    image.onload = function(){
        //onload属性适用于拥有 src 属性的元素,用来表示元素加载成功,当图片加载成功后执行匿名函数
        ctx.drawImage(image,x,y,width,height)
    }
    
  2. 读取插入的图片,返回一个 ImageData 对象,该对象中,包含了图片的像素值与宽高

    const imageData  = ctx.getImageData(x,y,width,height)
    
  3. 将获取到的图片信息,以像素的形式,写入到 canvas 中

    ctx.putImageData(imageData,x,y)
    
  4. 回看像素说明,先对一个单位像素进行操作

    const x = 1,y = 1
    //获取一个单位像素信息
    const newImageData = ctx.getImageData(x,y,imageData)
    //写入一个单位像素信息
    ctx.putImageData(x,y,newImageData)
    
  5. 设置马赛克模糊度 size,该模糊度表示,在一个 5*5 的像素范围内,他们的像素值相同,以此达到马赛克效果

    const size = 5,width = 800,height=600
    // 操作像素,x:表示图片x坐标位置,y:表示图片y坐标位置
    function pxOperation(x, y, width, height, size, newImageData) {
        // 在 5*5 的范围内取一个单元像素点
        const { data } = ctx.getImageData(x, y, 1, 1)
        // 将该像素点全部写入 size 范围内
        for (let n = 0; n < size; n++) {
            for (let m = 0; m < size; m++) {
                newImageData.data[(x + n + (y + m) * width) * 4 + 1] = data[1]
                newImageData.data[(x + n + (y + m) * width) * 4 + 2] = data[2]
                newImageData.data[(x + n + (y + m) * width) * 4 + 0] = data[0]
                newImageData.data[(x + n + (y + m) * width) * 4 + 3] = data[3]
            }
        }
    }
    
    
  6. 将马赛克效果铺满整个图片

    for (let x = 0; x < w / size; x++) {
        for (let y = 0; y < h / size; y++) {
            pxOperation(x * size, y * size, w, h, size, newImageData)
        }
    }
    // 像素写入图片中
    ctx.putImageData(newImageData, 800, 0)
    

案例

第一步:通过单像素复制图片

效果图:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        html {
            width: 100%;
            height: 100%;
        }

        * {
            margin: 0;
            padding: 0;
        }

        .syt {
            background-color: rgba(158, 169, 203, 255);
        }
    </style>
</head>

<body>
    <canvas id="canvas" width="800" height="400">
        您的浏览器不支持canvas,请更换浏览器
    </canvas>
    <script>
        window.onload = () => {
            if (canvas.getContext) {
                canvas.style.backgroundColor = 'orange'
                const ctx = canvas.getContext('2d')
                const image = new Image(200, 300)
                image.width = 200
                image.src = '../images/2.jpg'
                image.onload = () => {
                    draw(image)
                }

                function draw(image) {
                    const size = 20
                    ctx.drawImage(image, 0, 0, 400, 400)
                    const imageData = ctx.getImageData(0, 0, 400, 400)
                    const width = imageData.width
                    const height = imageData.height / size
                    setRGBA(400, 0, imageData)
                }

                function getRGBA(x, y) {
                    const imageData = ctx.getImageData(x, y, 1, 1)
                    return imageData.data
                }

                function setRGBA(x, y, imageData) {
                    const size = 2
                    const w = imageData.width
                    const h = imageData.height
                    const newImageData = ctx.createImageData(imageData)
                    const arr = newImageData.data
                    for (let i = 0; i < w; i++) { //w:代表一行有多少个像素
                        for (let j = 0; j < h; j++) { //h:代表有多少行
                            // j * w :j行 乘 每行的像素
                            // + i :表示当前像素点之前还有多少个像素点,
                            // * 4 :是因为 ImageData.data中的数据,每四个元素 为一组,组成 rgba 
                            // (j * w + i) * 4 :代表定位到当前元素的 rgba[0]的位置
                            const color = getRGBA(i, j)
                            arr[(j * w + i) * 4] = color[0]
                            arr[(j * w + i) * 4 + 1] = color[1]
                            arr[(j * w + i) * 4 + 2] = color[2]
                            arr[(j * w + i) * 4 + 3] = color[3]
                        }
                    }
                    ctx.putImageData(newImageData, x, y)
                }
            }
        }
    </script>
</body>

</html>

第二步:间隔像素取值

效果图:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        html {
            width: 100%;
            height: 100%;
        }

        * {
            margin: 0;
            padding: 0;
        }

        .syt {
            background-color: rgba(158, 169, 203, 255);
        }
    </style>
</head>

<body>
    <canvas id="canvas" width="800" height="400">
        您的浏览器不支持canvas,请更换浏览器
    </canvas>
    <script>
        window.onload = () => {
            if (canvas.getContext) {
                canvas.style.backgroundColor = 'orange'
                const ctx = canvas.getContext('2d')
                const image = new Image(200, 300)
                image.width = 200
                image.src = '../images/2.jpg'
                image.onload = () => {
                    draw(image)
                }

                function draw(image) {
                    const size = 4
                    ctx.drawImage(image, 0, 0, 400, 400)
                    const imageData = ctx.getImageData(0, 0, 400, 400)
                    const newImageData = ctx.createImageData(imageData)
                    const width = imageData.width / size
                    const height = imageData.height / size
                    for (let i = 0; i < width; i++) {
                        for (let j = 0; j < height; j++) {
                            setRGBA(imageData, newImageData, i, j, size)
                        }
                    }

                }

                function getRGBA(x, y) {
                    return ctx.getImageData(x, y, 1, 1).data
                }

                function setRGBA(imageData, newImageData, x, y, size) {
                    const color = getRGBA(x * size, y * size)
                    const w = newImageData.width
                    const h = newImageData.height
                    const tempData = newImageData.data
                    tempData[(w * y + x) * size * 4] = color[0]
                    tempData[(w * y + x) * size * 4 + 1] = color[1]
                    tempData[(w * y + x) * size * 4 + 2] = color[2]
                    tempData[(w * y + x) * size * 4 + 3] = color[3]
                    ctx.putImageData(newImageData, 400, 0)
                }
            }
        }
    </script>
</body>

</html>

第三步:马赛克

效果图:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        html {
            width: 100%;
            height: 100%;
        }

        * {
            margin: 0;
            padding: 0;
        }

        .syt {
            background-color: rgba(158, 169, 203, 255);
        }
    </style>
</head>

<body>
    <canvas id="canvas" width="800" height="400">
        您的浏览器不支持canvas,请更换浏览器
    </canvas>
    <script>
        window.onload = () => {
            if (canvas.getContext) {
                canvas.style.backgroundColor = 'orange'
                const ctx = canvas.getContext('2d')
                const image = new Image(200, 300)
                image.width = 200
                image.src = '../images/2.jpg'
                image.onload = () => {
                    draw(image)
                }

                function draw(image) {
                    const size = 4
                    ctx.drawImage(image, 0, 0, 400, 400)
                    const imageData = ctx.getImageData(0, 0, 400, 400)
                    const newImageData = ctx.createImageData(imageData)
                    const width = imageData.width / size
                    const height = imageData.height / size
                    for (let i = 0; i < width; i++) {
                        for (let j = 0; j < height; j++) {
                            setRGBA(imageData, newImageData, i * size, j * size, size)
                        }
                    }

                }

                function getRGBA(x, y) {
                    return ctx.getImageData(x, y, 1, 1).data
                }

                function setRGBA(imageData, newImageData, x, y, size) {
                    const color = getRGBA(x, y)
                    const w = newImageData.width
                    const h = newImageData.height
                    const tempData = newImageData.data
                    for (let n = 0; n < size; n++) {
                        for (let m = 0; m < size; m++) {
                            tempData[(w * (y + m) + x + n) * 4 + 0] = color[0]
                            tempData[(w * (y + m) + x + n) * 4 + 1] = color[1]
                            tempData[(w * (y + m) + x + n) * 4 + 2] = color[2]
                            tempData[(w * (y + m) + x + n) * 4 + 3] = color[3]
                        }
                    }

                    ctx.putImageData(newImageData, 400, 0)
                }
            }
        }
    </script>
</body>

</html>

随机获取马赛克像素

效果图

图片加载失败

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        html {
            width: 100%;
            height: 100%;
        }

        * {
            margin: 0;
            padding: 0;
        }

        .syt {
            background-color: rgba(158, 169, 203, 255);
        }
    </style>
</head>

<body>
    <canvas id="canvas" width="800" height="400">
        您的浏览器不支持canvas,请更换浏览器
    </canvas>
    <script>
        window.onload = () => {
            if (canvas.getContext) {
                canvas.style.backgroundColor = 'orange'
                const ctx = canvas.getContext('2d')
                const image = new Image(200, 300)
                image.width = 200
                image.src = '../images/2.jpg'
                image.onload = () => {
                    draw(image)
                }

                function draw(image) {
                    const size = 4
                    ctx.drawImage(image, 0, 0, 400, 400)
                    const imageData = ctx.getImageData(0, 0, 400, 400)
                    const newImageData = ctx.createImageData(imageData)
                    const width = imageData.width / size
                    const height = imageData.height / size
                    for (let i = 0; i < width; i++) {
                        for (let j = 0; j < height; j++) {
                            setRGBA(imageData, newImageData, i * size, j * size, size)
                        }
                    }

                }

                function getRGBA(x, y) {
                    return ctx.getImageData(x, y, 1, 1).data
                }

                function setRGBA(imageData, newImageData, x, y, size) {
                    const randomX = random(size)
                    const randomY = random(size)
                    const color = getRGBA(x + randomX, y + randomY)
                    const w = newImageData.width
                    const h = newImageData.height
                    const tempData = newImageData.data
                    for (let n = 0; n < size; n++) {
                        for (let m = 0; m < size; m++) {
                            tempData[(w * (y + m) + x + n) * 4 + 0] = color[0]
                            tempData[(w * (y + m) + x + n) * 4 + 1] = color[1]
                            tempData[(w * (y + m) + x + n) * 4 + 2] = color[2]
                            tempData[(w * (y + m) + x + n) * 4 + 3] = color[3]
                        }
                    }

                    ctx.putImageData(newImageData, 400, 0)
                }

                function random(size) {
                    return Math.floor(Math.random() * size)
                }
            }
        }
    </script>
</body>

</html>
posted @ 2021-11-28 13:08  走我们钓鱼去  阅读(290)  评论(0)    收藏  举报