PDF Export
Export raster and vector PDFs from Polotno, with bleed, crop marks, PDF/X-1a, and spot color support
Polotno offers two PDF export paths:
- Raster —
store.saveAsPDF()/store.toPDFDataURL()in the browser, orpolotno-nodeon the server. Each page is a flattened image embedded in the PDF. - Vector —
@polotno/pdf-export(browser or Node), or the Cloud Render API withvector: true. Resolution-independent output with selectable text.
Try it without code: The SVG to PDF converter exposes both options — it ships vector by default via @polotno/pdf-export/browser and offers a one-click bitmap fallback. Drop a file and try both before integrating.
Choosing raster vs vector
| Raster | Vector | |
|---|---|---|
| Output | Flattened image per page | Selectable text, scalable shapes |
| Visual fidelity | Identical to canvas | May differ slightly (font shaping, effects) |
| File size | Larger at high pixelRatio | Smaller, resolution-independent |
| Print compliance | Good with high pixelRatio | Required for PDF/X-1a, spot colors |
| Where it runs | Browser, or polotno-node on the server | Browser, Node, or Cloud Render API |
| Server required | No (browser path) | No (browser path); PDF/X-1a needs Node + Ghostscript |
Pick raster when you need pixel-perfect parity with the editor canvas. Pick vector for selectable text, smaller files, or print-shop deliverables (PDF/X-1a, spot inks, foils). Both can run fully client-side now — vector via the @polotno/pdf-export/browser entry.
Raster export
Browser-side export via store.saveAsPDF(). Same options apply to store.toPDFDataURL().
Quick start
await store.saveAsPDF({
fileName: 'design.pdf',
includeBleed: true,
cropMarkSize: 20,
pixelRatio: 2,
});Bleed and crop marks
Bleed is the extra ink area beyond the trim edge. Crop marks indicate where the print shop should cut.
// set bleed on the page
store.activePage.set({ bleed: 35 }); // 35px
// show bleed area on the canvas (optional, for editor preview)
store.toggleBleed(true);
// export
await store.saveAsPDF({
includeBleed: true,
cropMarkSize: 20, // crop mark length in pixels
});See Page Bleed for working with bleed in the editor.
Quality
Use pixelRatio to control resolution. dpi affects PDF page dimensions, not image quality.
await store.saveAsPDF({ pixelRatio: 2 }); // recommended for print
await store.saveAsPDF({ pixelRatio: 4 }); // ultra-highSee Units and Measures for DPI details.
Options
await store.saveAsPDF({
fileName: 'design.pdf',
includeBleed: true,
cropMarkSize: 20,
pixelRatio: 2,
onProgress: (progress) => console.log(progress),
});See Store API for the complete reference.
Vector export
Three ways to produce vector PDFs. All accept the same Polotno JSON and produce equivalent output for the same input — pick the one that matches your hosting model.
Browser package: @polotno/pdf-export/browser
Convert a design to a vector PDF entirely in the user's browser — no server, no Ghostscript, no API key.
npm install @polotno/pdf-exportimport { jsonToPDFBlob } from '@polotno/pdf-export/browser';
async function exportToPDF(store) {
const blob = await jsonToPDFBlob(store.toJSON());
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'design.pdf';
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(url);
}The browser entry also exports jsonToPDFBytes(json, attrs): Promise<Uint8Array> for cases where you want raw bytes (IndexedDB, navigator.share, WebTransport, etc.).
CORS
When the design references remote images, fonts, or SVG sources, the browser fetches those at export time. They must be reachable with CORS:
- Google Fonts (
fonts.googleapis.comandfonts.gstatic.com) work out of the box. - Custom asset URLs must be served with
Access-Control-Allow-Origin: *(or your origin), or pre-fetched and inlined asdata:URLs in the JSON.
Browser limitations
The browser entry does not support attrs.pdfx1a or attrs.validate — those rely on Ghostscript, which has no browser equivalent. Pass them and you'll get a clear runtime error pointing at the Node entry. For PDF/X-1a, spot colors, and Ghostscript-backed validation, see the Node section below.
Cloud Render API
Hosted rendering. Send the JSON as a render job with format: 'pdf' and vector: true.
const req = await fetch('https://api.polotno.com/api/renders?KEY=YOUR_API_KEY', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
design: store.toJSON(),
format: 'pdf',
vector: true,
}),
});See Cloud Render API for full options, polling, webhooks, and CMYK color profiles.
Node package: @polotno/pdf-export
Run the conversion fully offline inside Node 18+. Fits CI jobs, backend services, and desktop tools. Required for PDF/X-1a print-ready output and Ghostscript-backed spot colors.
npm install @polotno/pdf-exportimport fs from 'fs/promises';
import { jsonToPDF } from '@polotno/pdf-export';
const data = JSON.parse(await fs.readFile('./polotno.json', 'utf-8'));
await jsonToPDF(data, './output.pdf');jsonToPDFBytes(data, attrs): Promise<Uint8Array> is also exported on the Node entry — useful when you want raw bytes (to upload, attach, etc.) without writing to disk.
Bleed and crop marks
Set bleed (pixels) on each page in the JSON, then enable bleed and crop marks at export time.
// JSON
const data = {
width: 1080,
height: 1080,
pages: [{ background: '...', bleed: 36, children: [/* ... */] }],
};
// export
await jsonToPDF(data, './print-ready.pdf', {
pdfx1a: true,
includeBleed: true,
cropMarkSize: 18, // reserve 18px around the bleed for crop marks
});When includeBleed or cropMarkSize is set, the output PDF carries correct PDF/X page boxes:
- MediaBox — full sheet (trim + bleed + crop-mark margin)
- BleedBox — trim + bleed (where ink may cover)
- TrimBox — final cut size
- ArtBox — same as TrimBox
TrimBox ⊆ BleedBox ⊆ MediaBox, per PDF/X spec. RIPs and proofers use these boxes to identify the live area without guessing.
Element coordinates in the JSON stay relative to the trim corner — a (0, 0) element still lands at the top-left of the trim. Backgrounds extend automatically into the bleed strip; the crop-mark margin remains unprinted.
DPI handling
Coordinates in the JSON are pixels at the specified DPI; PDFs use points (1pt = 1/72 inch). The library converts: points = pixels × (72 / dpi).
// uses dpi from JSON (or 72 if unspecified)
await jsonToPDF(data, './output.pdf');
// override
await jsonToPDF(data, './output.pdf', { dpi: 150 });A 1920×1080 canvas at 300 DPI exports as 6.4″ × 3.6″; the same canvas at 72 DPI exports as 26.67″ × 15″.
PDF/X-1a
Print-ready output with CMYK conversion, transparency flattening, and font outlining.
await jsonToPDF(data, './print-ready.pdf', {
pdfx1a: true,
validate: true, // optional — verify PDF/X-1a compliance
metadata: {
title: 'Catalog Cover',
author: 'Marketing Team',
application: 'Polotno Automation 1.0',
},
});Note: PDF/X-1a conversion requires GhostScript on the host machine —
brew install ghostscript,apt-get install ghostscript, or download from ghostscript.com.
Spot colors and overprint
Map specific fills or strokes to separation inks for foil, Pantone, or varnish workflows. Any element using the matched color is exported with the correct separation ink; CMYK fallbacks ensure predictable previews.
await jsonToPDF(data, './foil-cover.pdf', {
pdfx1a: true,
spotColors: {
'rgba(255,215,0,1)': {
name: 'Gold Foil',
pantoneCode: 'Pantone 871 C', // optional reference
cmyk: [0, 0.15, 0.5, 0], // 0–1 range, used as fallback
overprint: true,
},
'#C0C0C0': {
name: 'Silver Foil',
cmyk: [0, 0, 0, 0.25],
overprint: true,
},
},
});Color matching is flexible. '#FFD700', '#ffd700', 'rgb(255,215,0)', and 'rgba(255,215,0,1)' all match the same color. Works on text, lines, figures (rect, circle, star, blobs), and SVG elements.
overprint: true tells the press to print the spot ink on top of the underlying CMYK rather than knocking it out. Without overprint, a misregistered foil die leaves a visible white halo at the edge. With overprint, CMYK prints continuously through the spot region and the foil stamps over it. This is the standard choice for foil and varnish.
Tip: Verify spot colors in Adobe Acrobat Pro: Tools → Print Production → Output Preview → Separations. Use Simulate Overprinting to preview how the press will composite the layers.
Caveat: Spot color preservation through PDF/X-1a depends on Ghostscript not flattening transparency in the spot region. Plain figures, lines, text, and simple SVG paths work. SVGs that use
<clipPath>or<mask>may have their spot color flattened to CMYK during pdfx1a conversion. For foil regions, prefer plain shapes or simple SVG paths over masked artwork.
Full reference
For all options and the latest changes, see the @polotno/pdf-export README on npm.
Troubleshooting
Bleed not visible on canvas? Use store.toggleBleed(true).
Raster export looks low quality? Increase pixelRatio to 2 or 4. dpi controls page dimensions, not quality.
Wrong page size? Adjust the JSON dpi value (or pass dpi to jsonToPDF).
Spot color rendered as CMYK in the foil region? Check whether the artwork uses <clipPath> or <mask> — Ghostscript may flatten transparency groups during PDF/X-1a conversion. Replace with plain shapes or simple paths.
Related
- Page Bleed — working with bleed in the editor
- Cloud Render API — hosted rendering
- Server-side image generation with Node.js —
polotno-nodefor raster export on the server - Units and Measures — DPI and unit conversion
- Store API — complete export API reference