用这项技术打码好像有点多此一举,但是好玩

251 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第13天,点击查看活动详情

不知道有没有同学了解过前端如何实现给图片打码,很多同学的第一反应基本上就是canvas,今天我们的主角不是它,canvas只是个跑龙套的,今天带大家来用box-shadow实现图片马赛克。文末还有惊喜等你开启,建议从头开始阅读,体验更佳,直接跳转文末惊喜减半~

画个简单的马赛克

 .demo {
    width: 100px;
    height: 100px;
    background-color: red;
    box-shadow: 0 100px orange, 
        0 200px yellow, 
        100px 0 green, 
        100px 100px cyan, 
        100px 200px blue, 
        200px 0 purple, 
        200px 100px black, 
        200px 200px grey;
}

image.png

有了这个技能,我们试着给一个带背景图打个码:

.demo {
    width: 300px;
    height: 300px;
    background: url(https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2Ftp03%2F1Z920151422M61-0-lp.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1662590780&t=e7da9ca7347d78496630aeb2924cbb5a) no-repeat center;
    background-size: 300px;
}

.mask {
    position: absolute;
    width: 10px;
    height: 10px;
    box-shadow: 110px 270px orange,
        110px 280px yellow,
        120px 270px green,
        120px 280px cyan,
        130px 270px blue,
        130px 280px purple,
        140px 270px black,
        140px 280px grey;
}

image.png

我们的马赛克好讨厌哦,颜色这么深,啥都看不见了呢。实际上马赛克区域的色值应该跟图片是相近的,比如这样:

image.png

更真实的马赛克

如何实现这个效果呢,我们必须拿到图片中那个点的色值才行,还好canvas有方法可以做到这一点

<script>
    let canvas = document.getElementById("cvs");
    canvas.width = 300;
    canvas.height = 300;
    let ctx = canvas.getContext("2d");
    let img = new Image();
    img.src = "./teacher.png";
    let mask = [];
    img.onload = () => {
        ctx.drawImage(img, 0, 0, 300, 300);
        for (let i = 0; i < 300; i += 10) {
            for (let j = 0; j < 300; j += 10) {
                const [r, g, b, a] = ctx.getImageData(i, j, 1, 1).data;
                if (i >= 270 && j >= 110 && j <= 150) {
                    mask.push({
                        x: i,
                        y: j,
                        color: `rgba(${r}, ${g}, ${b}, ${a / 255})`
                    })
                }
            }
        }
        console.log(mask);
    }
</script>

由于网络图存在跨域问题,我把图片下载到了本地。我们将落在我们框选位置的点收集起来。打印看看:

image.png 我们得到了这些点的位置信息和色值,那根据我们之前的方法,用box-shadow就可以将马赛克打上去了:

const maskEl = document.querySelector('.mask');
let shadowStr = '';
mask.forEach(item => {
    shadowStr += `${item.x}px ${item.y}px ${item.color},`
})
shadowStr = shadowStr.slice(0, -1);
maskEl.style.boxShadow = shadowStr;

image.png

我们可以将if限制去掉,这样就是整个图片打码:

image.png

我们还可以调整打码的颗粒度粗细:

再清晰些:

image.png

也可以再模糊些:

image.png

完整代码

<!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>
        .demo {
            position: relative;
            width: 300px;
            height: 300px;
            background: url(https://gimg2.baidu.com/image_search/src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fq_70%2Cc_zoom%2Cw_640%2Fimages%2F20171213%2F26994b5b011f4f03a7c24e6f332a20ce.jpeg&refer=http%3A%2F%2F5b0988e595225.cdn.sohucs.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1662556736&t=ad12ca5f4e2222aedb9da32c2ba4dd9f) no-repeat center;
            background-size: 300px;
        }

        .mask {
            position: absolute;
            top: 0;
            left: 0;
        }
    </style>
</head>

<body>
    <div class="demo">
        <div class="mask"></div>
    </div>
    <canvas id="cvs"></canvas>
</body>
<script>
    let canvas = document.getElementById("cvs");
    canvas.width = 300;
    canvas.height = 300;
    canvas.style.display = 'none';
    let ctx = canvas.getContext("2d");
    let img = new Image();
    img.src = "./dog.webp";
    let mask = [];
    let size = 15;
    img.onload = () => {
        ctx.drawImage(img, 0, 0, 300, 300);
        for (let i = 0; i < 300; i += size) {
            for (let j = 0; j < 300; j += size) {
                const [r, g, b, a] = ctx.getImageData(i, j, 1, 1).data;
                // if (j >= 270 && i >= 110 && i <= 150) {
                    mask.push({
                        x: i,
                        y: j,
                        color: `rgba(${r},${g},${b},${a / 255})`
                    })
                // }
            }
        }
        console.log(mask);
        const maskEl = document.querySelector('.mask');
        maskEl.style.width = size + 'px';
        maskEl.style.height = size + 'px';
        let shadowStr = '';
        mask.forEach(item => {
            shadowStr += `${item.x}px ${item.y}px ${item.color},`
        })
        shadowStr = shadowStr.slice(0, -1);
        maskEl.style.boxShadow = shadowStr;
    }
</script>

</html>

结语

是不是还没玩够呢,是不是很好玩呢,别急,这边我还用box-shadow画了个图,据说可以领钱!骗你是小狗:

code.juejin.cn/pen/7127681…