Canvas反色应优先用getImageData手动像素运算,因ctx.filter跨浏览器支持差;大图或实时场景可选WebGL或OffscreenCanvas;SVG反色仅适用于SVG元素本身。

HTML5 Canvas 中用 ctx.filter 做反色不靠谱
直接设 ctx.filter = "invert(100%)" 看似简单,但实际在多数浏览器(尤其是 Safari 和旧版 Chrome)中不生效,或仅对 drawImage() 生效、对 fillRect() / text 等无效。这不是写法错,是规范支持不一致 —— ctx.filter 本质是 CSS filter 的 canvas 映射,而 Canvas 2D 上下文对它的实现非常有限。
用 getImageData() + 手动像素运算才是可靠反色
这是跨浏览器稳定、可控、可调试的方案。核心是读取像素数组,对每个 r、g、b 分量做 255 - value 运算,a(alpha)保持不变。
实操注意点:
- 必须确保图像已加载完成且同源(否则
getImageData()抛SecurityError) - Canvas 尺寸要和图像原始尺寸一致,否则缩放会模糊像素数据
- 操作前调用
ctx.clearRect(0, 0, width, height)避免残留 - 处理完用
putImageData()写回,不是重绘
简例:
立即学习“前端免费学习笔记(深入)”;
const img = new Image();
img.onload = () => {
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
data[i] = 255 - data[i]; // r
data[i+1] = 255 - data[i+1]; // g
data[i+2] = 255 - data[i+2]; // b
// data[i+3] alpha 不变
}
ctx.putImageData(imageData, 0, 0);
};
img.src = 'photo.jpg';
WebGL 或 OffscreenCanvas 是高性能反色的备选路径
当图像大(如 >2000×2000)、需实时处理(视频帧)或频繁切换滤镜时,纯 CPU 的 getImageData 会卡顿。这时:
- 用 WebGL 编写简单 fragment shader:输入纹理,输出
vec4(1.0 - textureColor.rgb, textureColor.a) - 或用
OffscreenCanvas在 Worker 中做像素计算,避免阻塞主线程 - 注意:WebGL 方案需处理纹理上传、绑定、着色器编译,复杂度陡增;OffscreenCanvas 在 Safari 中支持仍不完整
SVG 只适用于静态 SVG 内容
如果目标是 SVG 元素(比如一个 或 ),可用 SVG 滤镜:
但这个方案和 HTML5 Canvas 无关,也不能用于 Canvas 绘制内容,更不能动态控制强度(比如 invert(70%))。值矩阵里四个 1 是偏移项,对应 RGB 各加 1 → 实际是 1 - r 等效,所以是真正反色。
真正容易被忽略的是:Canvas 反色不是“开个开关”,而是明确区分「目标载体」——你反的是 Canvas 上的位图?SVG 图元?还是 CSS 渲染层?选错路径,后面全是兼容性补丁。










