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

使用html2canvas下载图片时提示canvas宽高为0的DOMException错误

问题描述

使用html2canvas实现指定div转canvas后下载图片的功能时,已为待转换的目标div设置明确宽高样式,运行代码始终抛出如下错误:

DOMException: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The image argument is a canvas element with a width or height of 0

相关功能实现代码如下:

const handleDownload = () => {
  // 待下载的自定义div
  let containerImage = document.createElement('div');
  containerImage.style.width = 1080
  containerImage.style.height = 1080
  for(let i = 0;i < 3;i++){
    let tmpDiv = document.createElement('div')
    tmpDiv.style.width = 1080
    tmpDiv.style.height = 300
    tmpDiv.style.background = 'red'
    containerImage.appendChild(tmpDiv)
  }
  document.body.appendChild(containerImage)
  downloadImageFromCanvas(containerImage,12,() => console.log('1'))
}

// 从canvas下载图片
const downloadImageFromCanvas = (Ref, id,callback) => {
  html2canvas(Ref)
    .then(async (canvas) => {
      const photo = await getImage({ canvas, width: 1360, height: 675 });
      const element = document.createElement('a');
      const blobUrl = URL.createObjectURL(photo);
      element.href = blobUrl;
      element.download = `Image ${id}`;
      element.click();
      callback()
    })
    .catch((e) => console.log('error', e));
};

// canvas转换为blob
const getImage = async ({
  canvas,
  width,
  height,
  mime = 'image/png',
  quality = 0.8,
}) => {
  return new Promise((resolve) => {
    const tmpCanvas = document.createElement('canvas');
    tmpCanvas.width = width * 0.99;
    tmpCanvas.height = height;

    const ctx = tmpCanvas.getContext('2d');
    ctx.drawImage(
      canvas,
      0,
      0,
      canvas.width,
      canvas.height,
      0,
      0,
      width,
      height
    );

    tmpCanvas.toBlob(resolve, mime, quality);
  });
};
故障原因
  • 样式值非法:设置width、height样式时未添加单位,部分浏览器会直接判定为非法样式规则丢弃,导致节点实际渲染宽高为0
  • 调用时机错误:动态创建DOM插入页面后立即调用html2canvas,此时浏览器还未完成布局、绘制流程,html2canvas无法正确计算节点尺寸,最终生成宽高为0的canvas,传入drawImage方法时触发报错
  • 逻辑缺陷:待截图节点实际尺寸为10801080,二次绘制到新canvas时硬编码使用1360675的非等比尺寸,即使修复0宽高问题,导出的图片也会出现拉伸变形
解决方案

按以下顺序调整代码即可修复问题:

  • 给所有DOM宽高样式补充px单位,保证样式规则生效
  • 将html2canvas调用延迟到下一个事件循环执行,等待浏览器完成DOM渲染后再触发截图
  • 显式给html2canvas传入待截图节点的宽高参数,避免尺寸计算异常
  • 修正二次绘制的尺寸参数,保持和原节点等比,避免图片拉伸;如果不需要特殊裁剪,可直接使用html2canvas输出的原始canvas导出,跳过二次绘制逻辑
  • 下载完成后清理临时创建的DOM、释放生成的blob地址,避免内存泄漏和页面污染

修复后的核心代码示例:

const handleDownload = () => {
  let containerImage = document.createElement('div');
  // 补充px单位
  containerImage.style.width = '1080px'
  containerImage.style.height = '1080px'
  for(let i = 0;i < 3;i++){
    let tmpDiv = document.createElement('div')
    tmpDiv.style.width = '1080px'
    tmpDiv.style.height = '300px'
    tmpDiv.style.background = 'red'
    containerImage.appendChild(tmpDiv)
  }
  document.body.appendChild(containerImage)
  // 延迟执行等待DOM渲染完成
  setTimeout(() => {
    downloadImageFromCanvas(containerImage,12,() => {
      // 移除临时DOM
      document.body.removeChild(containerImage)
      console.log('1')
    })
  }, 0)
}

const downloadImageFromCanvas = (Ref, id,callback) => {
  html2canvas(Ref, {
    // 显式指定截图尺寸
    width: 1080,
    height: 1080,
    useCORS: true
  })
    .then(async (canvas) => {
      // 使用等比尺寸导出,避免拉伸
      const photo = await getImage({ canvas, width: 1080, height: 1080 });
      const element = document.createElement('a');
      const blobUrl = URL.createObjectURL(photo);
      element.href = blobUrl;
      element.download = `Image ${id}`;
      element.click();
      // 释放blob地址
      URL.revokeObjectURL(blobUrl)
      callback()
    })
    .catch((e) => console.log('error', e));
};

内容的提问来源于stack exchange,提问作者Minh Huy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 17:57:27