Polotno
Export & Import

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-export

It 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); // Blob

One 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:

OptionDefaultMeaning
key–Your Polotno API key, required for production use
pageIdfirst pagePage to render
pixelRatio1Output resolution multiplier
mimeType'image/png''image/png' or 'image/jpeg' (JPEG has a white backdrop)
quality0.92JPEG quality, 0 to 1
dpithe design's dpiResolution written into the file, unless it is 72. Pixels do not change
includeBleedfalseInclude the page's bleed
ignoreBackgroundfalseLeave the page background out
textOverflow'change-font-size'Overflow rule for text that sets none; see Text Sizing
textSplitAllowedfalseLet fitting text break inside a word
skipFontErrorfalseDraw with a fallback font and warn, instead of throwing
skipImageErrorfalseDraw the editor's error placeholder and warn, instead of throwing
onWarningconsole.warnCalled for everything drawn differently from the editor
blockPrivateNetworkfalseAlso refuse loopback and private network addresses
fetchGuard–(url) => boolean. Replaces the built-in download check
allowLocalFilesfalseRead 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-skipped warning.
  • Lottie. A Lottie element is left out and reports an unsupported-element warning.

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.

On this page