canvas图像色彩转换需直接操作imagedata像素数据,灰度滤镜用加权平均(0.299r+0.587g+0.114b)取整赋值,反色滤镜对rgb各通道执行255-值,alpha保持不变;须确保图像加载完成、画布尺寸匹配、同源且调用putimagedata写回。

Canvas 图像色彩转换的核心在于直接操作像素数据,灰度滤镜与反色滤镜都是通过修改 ImageData 中每个像素的 RGBA 值实现的。关键不是“改什么”,而是“怎么取值、怎么赋值、怎么写回”——三步缺一不可。
灰度滤镜:用加权平均还原人眼感知
简单取 R、G、B 平均((r+g+b)/3)会丢失明暗层次,因为人眼对绿色最敏感,对蓝色最不敏感。标准做法是加权计算:
- 提取每个像素的 red(data[i])、green(data[i+1])、blue(data[i+2])
- 按公式计算:gray = r × 0.299 + g × 0.587 + b × 0.114
- 用位运算 | 0 取整(比 Math.floor 更快),再同时赋给 R、G、B 三个通道
- Alpha 值(data[i+3])保持不变,不参与运算
反色滤镜:RGB 通道逐值取反
反色本质是颜色关于 127.5 的对称变换,操作极简且安全:
- 对每个像素的 R、G、B 分量分别执行:255 - 当前值
- 即 data[i] = 255 - data[i];data[i+1] = 255 - data[i+1];data[i+2] = 255 - data[i+2]
- Uint8ClampedArray 自动截断,无需额外判断越界
- Alpha 通道跳过,保留原始透明度
必须注意的执行前提
算法再正确,执行环境出错也会白忙一场:
- 图像必须已加载完成(监听 img.onload 再开始处理)
- 画布尺寸需与图像宽高一致,否则 getImageData 坐标可能越界
- 图像须同源,跨域图片会触发安全限制,无法读取像素
- getImageData 返回的是副本,修改后必须显式调用 putImageData 写回画布
性能小提醒
putImageData 是同步重操作,频繁调用会影响响应速度:
- 避免在 requestAnimationFrame 循环中反复执行
- 如需实时预览,可考虑 OffscreenCanvas 或 Web Workers 拆分计算
- 调试时可用 console.log(data.subarray(0, 12)) 查看前 3 个像素验证逻辑











