Every browser has an HTML canvas max size, and above it the canvas stays blank or the tab runs out of memory. The limit is not the same everywhere: desktop Chrome allows a side of 32,767 pixels, while iOS Safari allows about 67 million pixels in total, a square of 8,192. A design that exports fine on a laptop can then fail on an iPhone, often without an error.
Try it
Loading the live demo. Its code is below.
"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>
);
}The 4× export fits. The 60× export would be 28,800 pixels wide and is refused before any canvas is made, and so is a page of 20,000 × 20,000.
The limits
const engine = createDocumentEngine({
canvas,
limits: {
maxCanvasSide: 16384,
maxCanvasPixels: 8192 * 8192,
maxImagePixels: 8192 * 8192,
maxDocumentLength: 100_000_000,
},
});| Limit | Default | Checked on |
|---|---|---|
maxCanvasSide | 16,384 | The page, and PNG, JPEG, WebP and PDF exports |
maxCanvasPixels | 67,108,864 (8,192²) | The page and raster exports |
maxImagePixels | 67,108,864 | Each image, after it is decoded |
maxDocumentLength | 100,000,000 | The JSON of a document that is loaded |
The defaults match the strictest common browser, iOS Safari. Raise them only for an editor that runs on desktop browsers. Each check is a multiplication done before any canvas exists, so it costs nothing.
Exports
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);
}An export over the canvas size limit fails with EXPORT_BLOCKED and a TOO_LARGE problem, which says the size it would have had. PDF export instead draws the page at a lower resolution, so a PDF still comes out.
Resize the canvas
Use setPage to resize the canvas or change its background. The change is one undo step, and a size above the limits is refused with UNSAFE_DOCUMENT before anything changes:
try {
engine.setPage({ width: 3000, height: 2000, background: "#ffffff" });
} catch (error) {
if (isDocumentEngineError(error)) showMessage(error.message);
}Images and documents
An image above maxImagePixels fails to load with the reason TOO_LARGE, and a document whose page or JSON is over the limits is refused with UNSAFE_DOCUMENT. Both are checked before Fabric decodes or creates anything. The error codes list every code, and the security page covers the other limits. Stay under the HTML canvas max size and every device can open and export the document.