Fabric.js Document Engine

搜索文档

查找页面或章节

EN

画布大小限制

查看 Markdown

canvas 画布大小的上限是多少,以及引擎怎样保持在上限之内。

每个浏览器都限制了 canvas 画布大小,超过之后画布会一片空白,或者标签页的内存会耗尽。各浏览器的上限不同:桌面版 Chrome 的 canvas最大宽度是 32,767 像素,而 iOS Safari 总共只允许大约 6,700 万像素,也就是 8,192 见方。在笔记本上能正常导出的设计,到了 iPhone 上可能会失败,而且常常没有任何错误提示。

试一试

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

size-limits-demo.tsx
"use client";
 
import { isDocumentEngineError } from "fabricjs-document-engine";
import { useDocumentEngine } from "fabricjs-document-engine/react";
import { ExpandIcon, ImageIcon, MaximizeIcon } 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";
 
export default function SizeLimitsDemo() {
  const t = useTranslations("demos");
  const { elementRef, canvas } = useFabricCanvas();
  const engine = useDocumentEngine(canvas);
  const [message, setMessage] = useState<{
    tone: "ok" | "error";
    text: string;
  } | null>(null);
 
  useEffect(() => {
    if (!engine) return;
    engine.canvas.add(...seedShapes());
    engine.clearHistory();
  }, [engine]);
 
  async function check(scale: number) {
    if (!engine) return;
    const preflight = await engine.preflightExport({ format: "png", scale });
    const problem = preflight.problems[0];
    setMessage(
      problem
        ? {
            tone: "error",
            text: t("sizeLimits.refused", { code: problem.code, scale }),
          }
        : {
            tone: "ok",
            text: t("sizeLimits.fine", {
              scale,
              width: 480 * scale,
              height: 300 * scale,
            }),
          }
    );
  }
 
  function hugePage() {
    if (!engine) return;
    try {
      engine.setPage({ width: 20000, height: 20000 });
    } catch (error) {
      setMessage({
        tone: "error",
        text: t("sizeLimits.page", {
          code: isDocumentEngineError(error) ? error.code : String(error),
        }),
      });
    }
  }
 
  return (
    <DemoFrame>
      <DemoCanvas elementRef={elementRef} label={t("canvas")} />
 
      <Toolbar>
        <ToolButton
          icon={ImageIcon}
          label={t("sizeLimits.small")}
          disabled={!engine}
          onClick={() => void check(4)}
        />
        <ToolButton
          icon={MaximizeIcon}
          label={t("sizeLimits.large")}
          primary
          disabled={!engine}
          onClick={() => void check(60)}
        />
        <ToolButton
          icon={ExpandIcon}
          label={t("sizeLimits.hugePage")}
          disabled={!engine}
          onClick={hugePage}
        />
      </Toolbar>
 
      <Status tone={message?.tone ?? "idle"}>
        {message?.text ?? t("sizeLimits.hint")}
      </Status>
    </DemoFrame>
  );
}

按 4× 导出没有问题。按 60× 导出会有 28,800 像素宽,在创建任何画布之前就被拒绝;20,000 × 20,000 的页面也一样。

限制

const engine = createDocumentEngine({
  canvas,
  limits: {
    maxCanvasSide: 16384,
    maxCanvasPixels: 8192 * 8192,
    maxImagePixels: 8192 * 8192,
    maxDocumentLength: 100_000_000,
  },
});
限制默认值检查范围
maxCanvasSide16,384页面,以及 PNG、JPEG、WebP 和 PDF 导出
maxCanvasPixels67,108,864(8,192²)页面和位图导出
maxImagePixels67,108,864每张图片解码后的像素
maxDocumentLength100,000,000加载文档的 JSON

默认值对应最严格的常见浏览器 iOS Safari。只有编辑器只在桌面浏览器上运行时,才需要调高。每项检查都是在创建画布之前做的一次乘法,几乎没有开销。

导出

const preflight = await engine.preflightExport({ format: "png", scale: 4 });
 
if (!preflight.ok) {
  const tooLarge = preflight.problems.find(
    (problem) => problem.code === "TOO_LARGE"
  );
  if (tooLarge) showMessage(tooLarge.message);
}

超过 canvas 画布大小限制的导出会以 EXPORT_BLOCKED 失败,并附带一个 TOO_LARGE 问题,说明它本来会有多大。PDF 导出则会降低页面分辨率,所以仍然能得到 PDF。

调整画布大小

用 setPage 调整画布大小或修改背景。这次修改算一步撤销;超过限制的尺寸会在任何改动之前以 UNSAFE_DOCUMENT 被拒绝:

try {
  engine.setPage({ width: 3000, height: 2000, background: "#ffffff" });
} catch (error) {
  if (isDocumentEngineError(error)) showMessage(error.message);
}

图片和文档

超过 maxImagePixels 的图片会以 TOO_LARGE 的原因加载失败;页面或 JSON 超过限制的文档会以 UNSAFE_DOCUMENT 被拒绝。两者都在 Fabric 解码或创建任何东西之前检查,不会占用多余内存。错误代码列出了所有代码,其他限制见安全。保持在 canvas 画布大小上限之内,任何设备都能打开和导出文档。