@nextgensoftwares/folio-export-pdf
PDF export drawn from Folio layout: exact pages, HarfBuzz-shaped glyphs, embedded subset fonts. Guide: Exporters.
in progressexportPdf
ts
function exportPdf(layout: DocumentLayout, opts: PdfExportOptions): Promise<Uint8Array>;
interface PdfExportOptions {
fonts: (font: FontSpec) => MaybePromise<FontBytes | null | undefined>; // bytes of one face (single family name)
shaper?: FontEngine; // the engine the layout was measured with (recommended)
fallback?: string[]; // when building an engine (default ['Noto Sans Arabic'])
images?: (src: string) => MaybePromise<PdfImageData | null | undefined>; // default: data: URLs (png/jpeg)
rasterizeSvg?: (svg: string, width: number, height: number) => MaybePromise<Uint8Array | null | undefined>;
math?: (latex: string, display: boolean, size: number) => MaybePromise<PdfMathResult | null | undefined>;
painters?: Record<string, PdfPainter>; // custom fragments, inline atoms and media:<type>, by key
resolveSrc?: (src: string) => string | Promise<string>; // stored srcs (e.g. idb:…) → fetchable URLs, sync or async
onProgress?: (done: number, total: number) => void;
yieldEvery?: number; // default 25 pages
title?: string;
author?: string;
lang?: string; // catalog /Lang (BCP 47)
document?: FolioDocument; // headings → bookmarks + named destinations (h<index>, heading id); `#name` links jump there
outline?: boolean; // write bookmarks when `document` is given (default true)
colors?: { text?; code?; link?; marker?; codeMark?; highlight? };
onWarning?: (warnings: string[]) => void;
signal?: { aborted: boolean };
}
type FontBytes = Uint8Array | ArrayBuffer;
interface PdfImageData { data: Uint8Array | ArrayBuffer; type: 'png' | 'jpeg' | 'jpg' | 'svg' | (string & {}) }
interface PdfMathResult { vector?: PdfMathDrawing; png?: Uint8Array; jpeg?: Uint8Array; svg?: string } // vector preferred
interface PdfMathDrawing { width: number; height: number; depth: number; items: PdfMathItem[]; fonts: Record<string, Uint8Array> }
type PdfMathItem = // px, relative to the equation's left edge and baseline (y down)
| { kind: 'glyphs'; font: string; size: number; color?: string; y: number; chars: { c: string; x: number }[] }
| { kind: 'rect'; x: number; y: number; width: number; height: number; color?: string }
| { kind: 'path'; d: string; m: [number, number, number, number, number, number]; fill?: string; stroke?: string; strokeWidth?: number; clip?: { x; y; width; height } };
interface PrintFallback { image?: string; title: string; detail: string; link?: string }
type PdfPainter = (
attrs: Attrs,
ctx: PdfPaintContext & { fragment: CustomFragment | MediaFragment },
) => MaybePromise<void | PrintFallback | null | undefined>; // draw, return a card, or null = default
interface PdfPaintContext {
page: PageLayout;
ops(raw: string): void;
rect(r: { x: number; y: number; width: number; height: number; fill?: string; stroke?: string; strokeWidth?: number; radius?: number }): void;
text(text: string, at: { x: number; y: number; font: FontSpec; color?: string; rtl?: boolean }): Promise<void>;
image(src: string, box: { x: number; y: number; width: number; height: number }): Promise<void>;
}| Type | Description |
|---|---|
PdfExportOptions, FontBytes, PdfImageData, PdfMathResult | options and host-provided data |
PdfPainter, PdfPaintContext | plugin mappings keyed by custom type or media:<type>: draw through ctx (CSS px, page-relative, y down), return a PrintFallback, or null for the default |
PrintFallback | a card for a static medium: optional image, title, detail line, link (same shape as plugin-media's) |
Page layers
PdfExportOptions.pageLayers (e.g. composePlugins(...).pageLayers) are drawn under and over each page's content with target 'pdf', and PdfExportOptions.variables fill their . Layer custom fragments use painters[type], with extra context:
| Export | Description |
|---|---|
PdfPageLayer | structural twin of @nextgensoftwares/folio-editor's PageLayer (no editor dependency) |
PdfLayerPaintContext | PdfPaintContext plus fragment, opacity(alpha) (fill/stroke opacity through a shared ExtGState), measure(text, font) (shaped advance, px) and imageSize(src) |
LayerDrawer | draws the layers of one export (used by exportPdf) |
imageHeaderSize(bytes) | intrinsic size from PNG/JPEG headers, or null |
Page ranges, flattening and protection
See Reader & protection. PdfExportOptions extends PdfProtectionOptions: pages, watermarkMode ('layer' or 'interleaved'), pageVariables(page), permissions, ownerPassword.
| Export | Description |
|---|---|
PdfProtectionOptions | the options above |
PageSelection, selectPages(total, sel), parsePageRange(text, total?), countPages(total, sel) | 1-based selections ([1, [3, 5]], { from, to }) → sorted 0-based indices; "1-3, 7, 10-" parsing |
exportFlattenedPdf(layout, opts), FlattenedPdfOptions | image-only pages from a rasterizer (dpi default 150, pages, permissions): no fonts, no text operators |
PageRasterizer, PageRaster | (page, { index, scale, totalPages }) => { data, type: 'png' | 'jpeg' } |
drawInterleaved(writer, page, ctx, layers) | the hardened-watermark page drawer |
encryptPdf(doc, opts), PdfPermissions, PdfEncryptOptions | standard security handler (V2/R3, RC4-128, empty user password) with print/copy/modify/annotate/fillForms/accessibility flags. Weak by design |
resolveExportRequest(handler, format, total, sel?), ExportVerdict | runs a policy: veto, narrow (never widen), fail closed |
ExportRequest, ExportDecision, ExportRequestHandler | { pages, format, totalPages } → true | false | { allow?, pages?, reason? } |
maxPagesPolicy(max, message?), indicesToSelection(indices) | demo policy (first max pages); indices → selection |
resolveExportPages(opts, editor, mode), PdfExportPolicyOptions, PdfExportMode | the plugin's flow: ask for a range, run the policy |
Plugin
| Export | Description |
|---|---|
pdfExportPlugin(opts?: PdfExportPluginOptions): ExportPlugin | "Export ▸ PDF" toolbar entry: exports editor.layout and downloads it |
PdfExportPluginOptions | Partial<PdfExportOptions> plus faces?: FaceFile[], pageLayers? and variables? (values or getters read at export time), filename?, exporters?: Record<string, unknown> | (() => Record<string, unknown> | undefined) (other plugins' exporters.pdf, a map or a getter), onDone?(bytes, ms), onError?, and PdfExportPolicyOptions: onExportRequest, askPages, onDenied, pageRange (adds "PDF: pages…", default on), flatten: { rasterize, dpi?, permissions?, label? } (adds "PDF (protected, flattened)…"; rasterize may be a parameterless getter called per export) |
splitExporters(map, painters?, resolveSrc?) | { painters, resolveSrc? }: separates painters from plugin-media's resolveSrc entry |
ExportPlugin, ExportUIItem, ExportEditorLike | structural twins of FolioPlugin / UIItem (no editor dependency); all export plugins share one "Export" submenu |
Browser helpers
| Export | Signature | Description |
|---|---|---|
fontFiles | (faces: readonly FaceFile[]) => (font: FontSpec) => Promise<Uint8Array | null> | a fonts callback over font URLs (each fetched once; nearest weight); re-exported from @nextgensoftwares/folio-fonts |
FaceFile | { family; src; weight?: number | [number, number]; style? } | |
loadImageInBrowser | (src) => Promise<PdfImageData | null> | fetch an image (SVG rasterized) |
rasterizeSvgInBrowser | (svg, width, height) => Promise<Uint8Array | null> | SVG → PNG through a canvas |
decodeDataUrl | (src) => PdfImageData | null | decode a data: URL |
mathFromHtml | (render, options?: HtmlMathOptions) => PdfExportOptions['math'] | browser: typesets HTML math (KaTeX) off-screen into a PdfMathDrawing (embedded glyphs, rules, SVG paths); HtmlMathOptions.fontBytes overrides font lookup |
mathImageFromHtml | (render, options?: HtmlMathOptions & { scale?, color? }) => (latex, display, size) => Promise<{ png, width, height, depth } | null> | browser: the same drawing rasterized on a canvas (default 4×), for DOCX math: 'image' |
PdfMathDrawing, PdfMathItem | vector equation: { width, height, depth, items, fonts }; items are glyphs, rect or path. Drawn with its baseline on the math box's baseline, centred, scaled only when typeset at another size | |
svgPathToPdf | (d: string, m?: Matrix) => string | SVG path data (all commands, arcs as cubics) → PDF path operators, points mapped by m |
toUnicodeCMap | (map: ReadonlyMap<number, string>) => string | ToUnicode CMap for glyph id → text (searchable text) |
Comment annotations
| Export | Signature | Description |
|---|---|---|
PdfAnnotation, PdfAnnotationEntry | { author, text, date?, kind?: 'highlight' | 'note', rects, color?, replies? }: a highlight over rects (page px) or a sticky note, replies as notes "in reply to" it (IRT) | |
PdfAnnotationSource | (page, index) => readonly PdfAnnotation[] | undefined | PdfExportOptions.annotations (off unless given); pdfExportPlugin({ annotationsFor: (editor) => source }) builds one per export (see the comments plugin) |
annotationRefs | (ctx, page, list, seq) => PDFRef[] | writes a page's annotations (used by exportPdf) |