HTML5 Canvas 实现双重曝光需用 globalCompositeOperation="lighten" 逐层绘制预加载图像,而非 CSS filter;关键在像素级合成控制、跨域配置与加载时机,否则易出黑屏或错位。

HTML5 Canvas 双重曝光不是靠 filter CSS 属性实现的
直接用 CSS 的 filter: url(#myFilter) 或 filter: blur() 做不出真正的双重曝光效果。Canvas 才是可控叠加图像的核心——它允许你逐像素读写、混合透明度、叠加多层位图,而纯 CSS 滤镜无法精确控制两张图的 alpha 混合模式和权重。
关键点在于:globalCompositeOperation 控制图层合成方式,globalAlpha 控制透明度,drawImage() 多次绘制不同图像到同一画布。
用 globalCompositeOperation = "lighten" 模拟胶片双重曝光
传统胶片双重曝光本质是“亮部叠加”:同一位置取两张图中更亮的像素值。Canvas 的 "lighten" 合成模式正好对应这个逻辑。
-
ctx.globalCompositeOperation = "lighten"必须在每次drawImage()前设置(否则沿用上一次) - 两张图需预加载完成再绘制,否则可能只画出空白
- 建议统一缩放到画布尺寸,避免因尺寸错位导致局部缺失
- 若想加权重(比如第一张占 70%,第二张占 30%),不能只靠
globalAlpha,得用getImageData()+ 手动计算像素,性能较差,慎用
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
// 先清空
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 绘第一张图
ctx.drawImage(img1, 0, 0, canvas.width, canvas.height);
// 切换合成模式
ctx.globalCompositeOperation = 'lighten';
// 绘第二张图(自动与底层做亮部叠加)
ctx.drawImage(img2, 0, 0, canvas.width, canvas.height);
用 globalCompositeOperation = "multiply" 做暗部叠加(反向双重曝光)
如果你要的是“阴影叠加”效果(比如人像+纹理底图),"multiply" 更合适:每个通道取两图像素值相乘再归一化,结果比原图更暗、对比更强。
立即学习“前端免费学习笔记(深入)”;
注意:"multiply" 对纯白区域无效(白×任意=任意),所以底图最好避开大面积纯白;而 "lighten" 对纯黑无效(黑在亮部叠加中不贡献)。
- 两张图都应为
RGBA格式(带 alpha),否则透明区域会变黑 - 如果图像是
crossOrigin="anonymous"加载的,才能调用getImageData();否则会触发SecurityError - 移动端 Safari 对
"lighten"支持较晚(iOS 15.4+),旧版本会回退为"source-over",需要降级提示或 fallback 方案
别忽略图像加载顺序和跨域限制
双重曝光失败,80% 是因为图像没加载完就 drawImage(),或者图片来自其他域名但没配 crossOrigin。
- 必须监听
img.onload,而不是 DOM ready 后立刻画 - 所有外部图片都要加
img.crossOrigin = "anonymous",否则getImageData()报错,drawImage()却可能静默失败 - 若用
URL.createObjectURL()加载本地文件,无需跨域,但记得revokeObjectURL()避免内存泄漏 - Canvas 尺寸要用
canvas.width/canvas.height设置,别只靠 CSS 缩放,否则图像模糊且合成失真
真正难的不是写出两行 drawImage(),而是确保两张图在正确时间、正确格式、正确坐标下,以可预测的方式叠加——中间任何一个环节断掉,出来的就是黑块、白屏或错位残影。










