You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Canvas drawImage缩放透明图片时出现画面重叠故障如何解决

故障原因

你触发了Canvas绘制的经典误用:将同一个Canvas实例同时作为绘制源和绘制目标,叠加透明像素的特性才出现了“两张图”的现象:

  1. 首先通过putImageData将100x50的原始小图绘制到了目标Canvas的左上角,此时Canvas上已经存在这张小图的内容
  2. 调用drawImage时传入的第一个参数就是这个已经绘制了小图的Canvas本身:需要从它左上角取100x50的内容放大2倍,再绘制到它自己的整个200x100区域
  3. 原始小图的大部分区域alpha值为0,放大绘制时透明像素不会覆盖Canvas上已有的原始小图内容,所以原始小图会保留下来,和上层放大后的图叠加,看起来就像同时存在两张图
  4. 当你把透明区域的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 04:06:08