Skip to content

Export Formats

Templates can be exported to PDF, SVG, and PNG.

The PDF export supports all standards that Typst has to offer. The default in Oicana is PDF/A-3b (PDF 1.7).

You can configure the default PDF standards to use when exporting a given template in the template’s manifest file.

[tool.oicana.export.pdf]
standards = ["ua-1"]

The manifest above would configure this template to produce PDF files for Universal Access.

By default, Oicana produces tagged (accessible) PDFs. You can turn tagging off in the template’s manifest:

[tool.oicana.export.pdf]
tagged = false

The standards array accepts three kinds of entries (see the Typst docs for a complete list of supported standards):

  • Versions: 1.4, 1.5, 1.6, 1.7, 2.0
  • PDF/A profiles: every a-* entry (e.g. a-2b, a-3b, a-4)
  • PDF/UA: ua-1

You can list at most one of each kind, and they all have to share a compatible base PDF version. In particular, a PDF/A profile and PDF/UA-1 combine into an accessible, archivable document when both build on the same PDF version. For example, PDF/A-3b and PDF/UA-1 (both based on PDF 1.7):

[tool.oicana.export.pdf]
standards = ["ua-1", "a-3b"]

This is exactly the combination our invoice example template exports, and what an accessible e-invoice needs.

Incompatible combinations are rejected. For example, ["a-4", "ua-1"] fails because PDF/A-4 builds on PDF 2.0 while PDF/UA-1 requires PDF 1.7 or earlier. Listing two PDF/A profiles or two versions is rejected as well. oicana validate catches invalid combinations in your manifest, and oicana test catches documents that do not meet the standards they declare.

Oicana’s PDF export can attach files to the document and write custom XMP metadata. Together with the default PDF/A-3b standard, this is what e-invoice formats such as ZUGFeRD and Factur-X require: a human-readable PDF/A-3b document with the structured invoice XML embedded as an associated file and the matching metadata declared in the document’s XMP.

In many scenarios, PNG export is an easy option for previews.

Oicana integrations allow configuring the pixels per point in a PNG export. A smaller ratio leads to faster file generation and smaller files, but lower resolution. The default is 1px/pt. The parameter is called pixelsPerPt (pixels_per_pt in Python and Rust) and comes before the page range on every PNG export method, as in the examples below.

To keep memory usage in check, a PNG export is limited to 256 million pixels by default, which is about 1 GB of memory. The budget covers the per-page buffers as well as the merged canvas they are combined into, so an export costs roughly twice its output pixels. That corresponds to roughly 14 A4 pages at 300 DPI, or a single A4 page at about 1150 DPI. A large document combined with a high pixels-per-point ratio can hit this limit. In that case you can still export pages individually.

Like PNG, a multi-page export produces a single file with the pages stacked vertically, separated by the same gap. A two-page A4 document comes out as one SVG with a viewBox covering both pages. Export pages individually (see below) if you need one file per page.

SVG has no resolution setting, since it is vector output, and none of the PNG pixel budget applies to it.

Every export method accepts an optional page range, so you can export just a part of a document instead of the whole thing. Page indices are 0-based and inclusive: the range 0–2 exports the first three pages. Both bounds are optional. Omitting the start exports from the first page, omitting the end exports through the last page.

Each integration exposes this as a pages argument on the export methods, together with a PageRange helper to construct the range. Method names follow each language’s conventions, for example exportPdf in Node.js, export_pdf in Python and Rust, and ExportPdf in C#.

import { CompilationMode, PageRange, Template } from '@oicana/browser';
// The first three pages
const excerpt = template.exportPdf(
jsonInputs,
blobInputs,
CompilationMode.Production,
PageRange.of(0, 2),
);
// The third page through the end of the document
const rest = template.exportPdf(
jsonInputs,
blobInputs,
CompilationMode.Production,
PageRange.of(2),
);
// The first page as a PNG at twice the default resolution
const preview = template.exportPng(
jsonInputs,
blobInputs,
CompilationMode.Production,
2.0,
PageRange.single(0),
);

The export methods above compile the template and export it in a single call. When you need several exports of the same inputs, for example a full PDF plus a per-page PNG preview, compiling once and exporting repeatedly avoids the redundant compilation work.

Call compile instead of an export method to get a compiled document handle. It exposes the same export methods and reports its page count, so you can export individual pages or page ranges without recompiling. Release the handle when you are done to free memory.

import { PageRange, Template } from '@oicana/browser';
const document = template.compile(jsonInputs, blobInputs);
try {
const pdf = document.exportPdf();
const thumbnails = Array.from({ length: document.pageCount }, (_, page) =>
document.exportPng(2.0, PageRange.single(page)),
);
} finally {
document.dispose();
}

CompiledDocument implements Symbol.dispose, so using document = template.compile(...) releases it for you. TypeScript needs ESNext.Disposable in the lib of your tsconfig.json for that; the Vite react-ts scaffold ships "lib": ["ES2023", "DOM"] and reports Cannot find global type 'Disposable' until you add it.