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

JavaScript canvas中drawImage无法绘制的问题及修复建议请求

问题:Canvas缩放保存图片时drawImage未生效

我编写了一段JavaScript代码,意图将Canvas内容缩放后保存为图片。点击saveImg按钮触发逻辑:先将Canvas内容转为Image对象img1,再调用resizeImage函数在辅助Canvas中缩放绘制,最后通过a标签下载。但drawImage函数未生效,尽管img1包含Canvas的数据。我尝试在aux_canvas中手动绘制矩形可正常保存,请求修复建议。

原代码如下:

saveImg.addEventListener("click", () => {
  var img1 = new Image();
  img1.src = canvas.toDataURL();

  const link = document.createElement("a"); // 创建HTML<a>元素并存储在link变量中

  function resizeImage(img1, w, h) {
    var result = new Image();
    var aux_canvas = document.createElement("canvas");
    aux_canvas.width = w;
    aux_canvas.height = h;
    console.log(aux_canvas);
    aux_ctx = aux_canvas.getContext("2d");
    if (img1.complete) {
      console.log("complete");
      aux_ctx.drawImage(img1, 0, 0, w, h);
    } else {
      console.log("!complete");
      img1.onload = function () {
        console.log("onload");
        aux_ctx.drawImage(img1, 0, 0, w, h);
      };
    }
    console.log(img1);
    //aux_canvas.getContext("2d").drawImage(img_func, 0, 0, w, h);
    result.src = aux_canvas.toDataURL();
    return result;
  }

  var img2 = resizeImage(img1, 28, 28);

  link.download = `${Date.now()}.jpg`; // 设置link的download属性,用当前时间戳生成唯一文件名
  link.href = img2.src; // 将Canvas内容转为dataURL赋值给link的href属性
  link.click(); // 点击链接下载图片
});

问题根源

  1. 异步时机错误:即使img1是dataURL,图片加载仍为异步流程。resizeImage函数中,result.src = aux_canvas.toDataURL()会在drawImage执行前(尤其是onload回调的情况)就完成赋值,此时aux_canvas是空的,导致下载的图片无内容。
  2. 全局变量污染:aux_ctx未声明为局部变量,可能引发意外的作用域问题。

修复方案

将resizeImage改为返回Promise的异步函数,用async/await确保绘制完成后再执行下载逻辑,同时修正变量作用域:

saveImg.addEventListener("click", async () => {
  const img1 = new Image();
  img1.src = canvas.toDataURL();

  const link = document.createElement("a");

  // 改为返回Promise的异步缩放函数
  function resizeImage(img, targetWidth, targetHeight) {
    return new Promise((resolve) => {
      const auxCanvas = document.createElement("canvas");
      auxCanvas.width = targetWidth;
      auxCanvas.height = targetHeight;
      const auxCtx = auxCanvas.getContext("2d");

      // 统一绘制逻辑
      const drawScaledImage = () => {
        auxCtx.drawImage(img, 0, 0, targetWidth, targetHeight);
        const scaledImg = new Image();
        scaledImg.src = auxCanvas.toDataURL("image/jpeg", 0.9); // 指定jpg格式和质量
        resolve(scaledImg);
      };

      // 判断图片是否已加载完成
      if (img.complete) {
        drawScaledImage();
      } else {
        img.onload = drawScaledImage;
      }
    });
  }

  // 等待缩放完成再继续
  const img2 = await resizeImage(img1, 28, 28);

  link.download = `${Date.now()}.jpg`;
  link.href = img2.src;
  link.click();
});

额外优化点

  • 明确指定toDataURL("image/jpeg", 0.9),确保生成的是真正的jpg格式(默认是png,即使后缀写jpg),第二个参数为图片质量(0-1之间)。
  • 变量命名采用驼峰式,提升代码可读性。
  • 避免全局变量,所有变量使用const/let声明为局部变量。

内容的提问来源于stack exchange,提问作者Irina Morel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 02:27:03