使用Canvas drawImage缩放透明图片时出现画面重叠故障如何解决
故障原因
你触发了Canvas绘制的经典误用:将同一个Canvas实例同时作为绘制源和绘制目标,叠加透明像素的特性才出现了“两张图”的现象:
- 首先通过
putImageData将100x50的原始小图绘制到了目标Canvas的左上角,此时Canvas上已经存在这张小图的内容 - 调用
drawImage时传入的第一个参数就是这个已经绘制了小图的Canvas本身:需要从它左上角取100x50的内容放大2倍,再绘制到它自己的整个200x100区域 - 原始小图的大部分区域alpha值为0,放大绘制时透明像素不会覆盖Canvas上已有的原始小图内容,所以原始小图会保留下来,和上层放大后的图叠加,看起来就像同时存在两张图
- 当你把透明区域的alpha改成255时,放大后的图完全不透明,会彻底盖住底层的原始小图,故障现象自然消失
正确解决方案
不要直接复用目标Canvas作为绘制源,新增一个离屏Canvas存放原始尺寸的内容,再用离屏Canvas作为drawImage的源绘制到目标Canvas即可,完全保留drawImage的缩放能力:
<canvas id="cvs" width=200 height=100></canvas>
const canvas = document.getElementById('cvs'); const ctx = canvas.getContext('2d'); ctx.imageSmoothingEnabled = false; // 新建离屏Canvas存放原始尺寸内容,不参与页面渲染 const offscreenCvs = document.createElement('canvas'); offscreenCvs.width = 100; offscreenCvs.height = 50; const offscreenCtx = offscreenCvs.getContext('2d'); // 原始内容仅绘制到离屏Canvas,不要画到可见的目标Canvas上 const imageData = offscreenCtx.createImageData(100, 50); const data = imageData.data; for (var i = 0; i < data.length; i += 4) { if (i % 400 > 360) { data[i] = 255; data[i + 1] = 0; data[i + 2] = 0; data[i + 3] = 255; } else { data[i] = 0; data[i + 1] = 0; data[i + 2] = 0; data[i + 3] = 0; } } offscreenCtx.putImageData(imageData, 0, 0); // 从离屏Canvas读取源内容,缩放绘制到目标Canvas ctx.drawImage(offscreenCvs, 0, 0, 100, 50, 0, 0, 200, 100);
可选轻量方案
如果不想新增离屏Canvas,也可以先将原始内容缓存为ImageBitmap后再清空画布绘制,适合单次绘制的场景:
const canvas = document.getElementById('cvs'); const ctx = canvas.getContext('2d'); ctx.imageSmoothingEnabled = false; const imageData = ctx.createImageData(100, 50); const data = imageData.data; for (var i = 0; i < data.length; i += 4) { if (i % 400 > 360) { data[i] = 255; data[i + 1] = 0; data[i + 2] = 0; data[i + 3] = 255; } else { data[i] = 0; data[i + 1] = 0; data[i + 2] = 0; data[i + 3] = 0; } } ctx.putImageData(imageData, 0, 0); // 缓存原始区域内容后清空画布再绘制 createImageBitmap(canvas, 0, 0, 100, 50).then(bitmap => { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(bitmap, 0, 0, 200, 100); });
内容的提问来源于stack exchange,提问作者epileptic
相关产品推荐
相关产品推荐

