Canvas实现马赛克效果的核心是区块采样+填充:等图片加载完成后再绘制,设canvas尺寸匹配图片,按blockSize划分网格,取每格左上像素色值并fillRect填充;需规避跨域报错、DPR导致的模糊及性能问题。

网页端用 Canvas 实现马赛克效果,核心是控制像素区块的“采样+填充”,不是逐像素模糊,而是有意识地降低视觉分辨率。关键不在于写得多复杂,而在于理解 getImageData 和 putImageData 的配合逻辑,以及如何避开跨域、模糊、性能这三类典型坑。
基础准备:Canvas 初始化与图片加载
必须等图片完全加载后再绘制,否则 getImageData 会报错或返回空数据:
- 用
new Image()创建图片对象,先绑定onload再赋值src - 获取 canvas 上下文后,用
ctx.drawImage(img, 0, 0)把图绘到画布上 - 确保 canvas 的
width和height与图片自然尺寸一致(或按需缩放),避免 drawImage 自动插值引入模糊
马赛克实现:区块采样 + 填充(推荐)
这是最高效、最可控的方式,不操作每个像素,而是把图像划成网格,每格只取一个颜色并铺满:
- 设定马赛克单元大小,比如
blockSize = 12 - 遍历所有区块左上角坐标:
x从0到width,步长blockSize;y同理 - 在每个区块内,读取左上角像素的 RGBA 值:
data[(y * width + x) * 4]等 - 用
ctx.fillStyle = rgb(r,g,b)+fillRect(x, y, blockSize, blockSize)填满该格
这种方式比逐像素改 imageData.data 快得多,也更稳定,适合实时预览。
绕不开的跨域问题
如果图片来自其他域名(比如用户上传的外链图),直接调 getImageData 会触发 “tainted canvas” 错误:
- 本地开发时,不能双击 HTML 文件打开(
file://协议),必须起本地服务(如 VS Code Live Server 插件) - 线上部署时,图片服务器需返回
Access-Control-Allow-Origin: *或指定域名 - 若无法改服务端,可将图片转为 base64 字符串内联,或通过后端代理接口中转
高清屏适配:防止输出模糊
在 Retina 屏或高 DPR 设备上,Canvas 若未适配物理像素,渲染会自动插值,导致马赛克边缘发虚:
- 获取
window.devicePixelRatio,设 canvas 的width和height为clientWidth × DPR - 用
ctx.scale(dpr, dpr)缩放绘图坐标系,让 fillRect 等操作仍按 CSS 像素书写 - 避免对 canvas 元素使用 CSS
transform: scale(),那会触发浏览器二次插值
不复杂但容易忽略。


















