One call handles every Fabric.js export image format, plus SVG and JSON. You choose the area, the scale and the background. The current zoom and pan do not matter, because exports always use document coordinates.
Loading the live demo. Its code is below.
"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>
);
}Export and download
import { downloadExport } from "fabricjs-document-engine";
const result = await engine.export({ format: "png", scale: 2 });
downloadExport(result, "poster.png");result is { format, mimeType, blob, width, height, warnings }. Upload the blob, show it in an <img>, or download it with downloadExport.
Options
| Option | Values | Default |
|---|---|---|
format | 'png', 'jpeg', 'webp', 'svg' or 'json' | required |
scale | Output size multiplier, such as 2 for retina | 1 |
quality | 0 to 1, for JPEG and WebP | 0.92 |
area | 'canvas', 'content', 'selection' or { left, top, width, height } | 'canvas' |
padding | Extra space around content or selection | 0 |
background | 'keep', 'transparent' or any CSS color | 'keep' |
signal | An AbortSignal to cancel | — |
'content'crops to the objects, which is handy for a canvas to image thumbnail.- A JPEG has no transparency, so an empty or transparent background becomes white, not black.
- The export never changes the canvas, the undo history or the unsaved state.
Export SVG
const svg = await engine.export({
format: "svg",
area: "content",
padding: 20,
});To export SVG, the engine escapes all text, so a text box that contains <script> stays text.
Export to JSON
const { document } = await engine.export({ format: "json" });A JSON export is the same portable document a save produces. When assets.upload is set, tab-only images are uploaded first, so the file opens on any device.
Check before exporting
A tainted canvas is the classic reason a Fabric.js export image call fails. Before rendering, the engine checks every object:
MISSING_IMAGE: an image did not load.CROSS_ORIGIN_IMAGE: an image from another site without CORS would make the browser block a PNG, JPEG or WebP export. SVG and JSON are not affected.MISSING_FONT: a font is not available andassets.requireFontsis on.
If anything is found, export rejects with EXPORT_BLOCKED and error.problems lists each { code, message, url, objectIds }. Run the same check first to show it in your menu:
const check = await engine.preflightExport({ format: "png" });
if (!check.ok) showProblems(check.problems);Fixes for each problem are in images and fonts. A PDF export is not included; render a Fabric.js export image and place it in a PDF library of your choice.