You need to enable JavaScript to run this app. Fabric.js导出canvas图片时,如何追加DOM textarea文本到图片下方?
优惠活动
大模型
产品
解决方案
定价
更多

Fabric.js导出canvas图片时,如何追加DOM textarea文本到图片下方?

实现思路

核心是不直接导出原有Fabric画布,而是新建一个页面不可见的离屏canvas作为合成容器,将原有画布内容、textarea文本按位置拼接绘制后,最终导出合成canvas的内容。
具体实现步骤:

  • 计算合成画布的尺寸:宽度和原有Fabric画布保持一致,高度 = 原有画布高度 + 文本展示区预留高度(预留高度根据文本量、行高、上下内边距计算)
  • 加载原有Fabric画布生成的图片资源,等图片加载完成后,将其绘制到离屏画布的上半区域(坐标(0,0),尺寸和原画布一致)
  • 获取textarea的文本内容,按照指定的字体、行高、自动换行规则,从离屏画布上原画布底部的位置开始逐行绘制文本
  • 走原有的下载逻辑,导出这个合成完成的离屏canvas

改造后的参考代码

直接替换原有导出逻辑即可,对页面现有Fabric画布的交互无侵入:

// 文本展示区的固定配置,可按需调整
const TEXT_CONFIG = {
  fontSize: 16,
  lineHeight: 1.5,
  padding: 16, // 文本区上下左右的内边距
  color: "#333",
  maxTextWidth: width, // 文本不超出画布总宽度
}

async function exportCanvasWithText(canvas, textareaValue: string) {
  // 1. 加载原有Fabric画布的图片资源
  const originalCanvasUrl = canvas.toDataURL({
    format: "png",
    width,
    height,
  })
  const originalImg = new Image()
  originalImg.src = originalCanvasUrl
  // 等待图片加载完成,避免绘制空白
  await new Promise((resolve) => {
    originalImg.onload = resolve
  })

  // 2. 预计算文本排版,确定文本区需要的总高度
  const measureCtx = document.createElement("canvas").getContext("2d")
  measureCtx.font = `${TEXT_CONFIG.fontSize}px sans-serif`
  const textLines = wrapText(textareaValue, measureCtx, TEXT_CONFIG.maxTextWidth - TEXT_CONFIG.padding * 2)
  const textAreaHeight = TEXT_CONFIG.padding * 2 + textLines.length * TEXT_CONFIG.fontSize * TEXT_CONFIG.lineHeight

  // 3. 创建离屏合成画布
  const compositeCanvas = document.createElement("canvas")
  const compositeCtx = compositeCanvas.getContext("2d")
  compositeCanvas.width = width
  compositeCanvas.height = height + textAreaHeight

  // 4. 把原有Fabric画布内容绘制到离屏画布顶部
  compositeCtx.drawImage(originalImg, 0, 0, width, height)

  // 5. 绘制textarea文本到离屏画布的下半区域
  compositeCtx.fillStyle = TEXT_CONFIG.color
  compositeCtx.font = `${TEXT_CONFIG.fontSize}px sans-serif`
  const startY = height + TEXT_CONFIG.padding
  textLines.forEach((line, index) => {
    compositeCtx.fillText(
      line,
      TEXT_CONFIG.padding,
      startY + index * TEXT_CONFIG.fontSize * TEXT_CONFIG.lineHeight
    )
  })

  // 6. 复用原有下载逻辑,导出合成完成的画布
  const url = compositeCanvas.toDataURL("png");
  const a = document.createElement("a");
  a.href = url;
  a.download = "download";
  const clickHandler = () => {
    setTimeout(() => {
      URL.revokeObjectURL(url);
      a.removeEventListener("click", clickHandler);
      a.remove();
    }, 150);
  };
  a.addEventListener("click", clickHandler, false);
  a.click();
}

// 工具方法:实现文本自动换行,对齐原生textarea的排版逻辑
function wrapText(text: string, ctx: CanvasRenderingContext2D, maxWidth: number) {
  const lines: string[] = []
  let currentLine = ""
  for (let char of text) {
    const testLine = currentLine + char
    const testWidth = ctx.measureText(testLine).width
    if (testWidth > maxWidth && currentLine) {
      lines.push(currentLine)
      currentLine = char
    } else {
      currentLine = testLine
    }
  }
  if (currentLine) lines.push(currentLine)
  return lines
}

关键注意事项
  • 原Fabric画布生成的图片必须等待onload加载完成后再执行绘制,否则会出现合成图缺失画布内容的问题
  • 自动换行逻辑可根据实际排版需求迭代,比如需要适配中英文混排、长字符串断行时,可优化wrapText的判断规则
  • 如果需要匹配textarea的视觉效果,可在绘制文本前,先在离屏canvas的文本区域填充和textarea一致的背景色

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.06 17:45:02