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

React NFT艺术生成器如何下载绘制完成的不同HTML Canvas图片

问题根因

  • 全程复用同一个canvas实例:所有绘制操作都作用在同一块画布上,异步加载的图片完成绘制的时序不确定,后触发的绘制会直接覆盖前一次的画布内容
  • 时序逻辑完全错误:loadImages是异步方法,你没有等待图片加载、绘制完成就用固定1秒延迟触发下载,循环连续调用两次drawLayer时,两次的绘制操作会互相抢占画布,等1秒延迟触发下载时,画布内已经只剩最后一次绘制的结果,自然所有下载的图片都一样
  • 画布操作混用API:同时用document.getElementById('myCanvas')和React refcanvas.current获取画布实例,逻辑混乱

修复方案

核心逻辑调整

把异步加载逻辑Promise化方便控制时序,每次创建独立临时canvas绘制避免内容冲突,绘制完成后立刻触发下载,取消不可靠的固定延迟。

修复后的完整代码

// loadImages改为Promise化,方便等待执行完成
const loadImages = (sources) => {
  return new Promise((resolve) => {
    const images = {};
    let loadedImages = 0;
    const numImages = Object.keys(sources).length;
    if (numImages === 0) resolve(images);
    for (const src in sources) {
      images[src] = new Image();
      images[src].crossOrigin = 'anonymous'; // 跨域图片导出需要加该配置
      images[src].onload = () => {
        if (++loadedImages >= numImages) {
          resolve(images);
        }
      };
      images[src].src = sources[src];
    }
  })
}

const download = (canvas, index) => {
  const url = canvas.toDataURL("image/png");
  const link = document.createElement('a');
  link.download = `img_${index}.png`;
  link.href = url;
  link.click();
  URL.revokeObjectURL(url); // 释放内存
}

const drawLayer = async (data, index) => {
  // 每次创建独立临时canvas,避免绘制互相干扰
  const canvas = document.createElement('canvas');
  canvas.width = 230;
  canvas.height = 230;
  const context = canvas.getContext('2d');
  const sources = {};
  // 获取当前批次的图片地址
  const objURLs = getImagesURLs(data, index);
  
  objURLs.forEach((url, i) => {
    const key = `image${i+1}`;
    sources[key] = url;
  })
  // 等待所有图片加载完成
  const images = await loadImages(sources);
  // 按顺序绘制所有图层
  objURLs.forEach((url, i) => {
    if (url) {
      context.drawImage(images[`image${i+1}`], 0, 0, 230, 230);
    }
  })
  // 绘制完成立刻下载当前画布内容
  download(canvas, index);
}

const generateCollection = async () => {
  // 等待单张生成完成再生成下一张,也可改用Promise.all并行生成
  for(let k = 1; k <= 2; k++){
    await drawLayer(data, k);
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<!-- 原页面的展示用canvas可按需保留,不影响生成逻辑 -->
<Button onClick={()=>generateCollection()} >生成合集</Button>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 02:54:04