html5滤镜如何让色彩分离_html5色彩分离滤镜教程【步骤】

Canvas 2D 实现色彩分离需用 getImageData + putImageData 对 R/G/B 通道分别偏移整数像素并边界检查;WebGL 方案更高效,须在 Fragment Shader 中对纹理三次采样并归一化偏移量。

Canvas 2D 上下文里用 getImageData + putImageData 实现色彩分离

HTML5 本身没有内置“色彩分离”滤镜,所谓“HTML5 滤镜”实际依赖 Canvas 的像素级操作。核心是把 R、G、B 通道分别偏移不同像素,再合成——不是调色,而是错位。

常见错误是直接改 CSS filter 或 SVG filter,它们不支持通道级位移;也有人误用 ctx.filter(仅支持模糊/亮度等基础效果,不支持分离)。

实操建议:

  • canvas.getContext('2d') 获取上下文,drawImage 把图片画进去
  • 调用 ctx.getImageData(0, 0, width, height) 拿到原始像素数组 data(Uint8ClampedArray,每 4 个值为 R/G/B/A)
  • 新建一个空 ImageData,遍历原数组,把 R 通道写入偏移 (x + 2, y) 位置,G 写入 (x, y + 2),B 写入 (x - 2, y + 1) —— 偏移量可调,但必须是整数像素
  • 注意边界:写入时要判断目标坐标是否在画布范围内,否则会静默失败或报错 IndexSizeError
  • 最后用 ctx.putImageData() 贴回画布

WebGL 方案更高效但需写 shader:用 gl_FragColor 分别采样偏移纹理

Canvas 2D 方案在大图或动画中容易卡顿,真正实用的色彩分离得上 WebGL。本质是 Fragment Shader 中对同一纹理做三次采样,R/G/B 各自加不同 vec2 偏移。

关键点:

  • 顶点着色器保持标准 UV 传递;片元着色器里用 texture2D(u_texture, v_uv + u_offsetR) 取 R 分量,同理 G/B
  • u_offsetRu_offsetGu_offsetB 是 uniform,单位是纹理坐标(0.0–1.0),不是像素,需按画布宽高归一化
  • 不要用 mix() 简单叠加,要分别赋值:gl_FragColor = vec4(r, g, b, 1.0),否则通道会混合失真
  • 若用 Three.js,可用 ShaderMaterial 封装,但注意默认材质会启用 lighting,得设 lights: false

CSS filter 和 做不了真分离,只能模拟色偏

有人试过 filter: sepia(1) hue-rotate(90deg) 或 SVG 的 ,这些只是线性变换 RGB 值,所有像素统一计算,不会产生通道错位效果——也就是没“分离感”。

典型表现:

  • 图像整体变紫/变绿,但边缘依然锐利,没有 R/G/B 各自

    拖影的效果
  • 无法控制每个通道的偏移方向和距离
  • feColorMatrix 的 matrix 参数是 5×4 变换矩阵,只能缩放/平移颜色值,不能空间位移像素

移动端性能坑:iOS Safari 对 getImageData 有尺寸限制

iOS 15+ 的 Safari 在 canvas 宽高乘积超 ~1600万 像素时,getImageData 会直接返回空数据且不报错——这是静默降级,极易被忽略。

应对方式:

  • 先用 canvas.width * canvas.height 判断是否超限,超了就缩放图片再处理
  • 避免在 requestAnimationFrame 里反复调用 getImageData,它触发强制同步读取,严重阻塞主线程
  • Android Chrome 相对宽松,但低端机仍可能 OOM,建议最大处理尺寸控制在 1280×720 以内

色彩分离真正的复杂点不在算法,而在像素边界的越界检查、跨平台读取限制、以及 WebGL 下纹理坐标的归一化换算——这三处出错,效果就全歪了。