canvas滤镜分全局(css filter)和局部(getimagedata/putimagedata)两类:前者性能好但仅渲染层生效,后者精确可控但需手动处理像素并注意跨域、越界等细节。

Canvas 实现滤镜效果,核心在于区分“全局滤镜”和“局部像素处理”两种路径:前者依赖 CSS filter 属性快速施加视觉效果,后者通过 getImageData + putImageData 对每个像素逐个计算,实现精确可控的图像变换。二者适用场景不同,不可混用,也不应互相替代。
全局滤镜:用 CSS filter 快速叠加视觉效果
适用于背景模糊、整体色调偏移、简单高斯模糊等无需修改原始像素的场景。它不改变图像数据,只影响渲染层,性能好、代码少、支持硬件加速。
- 直接在 canvas 元素或其父容器上设置
filter: blur(4px) brightness(1.2) contrast(1.3) - 注意:CSS 滤镜作用于整个元素(含边框、阴影),无法只模糊某一块区域
- 移动端需加前缀(
-webkit-filter),且大半径模糊(>8px)可能触发重绘卡顿 - 不能导出为带滤镜的图片——
toDataURL()返回的是原始未滤镜图像
局部像素处理:读-改-写三步完成自定义滤镜
真正意义上的“滤镜逻辑”发生在这里。你拿到的是原始 RGBA 数组,可对任意像素做数学运算,灰度、反色、怀旧、浮雕等都由此构建。
用户要生成可打印的中文字帖/练习纸、导出多页 A4 PDF 报告,或把 SVG 设计稿零误差还原到 Canvas 时使用。本技能是「Canvas 内容工厂闭环」的总控,编排:网格渲染引擎(13 种教育网格+拼音标注) → 多页 PDF 导出(A4 合成) → SVG 精准复刻(坐标误差<0.001px)。触发词:生成字帖、练习纸、导出 PDF、SVG 转 Canvas、印刷级还原、A4 报告、米字格田字格。
- 先调用
ctx.drawImage(img, 0, 0)把图绘制到 canvas 上 - 再用
ctx.getImageData(0, 0, width, height)获取像素数组data - 遍历
data,每 4 个值一组(R、G、B、A),按公式修改,例如灰度:const gray = 0.299*r + 0.587*g + 0.114*b;
然后赋给data[i] = data[i+1] = data[i+2] = gray; - 最后
ctx.putImageData(imageData, 0, 0)写回画布,立即可见
关键细节:避免常见陷阱
看似简单,但几个边界问题常导致结果异常或报错:
-
跨域限制:加载非同源图片时,canvas 会污染,
getImageData抛出安全错误;需设置img.crossOrigin = "anonymous"并确保服务端配 CORS -
透明通道处理:多数滤镜不改 alpha 值,但若强行设
data[i+3] = 0,会导致局部变透明;慎改 A 分量 -
数值越界:亮度调节后可能超出 [0, 255],必须用
Math.min(255, Math.max(0, value))截断 - 性能瓶颈:1000×1000 图像含 400 万字节数据,纯 JS 遍历易卡顿;大图建议移交 Web Worker 处理
何时选哪一种?一句话判断
想一键模糊背景弹窗?用 CSS filter。想把用户头像实时转成赛博朋克风?必须走像素级处理。前者是“渲染层修饰”,后者是“数据层改造”。两者可组合使用——比如先用像素处理生成怀旧底图,再用 filter: brightness(0.9) 微调明暗。









