Image Export
Render Polotno designs to PNG or JPEG in Node.js or the browser, with no headless browser
The @polotno/image-export package renders a page of Polotno design JSON to a PNG or JPEG image, in Node.js or in the browser, with no headless browser. It builds the same canvas scene the editor builds and draws it with Skia (@napi-rs/canvas) in Node.js, or on an OffscreenCanvas in the browser.
For still images on a server it is faster and lighter than polotno-node, which drives a headless Chromium. Use polotno-node for video and GIF output, and for designs whose video frames or Lottie animations must appear in the image.
Installation
npm install @polotno/image-exportIt runs in the browser and in Node.js 22.13 or newer.
Basic Usage
Node.js – save the file:
import fs from 'fs';
import { jsonToImage } from '@polotno/image-export';
const json = JSON.parse(fs.readFileSync('./design.json', 'utf8'));
await jsonToImage(json, 'page.png', { key: 'YOUR_API_KEY' });Browser – download the file:
import { jsonToImage } from '@polotno/image-export';
// triggers a "page.png" download
await jsonToImage(store.toJSON(), 'page.png', { key: 'YOUR_API_KEY' });In memory:
import { jsonToImageBytes, jsonToImageBlob } from '@polotno/image-export';
const bytes = await jsonToImageBytes(json); // Uint8Array
const blob = await jsonToImageBlob(json); // BlobOne call renders one page: the page named by pageId, or the first page. The root import picks the Node or browser build for you; @polotno/image-export/node and @polotno/image-export/browser select one explicitly.
Options
Every function takes an optional last argument:
| Option | Default | Meaning |
|---|---|---|
key | – | Your Polotno API key, required for production use |
pageId | first page | Page to render |
pixelRatio | 1 | Output resolution multiplier |
mimeType | 'image/png' | 'image/png' or 'image/jpeg' (JPEG has a white backdrop) |
quality | 0.92 | JPEG quality, 0 to 1 |
dpi | the design's dpi | Resolution written into the file, unless it is 72. Pixels do not change |
includeBleed | false | Include the page's bleed |
ignoreBackground | false | Leave the page background out |
textOverflow | 'change-font-size' | Overflow rule for text that sets none; see Text Sizing |
textSplitAllowed | false | Let fitting text break inside a word |
skipFontError | false | Draw with a fallback font and warn, instead of throwing |
skipImageError | false | Draw the editor's error placeholder and warn, instead of throwing |
onWarning | console.warn | Called for everything drawn differently from the editor |
blockPrivateNetwork | false | Also refuse loopback and private network addresses |
fetchGuard | – | (url) => boolean. Replaces the built-in download check |
allowLocalFiles | false | Read file: URLs and paths (Node.js only) |
signal | – | AbortSignal to cancel. The render rejects with signal.reason |
A warning has a stable code (unsupported-element, video-frame-skipped, asset-failed, font-failed), a message, and the elementId and pageId it is about.
Untrusted Designs on a Server
In Node.js, the render downloads the design's images, SVGs and fonts. Only http: and https: URLs are downloaded, and cloud-metadata addresses are always refused. When the design JSON comes from your users, refuse loopback and private hosts too:
await jsonToImageBytes(json, { blockPrivateNetwork: true });
// or replace the built-in check with your own rule
await jsonToImageBytes(json, { fetchGuard: (url) => isAllowed(url) });Local files are refused unless you set allowLocalFiles. Every render also runs under fixed resource limits; a design past one rejects with EXPORT_FAILED and reason limit-exceeded.
What Is Not Drawn
- Video. Video frames are not decoded. A video element draws its border only and reports a
video-frame-skippedwarning. - Lottie. A Lottie element is left out and reports an
unsupported-elementwarning.
Render designs that need either with polotno-node.
Fonts
Google Fonts are downloaded, so the render needs network access for them. On a server with no fonts installed, such as AWS Lambda, characters the design's fonts lack (Chinese, Japanese, Korean, Arabic, Hebrew, symbols, emoji) are drawn with Noto fonts, also downloaded from Google Fonts.
Error Handling
Failures throw a plain Error with a code (DESIGN_INVALID, EXPORT_FAILED, IMAGE_FAILED, FONT_FAILED) and details.reason. Branch on the code, then the reason, never on the message – see Error Handling. The @polotno/image-export README lists every reason.