首页
/ 如何用 exportToBlob 把 Excalidraw 场景以代码方式导出为 PNG 图片?

如何用 exportToBlob 把 Excalidraw 场景以代码方式导出为 PNG 图片?

2026-09-08 17:07:30作者:冯梦姬Eddie

在把 @excalidraw/excalidraw 集成进自己的 React 应用后,如果想在用户点击按钮(或任意程序逻辑)时把当前画布上的内容导出成 PNG 文件,而不是依赖 Excalidraw 自带的界面菜单,就需要直接调用库导出的 exportToBlob 工具函数。它接收场景元素和 appState,返回一个以 Blob 类型解析的 Promise,内部通过 canvas.toBlob 完成生成。本文给出从安装依赖、获取 API 实例到导出并验证 PNG 的完整代码路径。

准备条件:安装包并确保容器有尺寸

npmyarn 安装 React 与 Excalidraw 包:

npm install react react-dom @excalidraw/excalidraw
# 或
yarn add react react-dom @excalidraw/excalidraw

两个容易忽略的前置条件,来自安装文档

  • Excalidraw 组件会占满容器 100% 的 widthheight,渲染它的容器必须有非零尺寸,否则画布不可用。
  • 默认情况下 Excalidraw 会从 CDN 下载字体;如果应用要离线或自托管运行,需要把 node_modules/@excalidraw/excalidraw/dist/prod/fonts 的内容复制到静态资源目录,并把 window.EXCALIDRAW_ASSET_PATH 指向该路径(资源在站点根目录时为 "/")。字体加载影响导出结果中的文字渲染,离线环境建议提前配置。

第一步:通过 excalidrawAPI 拿到场景数据

exportToBlob 需要三个输入:场景元素、appState 和文件数据。这三者都通过 excalidrawAPI prop 暴露的实例方法获取(参见 excalidrawAPI 文档):

方法 用途
getSceneElements() 返回场景中未删除的全部元素
getAppState() 返回当前 appState
getFiles() 返回场景中的文件数据(可能包含没有被任何元素引用的文件,若要把文件持久化存储,需要先与已存元素比对)

回调触发后要把 api 存进 state 以便后续使用:

export default function App() {
  const [excalidrawAPI, setExcalidrawAPI] = useState(null);
  return (
    <Excalidraw excalidrawAPI={(api) => setExcalidrawAPI(api)} />
  );
}

注意:自 v0.17.0 起 Ref 支持已被移除,旧代码里用 ref 拿实例的写法必须改为 excalidrawAPI 回调。

第二步:调用 exportToBlob 导出 PNG

exportToBlob@excalidraw/excalidraw 导入:

import { exportToBlob } from "@excalidraw/excalidraw";

其签名为 exportToBlob(opts: ExportOpts & { mimeType?: string, quality?: number, exportPadding?: number }),其中 opts 会整体传给 exportToCanvas。完整示例(元素列表参考 仓库示例应用 中 "Export to Blob" 按钮的写法):

import { useState } from "react";
import { Excalidraw, exportToBlob } from "@excalidraw/excalidraw";

export default function App() {
  const [excalidrawAPI, setExcalidrawAPI] = useState(null);
  const [blobUrl, setBlobUrl] = useState("");

  const onExportPng = async () => {
    if (!excalidrawAPI) {
      return;
    }
    const elements = excalidrawAPI.getSceneElements();
    if (!elements || !elements.length) {
      return;
    }
    const blob = await exportToBlob({
      elements,
      appState: excalidrawAPI.getAppState(),
      files: excalidrawAPI.getFiles(),
      mimeType: "image/png",
    });
    setBlobUrl(window.URL.createObjectURL(blob));
  };

  return (
    <div>
      <button onClick={onExportPng}>Export to Blob (PNG)</button>
      <img src={blobUrl} alt="exported scene" />
      <div style={{ width: 400, height: 400 }}>
        <Excalidraw excalidrawAPI={(api) => setExcalidrawAPI(api)} />
      </div>
    </div>
  );
}

各参数及默认值(引自 Export Utilities 文档):

参数 类型 默认值 说明
elements ExcalidrawElement[] _ 要导出的元素,本例用 getSceneElements() 取未删除元素
appState AppState 默认 App State 场景的 app state,本例用 getAppState() 取当前值
files BinaryFiles _ 场景中添加的文件(图片等),用 getFiles() 获取
mimeType string image/png 图片格式;导出 PNG 时可显式传 "image/png" 或省略
quality number 0.92 0~1 之间的画质值,仅对 image/jpeg/image/webp 生效,导出 PNG 时会被忽略
exportPadding number 10 画布四周添加的 padding

appState 中还有几个只影响导出结果的属性("Additional attributes of appState for export* APIs"):

属性 类型 默认值 说明
exportBackground boolean true 是否导出背景色
viewBackgroundColor string #fff 背景色
exportWithDarkMode boolean false 是否以暗色模式导出
exportEmbedScene boolean false 是否把场景数据嵌入 png/svg 中,会使图片体积增大

如果需要暗色导出,把 appState 改成 { ...excalidrawAPI.getAppState(), exportWithDarkMode: true } 即可。

可选:控制导出画布的尺寸

opts 继承自 exportToCanvas 的参数,因此还可以传入画布尺寸控制项(见同一文档的 exportToCanvasgetDimensions 小节):

  • getDimensions:一个函数,接收场景内容的 width/height,返回实际导出用的 { width, height, scale? }scale 默认为 1)。文档示例中固定导出 350×350 的写法是 getDimensions: () => { return { width: 350, height: 350 }; }
  • maxWidthOrHeight:限定导出图片的最大宽或高;提供后 getDimensions 会被忽略(源码在两者同时传入时会在控制台警告 "getDimensions() is ignored when maxWidthOrHeight is supplied.")。

验证导出结果

文档给出的操作路径是:导出完成后用 window.URL.createObjectURL(blob) 生成 URL,赋给 <img>src,页面上出现与画布一致的图片即表示成功(上例代码即如此,示例应用export-blob 区域也是同样的显示方式)。

失败时 exportToBlob 的 Promise 会 reject:查看 实现源码,当底层 canvas.toBlob 没有产生结果时会 reject(new Error("couldn't export to blob")),可以用 try/catch 捕获该错误提示用户重试。

限制与常见坑

  • quality 对 PNG 无效:源码里对 mimeType === "image/png" 且传了 quality 的情况会打印警告 "quality" will be ignored for "image/png" mimeType,调 PNG 画质没有意义。
  • 导出 JPEG 时若 exportBackgroundfalse,实现会自动把 exportBackground 置为 true 并打警告,因为 JPEG 不支持透明背景。
  • mimeType 写成 "image/jpg" 会被内部自动纠正为 image/jpeg,可以放心使用。
  • getFiles() 返回的文件可能包含未被元素引用的文件,只用于本次导出的 files 参数没有问题;若还要把它们持久化存储,需自行与已存元素比对。
  • 旧版 ref 写法在 v0.17.0 起不可用,ready/readyPromise 也已移除,统一改用 excalidrawAPI 回调。

更多导出工具(exportToCanvasexportToSvgexportToClipboard)的签名与参数见 Export Utilities 文档exportToBlob 本身就是先走 exportToCanvas 拿到 canvas 再调 canvas.toBlob,因此上面 exportToCanvas 小节的参数说明同样适用于本场景。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.81 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
920
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.79 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
390