canvas 的 imagedata 对象支持直接操作像素实现灰度图(加权平均法:gray = 0.299×r + 0.587×g + 0.114×b)和反色滤镜(r'/g'/b' = 255 − r/g/b),需先 getimagedata 获取数据、遍历修改、再 putimagedata 写回,且须确保图像已加载、同源、尺寸匹配。

Canvas 的 ImageData 对象提供了直接操作像素的能力,灰度图和反色滤镜正是通过修改每个像素的 RGBA 值实现的。关键在于先用 ctx.getImageData() 获取原始像素数据,再遍历修改,最后用 ctx.putImageData() 写回画布。
获取并锁定像素数据
必须在同源图像上执行,否则会触发安全限制。使用 getImageData(x, y, width, height) 获取指定区域的像素数组(data 是一维 Uint8ClampedArray,每 4 个连续元素代表一个像素的 R、G、B、A):
- 确保图像已加载完成(监听
img.onload) - 画布尺寸需与图像一致,否则坐标可能越界
- 返回的
ImageData是副本,修改它不会自动更新画布
实现灰度图(加权平均法)
人眼对绿色最敏感,对蓝色最不敏感,因此标准灰度公式为:G = 0.299×R + 0.587×G + 0.114×B。将计算出的灰度值同时赋给 R、G、B 通道,A 保持不变:
- 遍历
data数组,步长为 4(跳过每个像素的四个分量) - 提取
data[i](R)、data[i+1](G)、data[i+2](B) - 计算灰度值并取整:
gray = Math.floor(0.299*r + 0.587*g + 0.114*b) - 写回:
data[i] = data[i+1] = data[i+2] = gray
实现反色滤镜(RGB 取反)
反色即用 255 减去每个颜色通道值,Alpha 通道不参与运算:
- 对每个像素:R' = 255 − R,G' = 255 − G,B' = 255 − B
- 注意:无需判断是否越界,Uint8ClampedArray 会自动截断到 [0,255]
- 代码简洁写法:
data[i] = 255 - data[i]; data[i+1] = 255 - data[i+1]; data[i+2] = 255 - data[i+2];
写回画布并注意性能
修改完 ImageData.data 后,调用 putImageData() 将结果渲染到画布:
- 该操作是同步且较重的,避免在动画循环中高频调用
- 如需实时处理,可考虑使用 OffscreenCanvas 或 Web Workers 分离计算
- 调试时可用
console.log(data)查看前几个像素验证逻辑是否正确
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










