Fabric.js Document Engine

搜索文档

查找页面或章节

EN

PNG、JPEG、WebP、SVG 和 JSON,还会先告诉你哪里会出问题。

一次调用就能处理所有 Fabric.js 导出图片的格式,还有 SVG 和 JSON。区域、倍数和背景都由你选。当前的缩放和平移不影响结果,因为导出总是使用文档坐标。

正在加载在线示例,代码在下方。

export-demo.tsx
"use client";
 
import { Textbox } from "fabric";
import { downloadExport, type ExportFormat } from "fabricjs-document-engine";
import { useDocumentEngine } from "fabricjs-document-engine/react";
import { BracesIcon, FileCodeIcon, ImageIcon } from "lucide-react";
import { useTranslations } from "next-intl";
import { useEffect, useState } from "react";
 
import {
  DemoCanvas,
  DemoFrame,
  seedShapes,
  Status,
  Toolbar,
  ToolButton,
} from "./demo-ui";
import { useFabricCanvas } from "./use-fabric-canvas";
 
const FORMATS = [
  { format: "png", icon: ImageIcon },
  { format: "svg", icon: FileCodeIcon },
  { format: "json", icon: BracesIcon },
] as const;
 
export default function ExportDemo() {
  const t = useTranslations("demos");
  const { elementRef, canvas } = useFabricCanvas();
  const engine = useDocumentEngine(canvas);
  const [message, setMessage] = useState("");
  const title = t("export.title");
 
  // A small drawing to export. Text is measured once its font has loaded.
  useEffect(() => {
    if (!engine) return;
    document.fonts.load("600 32px Yellix").finally(() => {
      engine.canvas.add(
        ...seedShapes(),
        new Textbox(title, {
          originX: "left",
          originY: "top",
          left: 48,
          top: 108,
          width: 176,
          fontFamily: "Yellix",
          fontSize: 26,
          fontWeight: 600,
          textAlign: "center",
          fill: "#0d0d0d",
        })
      );
      engine.clearHistory();
    });
  }, [engine, title]);
 
  async function download(format: ExportFormat) {
    if (!engine) return;
    try {
      const result = await engine.export({ format, scale: 2 });
      downloadExport(result, `drawing.${format}`);
      setMessage(
        t("export.done", {
          width: result.width,
          height: result.height,
          format: format.toUpperCase(),
        })
      );
    } catch (error) {
      setMessage(t("export.failed", { message: String(error) }));
    }
  }
 
  return (
    <DemoFrame>
      <DemoCanvas elementRef={elementRef} label={t("canvas")} />
 
      <Toolbar>
        {FORMATS.map(({ format, icon }) => (
          <ToolButton
            key={format}
            icon={icon}
            label={format.toUpperCase()}
            disabled={!engine}
            onClick={() => void download(format)}
          />
        ))}
      </Toolbar>
 
      <Status tone={message ? "ok" : "idle"}>
        {message || t("export.hint")}
      </Status>
    </DemoFrame>
  );
}

导出并下载

import { downloadExport } from "fabricjs-document-engine";
 
const result = await engine.export({ format: "png", scale: 2 });
downloadExport(result, "poster.png");

result 是 { format, mimeType, blob, width, height, warnings }。你可以上传 blob、放进 <img> 显示,或用 downloadExport 下载。

配置项

配置项取值默认值
format'png'、'jpeg'、'webp'、'svg' 或 'json'必填
scale输出尺寸倍数,比如 Retina 屏用 21
quality0 到 1,用于 JPEG 和 WebP0.92
area'canvas'、'content'、'selection' 或 { left, top, width, height }'canvas'
paddingcontent 或 selection 周围的留白0
background'keep'、'transparent' 或任意 CSS 颜色'keep'
signal用于取消的 AbortSignal—
  • 'content' 会裁剪到对象范围,做缩略图很方便。
  • JPEG 没有透明度,所以空白或透明的背景会变成白色,而不是黑色。
  • 导出不会改变画布、撤销历史或未保存状态。

导出 SVG

const svg = await engine.export({
  format: "svg",
  area: "content",
  padding: 20,
});

导出 SVG 时,引擎会转义所有文字,所以文本框里的 <script> 仍然只是文字。

导出 JSON

const { document } = await engine.export({ format: "json" });

导出 JSON 得到的,和保存时生成的可移植文档完全相同。设置了 assets.upload 时,只存在于当前标签页的图片会先上传,所以文件在任何设备上都能打开。

导出前检查

画布被污染(tainted canvas)是 Fabric.js 导出图片失败的经典原因。渲染之前,引擎会检查每个对象:

  • MISSING_IMAGE:图片没有加载成功。
  • CROSS_ORIGIN_IMAGE:来自其他网站、没开 CORS 的图片会让浏览器拦截 PNG、JPEG 或 WebP 导出。SVG 和 JSON 不受影响。
  • MISSING_FONT:字体不可用,且开启了 assets.requireFonts。

发现问题时,export 会以 EXPORT_BLOCKED 拒绝,error.problems 列出每个 { code, message, url, objectIds }。先运行同样的检查,就能在菜单里提示用户:

const check = await engine.preflightExport({ format: "png" });
if (!check.ok) showProblems(check.problems);

每种问题的修复方法见图片和字体。这个包不提供 PDF 导出;可以先用 Fabric.js 导出图片,再放进你选的 PDF 库里。