携手创作,共同成长!这是我参与「掘金日新计划 · 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;
}
有了这个技能,我们试着给一个带背景图打个码:
.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;
}
我们的马赛克好讨厌哦,颜色这么深,啥都看不见了呢。实际上马赛克区域的色值应该跟图片是相近的,比如这样:
更真实的马赛克
如何实现这个效果呢,我们必须拿到图片中那个点的色值才行,还好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>
由于网络图存在跨域问题,我把图片下载到了本地。我们将落在我们框选位置的点收集起来。打印看看:
我们得到了这些点的位置信息和色值,那根据我们之前的方法,用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;
我们可以将if限制去掉,这样就是整个图片打码:
我们还可以调整打码的颗粒度粗细:
再清晰些:
也可以再模糊些:
完整代码
<!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画了个图,据说可以领钱!骗你是小狗: