# pdfnative > Pure native PDF generation library in TypeScript. Zero runtime dependencies, tree-shakeable, producing output that conforms to ISO 32000-1 (PDF 1.7) and ISO 19005 (PDF/A-1b/2b/2u/3b) — the latter validated against the veraPDF reference validator in CI. Works in Node.js, browsers, Deno, Bun, and Web Workers. 22 Unicode scripts with OpenType GSUB/GPOS shaping and full UAX #9 BiDi. PAdES digital signatures with long-term validation (B-B → B-LTA). Current version: 1.7.0. _Verified on 2026-08-29 against the source tree by `npm run verify:docs`; the canonical manifest is ._ ## Docs - [README](https://github.com/Nizoka/pdfnative/blob/main/README.md): Full feature list, install, quick start, API surface, examples. - [ROADMAP](https://github.com/Nizoka/pdfnative/blob/main/ROADMAP.md): Shipped milestones (v1.0 → v1.7; v1.7: PAdES LTV B-B → B-LTA, charts v2, colour-emoji flag/ZWJ sequences, UAX #9 conformance, print production, PDF/A declaration guards, `updateMetadata`; v1.6: parser-side decryptor, streaming merge/split/extract, fill & flatten AcroForms, native vector charts, `extractText`, re-encrypt output; v1.5: math/technical-symbols font, `pdfnative/tools` font compiler/parser, SVG ``, page-labels reader, layout debug overlay + `inspectDocumentLayout`, markup annotation read/write, AI-agent governance; v1.4: document outline/bookmarks, page labels, page-tree manipulation (merge/split/extract), streamToFile, COLRv1 advanced compositing; v1.3: COLRv1 colour emoji, USE-lite shaper integration, true constant-memory streaming, UAX #9 X4–X5 overrides, Telugu + Amharic/Sinhala/Tibetan/Khmer/Myanmar scripts, validatePdfUA) + long-term (WASM, full USE). - [CHANGELOG](https://github.com/Nizoka/pdfnative/blob/main/CHANGELOG.md): Per-version changes. - [Release notes v1.7.0](https://github.com/Nizoka/pdfnative/blob/main/release-notes/v1.7.0.md): PAdES LTV signing B-B → B-LTA (`signPdfBytesWithTimestamp` RFC 3161 timestamps, `addValidationInfo` `/DSS` + `/VRI` OCSP/CRL material, `addDocumentTimestamp`, `listSignatures`, multi-signature via `addSignaturePlaceholder({ allowMultiple })` — network transport injected through `setTimestampProvider`/`setRevocationProvider`, the engine never opens a socket), charts v2 (stackedBar/stackedBarH/area/scatter, secondary right axis, log + UTC time scales, data labels, x-label collision handling), colour-emoji flag & ZWJ sequences (51 flags + 22 ZWJ as COLR ligatures), UAX #9 conformance fixes (RTL digit order, glyph mirroring, ALEF joining, Persian presentation forms), PDF/A declaration guards (`strict`/`onDiagnostic`), incremental writer/xref hardening, `PdfModifier.updateMetadata()`. - [Release notes v1.6.0](https://github.com/Nizoka/pdfnative/blob/main/release-notes/v1.6.0.md): Standard Security Handler reader/decryptor (`openPdf(bytes, { password })`, RC4/AES-128/AES-256; `PdfSourceInput`/`MergeOptions.password` for encrypted merge/split sources), streaming page-tree manipulation (`streamMergedPdfs`/`streamSplitPdf`/`streamExtractPages`), fill & flatten existing AcroForm PDFs (`readFormFields`/`fillForm`/`flattenForm`) — encrypted documents included (encrypted incremental update), native vector charts (`chart` block: bar/barH/line/pie/donut), text extraction (`extractText`: per-page reading-order text + positioned runs, encrypted PDFs supported), re-encrypt merge/split output (`MergeOptions.encrypt`, AES-128/256), expanded colour-emoji subset (221 → 1167 incl. complete Transport & Map). Fixes: spec-compliant R6 hash + all-strings encryption on the writer; incremental trailer carries `/Encrypt` forward. - [Release notes v1.5.0](https://github.com/Nizoka/pdfnative/blob/main/release-notes/v1.5.0.md): math/technical-symbols font (lang `'math'`, `registerFont`), `pdfnative/tools` (`compileFontData`/`parseFontData`), SVG `` rendering, page-labels reader (`getPageLabels()`), layout debug overlay (`layout: { debug: true }`) + `inspectDocumentLayout()`, markup annotation read/write (`buildAnnotation`/`getAnnotations`/`addAnnotation`), control-character hardening (#58), table descender fix (#59), AI-agent governance (#56). - [Release notes v1.4.0](https://github.com/Nizoka/pdfnative/blob/main/release-notes/v1.4.0.md): document outline/bookmarks (`/Outlines`, `outline: 'auto'`), page labels (`/PageLabels`), page-tree manipulation (`mergePdfs`/`splitPdf`/`extractPages`, secure-by-default 256 MiB `maxOutputSize` cap), `streamToFile()`, COLRv1 sweep gradients + `PaintComposite` blend modes, pluggable signature crypto provider (`setCryptoProvider`), font-data validator (`validateFontData`), viewer preferences (`/ViewerPreferences`), nested lists, table cell borders + vertical alignment. - [Release notes v1.3.0](https://github.com/Nizoka/pdfnative/blob/main/release-notes/v1.3.0.md): COLRv1 colour emoji, USE-lite shaper integration, true constant-memory streaming, UAX #9 X4–X5 overrides, pixel-diff visual regression, Telugu + Amharic/Sinhala/Tibetan/Khmer/Myanmar scripts, opt-in NFC normalization, CSPRNG-only crypto, configurable block limit, validatePdfUA, colour-emoji selector/BBox fixes, #48 CP-1252 fix. - [Release notes v1.2.0](https://github.com/Nizoka/pdfnative/blob/main/release-notes/v1.2.0.md): `addSignaturePlaceholder()`, ASN.1 grandchild fix (#46), page-by-page streaming, UAX #9 embeddings, USE-lite classifier. - [Learn pdfnative](https://pdfnative.dev/learn/): Eight-step guided path from installing the package to generating 100,000 pages. Each step introduces one concept. Start here if you have never generated a PDF programmatically. - [Quick Start](https://pdfnative.dev/guides/quickstart.html): Install + first PDF in Node or browser. - [Architecture](https://pdfnative.dev/guides/architecture.html): Two builders, module dependency flow, design decisions. - [PDF/A conformance](https://pdfnative.dev/guides/pdfa.html): How `tagged: true` produces veraPDF-valid PDF/A-1b/2b/2u/3b. - [Digital signatures](https://pdfnative.dev/guides/signatures.html): CMS/PKCS#7 and PAdES + `addSignaturePlaceholder()` three-line workflow; multiple signatures, signature metadata, RSA SHA-256/384/512 + ECDSA P-256. - [Long-term validation](https://pdfnative.dev/guides/ltv.html): PAdES B-B → B-LTA — RFC 3161 signature timestamps, `/DSS` + `/VRI` revocation material, document timestamps, injected `TimestampProvider`/`RevocationProvider` (no built-in networking). - [Print production](https://pdfnative.dev/guides/print.html): Bleed/trim/art/crop page boxes (`layout.print`), crop + registration marks, `/Trapped` with XMP parity, duplex/tray/copies print defaults, custom OutputIntent ICC, large-format `/UserUnit`. - [Accessibility](https://pdfnative.dev/guides/accessibility.html): Tagged PDF, /ActualText, PDF/UA structure tree. - [Onboarding](https://pdfnative.dev/guides/onboarding.html): 90-second ecosystem tour — library + CLI + MCP. - [Choosing your surface](https://pdfnative.dev/guides/choose.html): Library, CLI, MCP or React? The decision tree plus a verified capability × surface matrix, with an honest em-dash where a surface lacks a capability. - [FAQ](https://pdfnative.dev/guides/faq.html): Custom fonts, encryption, BiDi, workers, vs other libs. - [Troubleshooting](https://pdfnative.dev/guides/troubleshooting.html): Missing glyphs, RTL appearing backwards, oversized PDFs, parser errors. - [Colour-emoji CLI](https://pdfnative.dev/guides/colour-emoji-cli.html): `npx pdfnative-build-emoji-font` — generate a colour-emoji data module covering any glyph subset up to the full ~3,600-glyph Noto Color Emoji set, plus flag & ZWJ sequences via `--sequences` / `--sequence-list`; pinned download + SHA-256 verification. - [Charts](https://pdfnative.dev/guides/charts.html): Native vector `chart` blocks — 9 kinds (bar, horizontal bar, stacked bar, stacked horizontal bar, line, area, scatter, pie, donut) with secondary right axis, log and time scales, data labels, x-label collision handling. Path operators, no rasterisation; `/Figure` tagging with alt text. - [Text extraction](https://pdfnative.dev/guides/text-extraction.html): `extractText()` — reading-order Unicode via `/ToUnicode`, optional positioned runs, works on encrypted PDFs with a password. The RAG / agent-ingestion entry point. - [Form filling](https://pdfnative.dev/guides/form-filling.html): `readFormFields()` / `fillForm()` / `flattenForm()` on existing AcroForms, including encrypted PDFs via incremental update. - [PDF manipulation](https://pdfnative.dev/guides/pdf-manipulation.html): `openPdf()` (with `{ password }`), merge / split / extract pages, re-encrypt on output, and their streaming variants. - [Streaming output](https://pdfnative.dev/guides/streaming.html): `buildDocumentPDFStream` vs `buildDocumentPDFStreamTrue`, `streamToFile`, and the exact memory profile of each. - [Smart tables](https://pdfnative.dev/guides/tables.html): Multi-page tables — auto-wrap, repeated headers, zebra striping, cell borders, vertical alignment, auto-fit columns. - [Annotations](https://pdfnative.dev/guides/annotations.html): Markup annotations (highlight, underline, note, shape, freetext) applied by incremental update so signatures stay valid. - [Outlines & page labels](https://pdfnative.dev/guides/outlines.html): Document bookmarks (`outline: 'auto'` or an explicit tree) and `/PageLabels` numbering. - [Viewer preferences](https://pdfnative.dev/guides/viewer-preferences.html): `/ViewerPreferences` — page layout, page mode, and display hints. - [Colour emoji](https://pdfnative.dev/guides/colour-emoji.html): COLRv1 rendering — solid, linear and radial gradient layers as native PDF Form XObjects; flag & ZWJ sequences (51 flags + 22 ZWJ bundled) render as single ligature glyphs. - [Layout debugging](https://pdfnative.dev/guides/debugging.html): `inspectDocumentLayout()` and the `debug: true` overlay for diagnosing pagination. - [Font validation](https://pdfnative.dev/guides/font-validation.html): `validateFontData()` — check a font module before registering it. - [Self-verifying generation](https://pdfnative.dev/guides/self-verify.html): The generate → inspect → assert → correct loop — `inspectDocumentLayout()` before building, then `extractText()` / `validatePdfUA()` / `listSignatures()` against the emitted bytes; the same loop on the CLI (`inspect --check`, stable exit codes) and MCP (`inspect_pdf`). - [Agentic workflows](https://pdfnative.dev/guides/agentic-workflows.html): Patterns for driving pdfnative from AI agents on public, validated APIs. - [Use cases](https://pdfnative.dev/guides/use-cases.html): Four ecosystem architectures with diagrams — store the DocSpec instead of the PDF and render on-device, air-gapped PAdES B-LTA archiving, a CI document-regression gate with `compare`, and edge-rendered PDFs with correct HTTP caching. - [AI governance](https://pdfnative.dev/guides/ai-governance.html): The human-in-the-loop contract — agents draft, humans review, approve and submit. - [Responsibility](https://pdfnative.dev/responsibility.html): Sustainability, supply-chain and accessibility position — every claim linked to its proof, plus an explicit list of what is deliberately not claimed. - [Ecosystem manifest](https://pdfnative.dev/assets/ecosystem.json): Machine-readable versions and counts for the whole ecosystem (canonical, enforced by `npm run verify:docs`). > Every guide is pre-rendered: the HTML at `https://pdfnative.dev/guides/.html` already contains the full article, so a fetcher that does not execute JavaScript gets the whole page. The Markdown source is served at the same path with `.md` (`https://pdfnative.dev/guides/charts.md`) and is declared as a `text/markdown` alternate in each page head — the same text without the page chrome, and the cheaper fetch of the two. Both work without JavaScript. ## Agent and AI integration - [Copilot instructions](https://github.com/Nizoka/pdfnative/blob/main/.github/copilot-instructions.md): Canonical project conventions — architecture, code style, build/test, PDF-specific invariants. - [AGENTS.md](https://github.com/Nizoka/pdfnative/blob/main/AGENTS.md): Editor-agnostic agent guidance (Cursor / Aider / Claude Code / Continue). - [MCP integration](https://pdfnative.dev/guides/mcp.html): `pdfnative-mcp` v1.6.0 — use pdfnative from Claude Desktop, Cursor, Continue, Zed via 28 tools — the complete PAdES ladder B-B → B-LTA (`sign_pdf` with RFC 3161 timestamps, `add_ltv`, `timestamp_pdf`), `update_metadata`, the read-only `inspect_layout` pagination preview, all 13 block kinds in `generate_basic_pdf`, print production, charts v2, native vector `add_chart`, `read_form_fields` / `fill_form`, `encrypt_pdf` / `decrypt_pdf`, markup `annotate_pdf`, the network-free `draft_governance_issue`, and the page-tree trio `merge_pdfs` / `split_pdf` / `extract_pages`. MCP 2026-07-28 spec with legacy fallback. Built on pdfnative 1.7.0. - [CLI](https://pdfnative.dev/guides/cli.html): `pdfnative-cli` v1.4.0 — 21 commands from the terminal — render, fill, annotate, metadata, merge / split / extract, sign (RFC 3161 `--timestamp`, B-T), ltv (B-LT, air-gapped collect → embed), doc-timestamp (B-LTA), verify, encrypt, decrypt, inspect, extract-text, compare, batch (incl. declarative `--manifest` pipelines), doctor, schema, completion, govern; agent-native `--json`/`E_*`/`--dry-run` contract (12 error codes, 19 schema subjects). Built on pdfnative 1.7.0 (pins `^1.7.0`), Node ≥ 22. - [React](https://pdfnative.dev/guides/react.html): `pdfnative-react` v1.2.0 — declarative JSX components compiled on-device to pdfnative blocks; charts v2, print production, PDF/A diagnostics channel, `renderToResponse` HTTP caching, 25 lint rules, render functions, client hooks, token-frugal DocSpec. Peers: React 19 + pdfnative `^1.7.0`. ## Source - [src/](https://github.com/Nizoka/pdfnative/tree/main/src): Library source (core, crypto, fonts, parser, shaping, types, worker). - [scripts/generators/](https://github.com/Nizoka/pdfnative/tree/main/scripts/generators): 48 sample generators producing 242 reference PDFs. - [tests/](https://github.com/Nizoka/pdfnative/tree/main/tests): 2691+ tests across 123 files. 95%+ statements measured at v1.6.0; CI enforces ≥88%. ## Machine-readable artefacts - [agent-brief.md](https://pdfnative.dev/agent-brief.md): A compact briefing for AI agents writing code with pdfnative — the core API, the verified pitfalls that produce wrong code, the surface decision tree, and the self-verification loop. Designed to be pasted into a coding agent's context. - [llms-full.txt](https://pdfnative.dev/llms-full.txt): This index plus the README and the full Markdown source of every guide, in one request. - [llms-recipes.txt](https://pdfnative.dev/llms-recipes.txt): The executable recipe corpus — standalone TypeScript files importing from `pdfnative`, each executed in CI with its `@expect` assertions verified, so the code you copy is proven to compile and to produce exactly the artefact its header describes. - [api.json](https://pdfnative.dev/assets/api.json): The public API surface, derived mechanically from the export statements of `src/index.ts` — name, kind, source module, signature and TSDoc summary where extractable. The substitute for the unpublished `index.d.ts`. - [surfaces.json](https://pdfnative.dev/data/surfaces.json): The capability × surface matrix (library / CLI / MCP / React) behind the [Choosing your surface](https://pdfnative.dev/guides/choose.html) guide. - [errors.json](https://pdfnative.dev/data/errors.json): The engine's diagnostic registry — every `PDFA_` diagnostic code with its meaning and remedy, two-way verified against `src/` by the `error-parity` rule. - [llms-index.json](https://pdfnative.dev/llms-index.json): Per-page machine index — HTML and raw-Markdown URL, title, summary, section anchors, and exact byte / approximate token sizes for every artefact, so you can decide what to fetch before spending the tokens. - Every guide serves its raw Markdown at the same URL with `.md` instead of `.html`, declared via `` in each page head. All of these URLs are listed in the sitemap. ## Ecosystem - [pdfnative-cli](https://github.com/Nizoka/pdfnative-cli): CLI wrapper for pdfnative (v1.4.0, built on pdfnative 1.7.0 — pins `^1.7.0`, Node ≥ 22) — render, fill, annotate, metadata, merge, split, extract, sign, verify, ltv, doc-timestamp, encrypt, decrypt, inspect, extract-text, compare, batch, doctor, schema, completion, govern. - [pdfnative-mcp](https://github.com/Nizoka/pdfnative-mcp): Model Context Protocol server exposing pdfnative as 28 AI tools (v1.6.0, built on pdfnative 1.7.0). - [pdfnative-react](https://github.com/Nizoka/pdfnative-react): React renderer — declarative JSX components compiled on-device to pdfnative blocks (v1.2.0, React 19 + pdfnative ^1.7.0 peers). --- # pdfnative [![CI](https://github.com/Nizoka/pdfnative/actions/workflows/ci.yml/badge.svg)](https://github.com/Nizoka/pdfnative/actions/workflows/ci.yml) [![CodeQL](https://github.com/Nizoka/pdfnative/actions/workflows/codeql.yml/badge.svg)](https://github.com/Nizoka/pdfnative/actions/workflows/codeql.yml) [![npm version](https://img.shields.io/npm/v/pdfnative)](https://www.npmjs.com/package/pdfnative) [![npm downloads](https://img.shields.io/npm/dm/pdfnative)](https://www.npmjs.com/package/pdfnative) [![bundle size](https://img.shields.io/bundlephobia/minzip/pdfnative)](https://bundlephobia.com/package/pdfnative) [![zero dependencies](https://img.shields.io/badge/dependencies-0-brightgreen)](https://www.npmjs.com/package/pdfnative) [![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue)](https://www.typescriptlang.org/) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![npm provenance](https://img.shields.io/badge/provenance-signed-blueviolet)](https://docs.npmjs.com/generating-provenance-statements) [![website](https://img.shields.io/badge/pdfnative.dev-0066FF?logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiPjxyZWN0IHg9IjMiIHk9IjIiIHdpZHRoPSIxNCIgaGVpZ2h0PSIxOCIgcng9IjIiIGZpbGw9Im5vbmUiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMS41Ii8+PHBhdGggZD0iTTcgN2g2TTcgMTFoOE03IDE1aDQiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiLz48L3N2Zz4=)](https://pdfnative.dev) [![pdfnative-mcp](https://img.shields.io/npm/v/pdfnative-mcp?label=pdfnative-mcp&color=6366f1)](https://www.npmjs.com/package/pdfnative-mcp) [![pdfnative-cli](https://img.shields.io/npm/v/pdfnative-cli?label=pdfnative-cli&color=0e7490)](https://www.npmjs.com/package/pdfnative-cli) [![pdfnative-react](https://img.shields.io/npm/v/pdfnative-react?label=pdfnative-react&color=06b6d4)](https://www.npmjs.com/package/pdfnative-react) Pure native PDF generation library — zero vendor dependencies. Conforms to ISO 32000-1 (PDF 1.7). ## Ecosystem pdfnative ships as four coordinated packages — pick whichever entry point fits your workflow: | Package | Latest | Use it for | |---|:---:|---| | [`pdfnative`](https://www.npmjs.com/package/pdfnative) | **v1.7.0** | The library itself — call from Node, browsers, Workers, Deno, Bun. | | [`pdfnative-cli`](https://www.npmjs.com/package/pdfnative-cli) | **v1.4.0** | Render JSON → PDF, sign with the **complete PAdES ladder** (`sign --timestamp` B-T, `ltv` B-LT with air-gapped collect → embed, `doc-timestamp` B-LTA; RSA-SHA256/384/512 + ECDSA, native constant-time crypto by default), inspect, verify, **compare** (CI text + structure diff), signature-safe **metadata** edits, **merge / split / extract** pages, **annotate**, **govern** (AI-governance / HITL gate), declarative **batch `--manifest`** pipelines, and emit JSON Schemas from the shell. Pins pdfnative `^1.7.0`: 22 scripts + COLRv1 emoji, `--font math`, charts v2, print production, `render --strict` PDF/A gating, and an agent-native `--json`/`E_*`/`--dry-run`/`--summary` contract. Node ≥ 22. | | [`pdfnative-mcp`](https://www.npmjs.com/package/pdfnative-mcp) | **v1.6.0** | Use pdfnative from Claude Desktop, Cursor, Continue, Zed (or any MCP client, stdio or HTTP) — **28 production tools** spanning the engine's full document model: all 13 block kinds in `generate_basic_pdf`, layout options, build-time `encrypt` that keeps the AcroForm, image watermarks, print production (page boxes, bleed, marks, `/UserUnit`, OutputIntent), charts v2 (stacked / area / scatter, dual axis, log & time scales), the complete PAdES ladder B-B → B-LTA (`sign_pdf` with RFC 3161 timestamps, `add_ltv`, `timestamp_pdf`, `verify_pdf ltv: true`), `update_metadata`, the read-only `inspect_layout` pagination preview, honest PDF/A (`embedFonts` / `strict` / diagnostics), six MCP prompts, token-frugal read modes (`verbosity` / `fields`), the network-free `draft_governance_issue` (AI-governance / HITL), and the MCP **2026-07-28** spec with automatic legacy fallback. No outbound request by default — the only permitted egress is operator-configured TSA / OCSP / CRL. Pins pdfnative `^1.7.0`. | | [`pdfnative-react`](https://www.npmjs.com/package/pdfnative-react) | **v1.2.0** | Write PDFs as declarative JSX — ``, ``, ``, ``, ``, ``… compiled on-device to pdfnative blocks by a custom React 19 reconciler. Charts v2 (9 kinds, dual axes, log/time scales), print production (``), the PDF/A diagnostics channel (`layout.strict` / `onDiagnostic`), HTTP caching on `renderToResponse` (`etag` / `cacheControl`), 25 lint rules, client hooks & components (`usePdf`, `PDFViewer`, `PDFDownloadLink`), and a versioned `DocSpec` grammar (`docSpecSchema()`) for AI agents. Peer: pdfnative ^1.7.0, React ^19.0.0, Node ≥22. (A 1.6 engine would throw mid-render on the charts-v2 fields.) | ```bash npm install pdfnative # library npm install pdfnative pdfnative-react react # React renderer (pdfnative + React 19 peers) npm install -g pdfnative-cli # CLI npm install -g pdfnative-mcp # MCP server ``` Detailed docs: [CLI guide](docs/guides/cli.md) · [MCP guide](docs/guides/mcp.md) · [React guide](docs/guides/react.md) · [Onboarding cheatsheet](docs/guides/onboarding.md). ## Highlights - **Zero dependencies** — built from scratch in pure TypeScript. Zero runtime dependencies, tree-shakeable, auditable - **Conforms to ISO 32000-1** — valid xref tables, /Info metadata, proper font embedding - **22 Unicode scripts** — Thai, Japanese, Chinese (SC), Korean, Greek, Devanagari, Telugu, Turkish, Vietnamese, Polish, Arabic, Hebrew, Cyrillic, Georgian, Armenian, Bengali, Tamil, Sinhala, Tibetan, Khmer, Myanmar, Ethiopic - **Thai OpenType shaping** — GSUB substitution + GPOS mark-to-base + mark-to-mark positioning - **Arabic positional shaping** — GSUB isolated/initial/medial/final forms + lam-alef ligatures - **BiDi text layout** — Unicode Bidirectional Algorithm (UAX #9) with isolates (LRI/RLI/FSI/PDI) and explicit embeddings (LRE/RLE/LRO/RLO/PDF) including character-level X4–X5 overrides (v1.3.0). **v1.7.0** implements I1/I2 even embedding levels so digit runs (European, Arabic-Indic, Extended Arabic-Indic) keep logical order in RTL text, and full rule-L4 glyph mirroring through the complete 428-pair `BidiMirroring.txt` table - **USE-lite shaping** — `classifyUseCategory` / `classifyClusters` drive joiner classification across the Devanagari, Bengali, and Tamil shapers, fixing nukta+virama, half-form, eyelash-ra, and ya-phalaa edge cases (v1.3.0) - **Colour emoji (COLRv1)** — opt-in Noto Color Emoji subset (**expanded to 1167 glyphs in v1.6.0**, ~4.5 MB with the v1.7.0 sequence ligatures, incl. the complete Transport & Map block); solid + linear + radial gradient layers rendered as native PDF Form XObjects; monochrome fallback when not registered (v1.3.0). Variation selectors, ZWJ/ZWNJ, and skin-tone modifiers no longer leave tofu, and glyph `/BBox` is computed from contour bounds so emoji are never clipped (v1.3.0). **Advanced compositing** (v1.4.0): COLRv1 sweep (conic) gradients render as native flat-shaded wedges, and `PaintComposite` separable blend modes (Multiply, Screen, Overlay, Darken, Lighten, …) map to PDF `/BM` ExtGState; structural Porter-Duff modes fall back to monochrome. **Flag & ZWJ sequences** (v1.7.0): 51 flags + 22 ZWJ sequences (families, professions, rainbow/pirate flags, …) resolve through the source font's GSUB into single colour ligature glyphs with a longest-match pre-pass — both VS-16 spellings match, uncovered sequences degrade to the historical per-codepoint rendering, and the CLI bundles any custom set (`--sequences`, `--sequence-list`, skin tones included). [Guide →](docs/guides/colour-emoji.md) - **Multi-font fallback** — automatic cross-script font switching with continuation bias - **TTF subsetting** — only used glyphs embedded (dramatic file size reduction) - **Tagged PDF / PDF/A** — structure tree, /ActualText, XMP metadata, sRGB OutputIntent (PDF/A-1b, 2b, 2u, 3b with embedded file attachments). **Conformance guards** (v1.7.0): configurations that would break the declared PDF/A level (no embedded fonts, DeviceCMYK images) surface a diagnostic — `console.warn` by default, a custom `onDiagnostic` sink, or a thrown error under `strict: true`. [Guide →](docs/guides/pdfa.md) - **PDF Encryption (round-trip)** — **write** AES-128 (V4/R4) and AES-256 (V5/R6) encrypted PDFs (RC4 is never emitted), and **read** all of AES-128, AES-256, and legacy RC4 (V1–V4); owner + user passwords, granular permissions. **v1.6.0** adds a Standard Security Handler **decryptor** — `openPdf(bytes, { password })` decrypts transparently, the merge/split API ingests encrypted sources **and re-encrypts its output** (`MergeOptions.encrypt`, AES only, fresh keys) — closing the full *open → edit → re-secure* round trip. [Guide →](docs/guides/pdf-manipulation.md) - **Native vector charts** (v1.6.0, **charts v2 in v1.7.0**) — bar, horizontal-bar, line, pie, donut, **stacked bars, area, and scatter** `chart` blocks rendered as pure PDF path operators (zero deps, no rasterisation); multi-series, legends, "nice" axis ticks, negative values, tagged `/Figure` + alt text. v1.7.0 adds a **secondary right axis**, **log and UTC-deterministic time scales**, **per-point data labels**, and x-label collision handling (automatic stride + `labelStride` / `labelRotation`). [Guide →](docs/guides/charts.md) - **Text extraction** (v1.6.0) — `extractText()` decodes page content streams into per-page reading-order Unicode text plus optional positioned runs; `/ToUnicode` CMap, `/Encoding /Differences`, and WinAnsi/MacRoman decoding; works on encrypted documents (`{ password }`); hard `maxTextLength` memory cap for untrusted input. [Guide →](docs/guides/text-extraction.md) - **Free-form document builder** — headings, paragraphs, lists (incl. **nested / hierarchical** bullet & numbered lists, v1.4.0), tables, images, barcodes, SVG paths, form fields, spacers, page breaks, table of contents. Configurable block limit via `layout.maxBlocks` (default 100 000) for very large reports (v1.3.0) - **Smart tables** — multi-page slicing with repeated headers, auto-wrap on column overflow, zebra striping, captions, and smart auto-fit columns (v1.2.0), plus per-cell **borders** (`cellBorders`) and **vertical alignment** (`cellVAlign` / `ColumnDef.vAlign`, v1.4.0). [Guide →](docs/guides/tables.md) - **Barcode & QR code generation** — Code 128, EAN-13, QR Code, Data Matrix, PDF417 — pure PDF path operators (no images) - **SVG rendering** — path, rect, circle, ellipse, line, polyline, polygon as native PDF operators, plus `` elements rendered as upright PDF text with `x`/`y` positioning and `text-anchor` (start/middle/end) support (v1.5.0) - **AcroForm fields** — text, multiline, checkbox, radio, dropdown, listbox with appearance streams (ISO 32000-1 §12.7). **v1.6.0** adds **fill & flatten of existing forms**: `readFormFields()`, `fillForm()` (regenerates appearances), and `flattenForm()` — non-destructive incremental update that preserves prior signatures, **including on encrypted documents** (appended objects are encrypted under the document's existing scheme). [Guide →](docs/guides/form-filling.md) - **Digital signatures** — CMS/PKCS#7 detached signatures with RSA (SHA-256/384/512, v1.7.0) + ECDSA-SHA256 (P-256) and X.509 parsing (ISO 32000-1 §12.8). One-call placeholder injection via `addSignaturePlaceholder()` (v1.2.0). Pluggable **native crypto provider** (`setCryptoProvider()` / `PdfSignOptions.provider`, v1.4.0) for constant-time, hardware-backed signing (`node:crypto` / Web Crypto / HSM). **v1.7.0**: PAdES baseline profile (`profile: 'pades'` — ESS signing-certificate-v2, `ETSI.CAdES.detached`), **multiple signatures** (`allowMultiple` + `fieldName` selector), and `listSignatures()` inspection. [Guide →](docs/guides/signatures.md) - **Print production** (v1.7.0) — bleed/trim/art/crop **page boxes** (`layout.print`, with a one-line `bleed` shorthand), **crop & registration marks** drawn as pure vector operators outside the TrimBox, `/Trapped` metadata with XMP parity, print-dialog defaults (**duplex**, tray pick, page range, copies), caller-supplied **OutputIntent ICC profile** (tagged mode), and large-format `/UserUnit` (banners, plans). Boxes survive `mergePdfs`/`splitPdf`. Byte-identical output when unused. [Guide →](docs/guides/print.md) - **Long-term validation (LTV, PAdES B-B → B-LTA)** (v1.7.0) — RFC 3161 **signature timestamps** (`signPdfBytesWithTimestamp()`), embedded revocation material in `/DSS` + per-signature `/VRI` (`addValidationInfo()` — OCSP RFC 6960 + CRL RFC 5280), and **document timestamps** (`addDocumentTimestamp()`). Network transport is injected (`TimestampProvider` / `RevocationProvider`) — the engine stays offline and zero-dependency; rejected or tampered TSA tokens are never embedded. [Guide →](docs/guides/ltv.md) - **Streaming output** — AsyncGenerator-based progressive PDF emission with configurable chunk size, object-boundary page-by-page streaming, and **true constant-memory streaming** (`buildDocumentPDFStreamTrue()`, v1.3.0) where the full PDF binary never materialises. One-call `streamToFile()` drains any stream to disk with back-pressure and `AbortSignal` support (v1.4.0). [Guide →](docs/guides/streaming.md) - **Document outline & page labels** — nested bookmarks (`/Outlines` tree, with bold/italic/colour, collapsible nodes via `open: false`, explicit or `outline: 'auto'` from headings) and logical page numbering (`/PageLabels`: decimal, roman, alpha, prefixes, custom start) (v1.4.0). [Guide →](docs/guides/outlines.md) - **Viewer preferences** — `PdfLayoutOptions.viewerPreferences` controls initial `/PageLayout` & `/PageMode` plus the `/ViewerPreferences` dict (hide toolbar/menubar, fit/center window, display doc title, non-full-screen mode, reading direction, print scaling) — PDF/A-safe (v1.4.0). **v1.7.0** adds the print-dialog defaults: `duplex`, `pickTrayByPDFSize`, `printPageRange`, `numCopies`. [Guide →](docs/guides/viewer-preferences.md) - **Font-data validator** — opt-in `validateFontData()` structurally checks custom font modules (SFNT magic, base64 integrity, cmap coverage, glyph-id range, width array, finite metrics) and returns `{ valid, errors, warnings }` (v1.4.0). [Guide →](docs/guides/font-validation.md) - **PDF parser & modifier** — read existing PDFs (tokenizer, xref, object parser, FlateDecode inflate) + incremental modification. Read-only PDF/UA structural checker `validatePdfUA()` (ISO 14289-1: MarkInfo, StructTree, ParentTree, Lang, per-page MCID uniqueness) (v1.3.0). **Page-tree manipulation** (v1.4.0): `mergePdfs()`, `splitPdf()`, `extractPages()` rebuild a clean object graph (inherited attributes resolved, annotations/signatures optionally dropped, deterministic trailer `/ID`, bounded-depth copy, 256 MiB output cap via `maxOutputSize`). **Round-trip readers** (v1.5.0): `getPageLabels()` parses `/PageLabels` back into a typed `PageLabelRange[]`; `getAnnotations()` / `getPageRef()` read page annotations, and `PdfModifier.addAnnotation()` injects new ones incrementally. **v1.6.0**: a Standard Security Handler **decryptor** (`openPdf(bytes, { password })`, RC4/AES-128/AES-256) lets the reader and page-tree API ingest encrypted sources, and **constant-memory streaming** variants `streamMergedPdfs()` / `streamSplitPdf()` / `streamExtractPages()` emit merges/splits in fixed-size chunks (byte-identical to the buffered functions). [Guide →](docs/guides/pdf-manipulation.md) - **Markup annotations** — typed annotation model (text, highlight, underline, strikeout, squiggly, square, circle, line, freetext) via `buildAnnotation()` / `buildAnnotationBody()`, plus `PdfReader.getAnnotations()` and `PdfModifier.addAnnotation()` for round-trip read/write (v1.5.0); **v1.6.0** lets `addAnnotation()` operate on encrypted documents (RC4/AES sources, annotations stored encrypted). [Guide →](docs/guides/annotations.md) - **Layout debug & inspection** — opt-in `layout: { debug: true }` overlays margin / content / cell boxes for visual layout debugging; `inspectDocumentLayout()` returns a programmatic per-page block-geometry report. Byte-identical when debug is off (v1.5.0). [Guide →](docs/guides/debugging.md) - **Math & technical symbols** — bundleable math font under lang `'math'`; mathematical operators, Greek, arrows, and technical symbols route automatically via script detection (v1.5.0) - **Font-data tooling** — `pdfnative/tools` exposes `compileFontData()` / `parseFontData()` to build and introspect font-data modules programmatically (v1.5.0) - **Image embedding** — JPEG (DCTDecode) and PNG (FlateDecode) with auto-scaling and alignment - **Hyperlinks** — PDF link annotations (/URI) with URL validation, blue underlined text, tagged /Link - **Header/footer templates** — configurable `PageTemplate` with left/center/right zones and `{page}`/`{pages}`/`{date}`/`{title}` placeholders - **Watermarks** — text and image overlays with configurable opacity, rotation, and position (background/foreground) - **Table of contents** — auto-generated TOC with internal /GoTo links, dot leaders, and page numbers - **FlateDecode compression** — zlib stream compression (50–90% size reduction), zero-dependency, platform-native - **Web Worker support** — off-main-thread generation for large datasets - **Tree-shakeable** — ESM + CJS dual build with TypeScript declarations - **Heavily tested** — 2691+ tests across 123 files, fuzz suite, dual-mode visual-regression suite, performance benchmarks; 95.41% statement coverage measured at the v1.6.0 release, with CI enforcing ≥88% statements / 80% branches / 85% functions / 90% lines (vitest.config.ts) - **NPM provenance** — signed builds via GitHub Actions OIDC - **On-device generation** — runs in Node, browsers, Workers, Deno, Bun. No SaaS round-trip; documents never leave the calling process unless your application explicitly sends them - **No telemetry, no network calls** — verifiable in source. The library never opens a socket, fetches remote fonts, or phones home - **AI client integration** — use pdfnative from Claude Desktop, Cursor, Continue, and Zed via [`pdfnative-mcp`](https://github.com/Nizoka/pdfnative-mcp) — **28 production tools** (generate, tables, barcodes, forms, sign with the full PAdES ladder, verify, validate, attachments, extraction, inspect, metadata, layout preview, plus page-tree `merge_pdfs` / `split_pdf` / `extract_pages`) - **Command-line interface** — render, sign, verify, inspect, and batch-render PDFs from the shell with [`pdfnative-cli`](https://github.com/Nizoka/pdfnative-cli) — zero-config, scriptable, agent-native (`--json`/`E_*`/`--dry-run`), ideal for CI/CD pipelines - **React renderer** — author PDFs as declarative JSX with [`pdfnative-react`](https://github.com/Nizoka/pdfnative-react): ``/`
`/`` components, `usePdf`/`PDFViewer` client hooks, on-device rendering with no DOM or headless browser ## Installation ```bash npm install pdfnative ``` **Requirements:** Node.js >= 22 | Modern browsers | Deno | Bun ## Documentation - 🌐 **Website:** [pdfnative.dev](https://pdfnative.dev) — landing page, live in-browser demo with 12 examples, comparisons, benchmarks. - 📘 **Quick Start:** [docs/guides/quickstart.md](docs/guides/quickstart.md) — Node.js, browser, Web Worker, streaming. - 🏛️ **Architecture:** [docs/guides/architecture.md](docs/guides/architecture.md) — modules, builders, generation pipeline. - ♿ **Accessibility:** [docs/guides/accessibility.md](docs/guides/accessibility.md) — tagged PDF, PDF/UA, PDF/A. - ❓ **FAQ:** [docs/guides/faq.md](docs/guides/faq.md) — fonts, encryption, signatures, comparisons. - 🤖 **Agentic workflows:** [docs/guides/agentic-workflows.md](docs/guides/agentic-workflows.md) — extend the engine at runtime (register fonts without a release) and embed agent-generated images. - 🛠️ **Troubleshooting:** [docs/guides/troubleshooting.md](docs/guides/troubleshooting.md) — common pitfalls. - 🎮 **Playgrounds:** ten interactive demos at [docs/playgrounds/](docs/playgrounds/) — [extreme-scripts](docs/playgrounds/extreme-scripts.html) (live BiDi/Indic stress tests), [all-scripts](docs/playgrounds/all-scripts.html) (every Unicode script), [scale](docs/playgrounds/scale.html) (1k-100k pages, Web Worker + true streaming), [authoring-plus](docs/playgrounds/authoring-plus.html) (SVG text, layout overlay, annotations), [toolkit](docs/playgrounds/toolkit.html) (bookmarks, page labels, viewer prefs, merge/split/extract, and v1.6.0 form fill/flatten), [charts](docs/playgrounds/charts.html) (native vector charts — all 9 v1.7.0 types), [inspect](docs/playgrounds/inspect.html) (drop any PDF and read a full report, entirely client-side), plus [cli](docs/playgrounds/cli.html), [mcp](docs/playgrounds/mcp.html) and [react](docs/playgrounds/react.html) ecosystem explorers. - 🧪 **Sample PDFs:** [scripts/generators/](scripts/generators/) — 242 sample PDFs across 37 categories (48 generators) (see [Sample PDFs](#sample-pdfs) below). - 🎓 **Learn:** [docs/learn/](docs/learn/) — an eight-step guided path from installing the package to generating 100,000 pages, live at [pdfnative.dev/learn/](https://pdfnative.dev/learn/). - 🤖 **Machine-readable:** [llms.txt](llms.txt) (doc index for LLMs), [AGENTS.md](AGENTS.md) (agent guidance), and [docs/assets/ecosystem.json](docs/assets/ecosystem.json) — the canonical manifest of ecosystem versions and counts, enforced by `npm run verify:docs`. ## Why pdfnative? pdfnative was designed for teams that need **ISO-compliant, production-grade PDF generation** with zero supply-chain risk. Here is how it compares to other popular JavaScript PDF libraries: | Feature | pdfnative | jsPDF | pdfkit | pdf-lib | pdfmake | |---------|:---------:|:-----:|:------:|:-------:|:------:| | Runtime dependencies | **0** | 3 | 6 | 4 | 3 | | TypeScript declarations | Built-in | Built-in | @types/* | Built-in | @types/* | | PDF/A (ISO 19005) | 1b, 2b, 2u, 3b | — | — | — | — | | Tagged PDF / PDF/UA | ✅ | — | ✅ | — | — | | Encryption (read + write) | AES-128/256 + RC4 read | write (RC4) | write | — | write | | Complex text shaping (GSUB/GPOS) | ✅ Thai, Arabic, Devanagari, Bengali, Tamil | — | Via fontkit | Via @pdf-lib/fontkit | Via pdfkit | | BiDi (RTL) layout | ✅ | — | — | — | — | | Modify existing PDFs | ✅ (incremental) | — | — | ✅ | — | | Forms (create + fill + flatten) | ✅ all three | create | create | create + fill | — | | Native charts (vector) | ✅ 9 kinds incl. stacked/area/scatter | — | — | — | — | | Digital signatures | ✅ (RSA + ECDSA, PAdES) | — | — | — | — | | LTV / timestamps (PAdES B-LTA) | ✅ RFC 3161 + /DSS | — | — | — | — | | Print production (bleed/trim boxes, marks) | ✅ | — | — | — | — | | Barcode / QR code (native) | ✅ 5 formats | — | — | — | QR | | SVG path rendering | ✅ | Plugin | ✅ | Paths only | ✅ | | Streaming output | ✅ | — | ✅ | — | ✅ | | PDF parser | ✅ | — | — | ✅ | — | | Tree-shakeable (ESM) | ✅ | — | — | ✅ | — | | NPM provenance (SLSA) | ✅ | — | — | — | ✅ | > **Data sources:** npm registry metadata and official README/documentation for each library, compared on **2026-07-28** (pdfkit 0.19.1, jsPDF 4.2.1, pdfmake 0.3.11, pdf-lib 1.17.1 — see [docs/data/comparison-2026-07-28.json](docs/data/comparison-2026-07-28.json)). Dependency counts reflect direct `dependencies` listed in each package's published manifest. "—" means the feature is not supported or not documented. Feature claims about third-party libraries are based on their public documentation and may not reflect the latest version — please verify against current releases. Sample PDFs validate with veraPDF (PDF/A) and Adobe Acrobat. **When to choose another library:** You need advanced vector graphics (complex gradients, arbitrary transforms), rich interactive form scripting (JavaScript actions), or mature ecosystem integrations with existing toolchains. **When to choose pdfnative:** You need zero-dependency PDF generation with ISO archival compliance (PDF/A), accessibility (tagged PDF), AES encryption, digital signatures, multi-script Unicode support — particularly Arabic/Hebrew BiDi and Thai GSUB/GPOS shaping — form fields, barcode generation, SVG rendering, or the ability to parse and incrementally modify existing PDFs. ## Quick Start ```typescript import { buildPDFBytes, downloadBlob } from 'pdfnative'; const pdf = buildPDFBytes({ title: 'Monthly Report', infoItems: [ { label: 'Period', value: 'January 2026' }, { label: 'Account', value: 'Main Account' }, ], balanceText: 'Balance: $1,234.56', countText: '42 transactions', headers: ['Date', 'Description', 'Category', 'Amount', 'Status'], rows: [ { cells: ['01/15', 'Grocery Store', 'Food', '-$45.00', ''], type: 'debit', pointed: false }, { cells: ['01/16', 'Salary', 'Income', '+$3,000.00', 'X'], type: 'credit', pointed: true }, ], footerText: 'Generated by MyApp', }); // Browser: trigger download downloadBlob(pdf, 'report.pdf'); // Node.js: write to file import { writeFileSync } from 'fs'; writeFileSync('report.pdf', pdf); ``` ### Document Builder Build free-form documents with headings, paragraphs, lists, tables, images, barcodes, and more: ```typescript import { buildDocumentPDFBytes } from 'pdfnative'; const pdf = buildDocumentPDFBytes({ title: 'Project Report', blocks: [ { type: 'toc' }, { type: 'heading', text: 'Executive Summary', level: 1 }, { type: 'paragraph', text: 'This quarter saw strong growth across all divisions...' }, { type: 'image', data: jpegBytes, width: 400, align: 'center', alt: 'Revenue chart' }, { type: 'list', items: ['Revenue up 15%', 'Costs down 8%', 'Net profit +23%'], style: 'bullet' }, { type: 'table', headers: ['Q1', 'Q2', 'Q3', 'Q4'], rows: [ { cells: ['$1.2M', '$1.4M', '$1.6M', '$1.8M'], type: 'credit', pointed: false }, ]}, { type: 'spacer', height: 20 }, { type: 'heading', text: 'Next Steps', level: 2 }, { type: 'paragraph', text: 'Focus areas for next quarter include...', align: 'left' }, { type: 'link', text: 'View full report online', url: 'https://example.com/report' }, { type: 'barcode', format: 'qr', data: 'https://example.com/report', align: 'center' }, ], footerText: 'Confidential', }, { headerTemplate: { center: 'Project Report', right: '{date}' }, footerTemplate: { left: 'Confidential', right: 'Page {page} of {pages}' }, }); ``` ## Unicode Font Support For non-Latin scripts, register font data loaders (lazy-loaded on demand): ```typescript import { registerFonts, loadFontData, buildPDFBytes } from 'pdfnative'; registerFonts({ th: () => import('pdfnative/fonts/noto-thai-data.js'), ja: () => import('pdfnative/fonts/noto-jp-data.js'), zh: () => import('pdfnative/fonts/noto-sc-data.js'), ko: () => import('pdfnative/fonts/noto-kr-data.js'), el: () => import('pdfnative/fonts/noto-greek-data.js'), hi: () => import('pdfnative/fonts/noto-devanagari-data.js'), tr: () => import('pdfnative/fonts/noto-turkish-data.js'), vi: () => import('pdfnative/fonts/noto-vietnamese-data.js'), pl: () => import('pdfnative/fonts/noto-polish-data.js'), ar: () => import('pdfnative/fonts/noto-arabic-data.js'), he: () => import('pdfnative/fonts/noto-hebrew-data.js'), ru: () => import('pdfnative/fonts/noto-cyrillic-data.js'), ka: () => import('pdfnative/fonts/noto-georgian-data.js'), hy: () => import('pdfnative/fonts/noto-armenian-data.js'), bn: () => import('pdfnative/fonts/noto-bengali-data.js'), ta: () => import('pdfnative/fonts/noto-tamil-data.js'), te: () => import('pdfnative/fonts/noto-telugu-data.js'), // v1.3.0 si: () => import('pdfnative/fonts/noto-sinhala-data.js'), // v1.3.0 bo: () => import('pdfnative/fonts/noto-tibetan-data.js'), // v1.3.0 km: () => import('pdfnative/fonts/noto-khmer-data.js'), // v1.3.0 my: () => import('pdfnative/fonts/noto-myanmar-data.js'), // v1.3.0 am: () => import('pdfnative/fonts/noto-ethiopic-data.js'), // v1.3.0 // v1.1.0+ — optional Latin fallback for PDF/A documents with curly quotes, // em-dash, ellipsis, etc. (activates automatically when needed): latin: () => import('pdfnative/fonts/noto-sans-data.js'), // v1.1.0+ — optional monochrome emoji: emoji: () => import('pdfnative/fonts/noto-emoji-data.js'), }); const thaiFont = await loadFontData('th'); const pdf = buildPDFBytes({ title: 'รายงานประจำเดือน', // ... other params fontEntries: thaiFont ? [{ fontData: thaiFont, fontRef: '/F3', lang: 'th' }] : [], }); ``` ### Supported Languages | Language | Code | Font | Script | |----------|------|------|--------| | Thai | `th` | Noto Sans Thai | GSUB + GPOS shaping | | Japanese | `ja` | Noto Sans JP | CJK ideographs + kana | | Chinese (Simplified) | `zh` | Noto Sans SC | CJK ideographs | | Korean | `ko` | Noto Sans KR | Hangul syllables | | Greek | `el` | Noto Sans Greek | Greek alphabet | | Hindi (Devanagari) | `hi` | Noto Sans Devanagari | GSUB conjuncts + GPOS marks | | Turkish | `tr` | Noto Sans Turkish | Latin extended (İ/ı) | | Vietnamese | `vi` | Noto Sans Vietnamese | Latin + combining marks | | Polish | `pl` | Noto Sans Polish | Latin extended (Ł/ł) | | Arabic | `ar` | Noto Sans Arabic | GSUB positional shaping | | Hebrew | `he` | Noto Sans Hebrew | Right-to-left script | | Russian (Cyrillic) | `ru` | Noto Sans | Cyrillic alphabet | | Georgian | `ka` | Noto Sans Georgian | Mkhedruli script | | Armenian | `hy` | Noto Sans Armenian | Armenian alphabet | | Bengali | `bn` | Noto Sans Bengali | GSUB conjuncts + GPOS marks | | Tamil | `ta` | Noto Sans Tamil | GSUB ligatures + split vowels | | Latin (PDF/A) | `latin` | Noto Sans VF | WinAnsi-extended Latin (curly quotes, em-dash, ellipsis…) | | Emoji | `emoji` | Noto Emoji | Monochrome emoji (BMP/SMP, Fitzpatrick, ZWJ, VS-15/16) | ## Multi-Font (Mixed Scripts) Generate PDFs with multiple scripts in the same document: ```typescript const fonts = await Promise.all([ loadFontData('th'), loadFontData('ja'), loadFontData('zh'), ]); const fontEntries = fonts .filter(Boolean) .map((fd, i) => ({ fontData: fd!, fontRef: `/F${3 + i}`, lang: ['th', 'ja', 'zh'][i] })); const pdf = buildPDFBytes({ title: 'Multi-Language Report', headers: ['Date', 'Description', 'Category', 'Amount', 'Status'], rows: [ { cells: ['01/01', 'English text', 'Test', '+100', 'OK'], type: 'credit', pointed: false }, { cells: ['01/02', 'ข้อความไทย', 'ทดสอบ', '-50', ''], type: 'debit', pointed: false }, { cells: ['01/03', '日本語テキスト', 'テスト', '+200', '済'], type: 'credit', pointed: true }, ], // ... other params fontEntries, }); ``` ## Web Worker (Large Datasets) ```typescript import { createPDF } from 'pdfnative'; const pdf = await createPDF(params, { workerUrl: new URL('pdfnative/worker', import.meta.url), threshold: 500, // use Worker above 500 rows timeout: 30000, // Worker timeout in ms (default: 60000) onProgress: (percent) => console.log(`${percent}%`), }); ``` For lower-level control, use `generatePDFInWorker` directly with `WorkerGenerationOptions`: ```typescript import { generatePDFInWorker } from 'pdfnative'; import type { WorkerGenerationOptions } from 'pdfnative'; const options: WorkerGenerationOptions = { timeout: 15000, onProgress: (percent) => console.log(`${percent}%`), }; const pdf = await generatePDFInWorker(workerUrl, params, options); ``` ## Layout Customization ```typescript const pdf = buildPDFBytes(params, { pageWidth: 595.28, // A4 (default) pageHeight: 841.89, // A4 (default) margins: { t: 45, r: 36, b: 35, l: 36 }, colors: { title: '#2563EB', // hex — primary format credit: [15, 145, 121], // RGB tuple [0–255] debit: '0.863 0.149 0.149', // PDF operator string [0.0–1.0] // ... see PdfColors type }, columns: [ { f: 0.15, a: 'l', mx: 12, mxH: 12 }, { f: 0.35, a: 'l', mx: 50, mxH: 50 }, { f: 0.20, a: 'r', mx: 20, mxH: 20 }, { f: 0.30, a: 'r', mx: 30, mxH: 30 }, ], }); ``` ### Color Formats All color values accept three formats: | Format | Example | Description | |--------|---------|-------------| | Hex string | `'#2563EB'` or `'#26E'` | Primary format — `#RRGGBB` or `#RGB` | | RGB tuple | `[37, 99, 235]` | Array with values 0–255 | | PDF operator | `'0.145 0.388 0.922'` | Raw PDF RGB string (0.0–1.0) | ```typescript import { parseColor } from 'pdfnative'; parseColor('#2563EB'); // '0.145 0.388 0.922' parseColor([37, 99, 235]); // '0.145 0.388 0.922' parseColor('0.145 0.388 0.922'); // '0.145 0.388 0.922' ``` All inputs are validated and normalized before interpolation into PDF content streams, preventing operator injection. ### Font Sizes Customize font sizes for each zone (title, info bar, table header, table cells, footer): ```typescript const pdf = buildPDFBytes(params, { fontSizes: { title: 20, // Title text (default: 16) info: 10, // Info bar items (default: 9) th: 9, // Table header cells (default: 8) td: 8, // Table body cells (default: 7.5) ft: 8, // Footer text (default: 7) }, }); ``` | Zone | Key | Default | Description | |------|-----|---------|-------------| | Title | `title` | 16 | PDF title text | | Info bar | `info` | 9 | Key-value pairs below title | | Table header | `th` | 8 | Column header row | | Table cells | `td` | 7.5 | Data row cells | | Footer | `ft` | 7 | Page footer text | All values are in PDF points (1pt = 1/72 inch). Partial overrides are supported — unspecified keys use defaults. ## Building Custom Font Data ### Obtaining TTF Files For Noto Sans fonts, download the raw `.ttf` file directly from the [noto-fonts GitHub repository](https://github.com/notofonts): 1. Navigate to the font's GitHub repository (e.g., `github.com/notofonts/bengali`) 2. Find the TTF file under `fonts/NotoSansBengali/unhinted/ttf/` (or similar path) 3. Click the file, then click **"Download raw file"** (or use the raw URL) 4. Save it to `fonts/ttf/` No zip download or extraction needed — each TTF is a standalone file you can download directly. ### Building the Data Module Convert any TTF font into an importable data module: ```bash npx pdfnative-build-font fonts/ttf/MyFont.ttf fonts/my-font-data.js ``` The tool extracts cmap, widths, metrics, GSUB, GPOS, and embeds the raw TTF as base64. ### Full colour-emoji coverage (`pdfnative-build-emoji-font`) The bundled colour-emoji module (`pdfnative/fonts/noto-color-emoji-data.js`) ships a lean curated subset to keep the package small. When you need glyphs beyond that subset — up to the **full ~3,600-glyph** Noto Color Emoji set — a second bundled binary generates a custom data module on demand, so even **pdfnative-only** users get full coverage without the package ever carrying the ~32 MB source font: ```bash # Download the pinned Noto Color Emoji (SHA-256 verified) and emit every glyph npx pdfnative-build-emoji-font --download --all --out my-color-emoji-data.js # …or build from a local TTF, selecting only the glyphs you need npx pdfnative-build-emoji-font --ttf NotoColorEmoji-Regular.ttf \ --codepoints "1F600,1F680,2764" --out my-color-emoji-data.js ``` Select glyphs with `--all`, `--preset`, `--codepoints`, or `--ranges`, then register the generated module under lang `'emoji'`. See the [Colour-emoji CLI guide](docs/guides/colour-emoji-cli.md). ## Agentic workflows pdfnative is shaped so an AI agent can do more than *call* the engine — it can **extend** it at runtime and **feed it content it generated itself**, without waiting for a library release. Both patterns use already-shipped, public APIs. **1. Extend the engine at runtime — no release required.** The font registry is a runtime API. An agent can compile a TTF/OTF in memory and register it on the spot, so a document renders the moment it needs a new script, symbol set, or brand font: ```js import { registerFont, loadFontData, buildDocumentPDFBytes } from 'pdfnative'; registerFont('th', () => import('pdfnative/fonts/noto-thai-data.js')); const th = await loadFontData('th'); if (!th) throw new Error('Thai font failed to load'); const bytes = buildDocumentPDFBytes({ title: 'Thai demo', blocks: [{ type: 'paragraph', text: 'สวัสดีชาวโลก' }], fontEntries: [{ fontData: th, fontRef: '/F3', lang: 'th' }], // /F1 and /F2 are reserved }); ``` This is how the bundled **Noto Sans Math** font existed as a *working runtime pattern* before it shipped as a default in v1.5.0. Use `compileFontData()` to emit a reusable `*-data.js` module (byte-identical to `npx pdfnative-build-font`). **2. Embed agent-generated images.** Image-generating agents (e.g. Antigravity, ChatGPT, and other multimodal assistants) can pipe a generated PNG/JPEG straight into a document — via the `image` block (library / CLI) or the `embed_image` MCP tool. pdfnative parses and embeds it natively (no rasterization) and validates it at the boundary. Runtime extensibility is **not** autonomous modification of the published package: the agent extends its own in-process instance; the repository is only ever changed by a human under the [AI-governance / human-in-the-loop contract](docs/guides/ai-governance.md). See the [Agentic workflows guide](docs/guides/agentic-workflows.md) for the full walkthrough. ## Visual PDF Inspection Generate sample PDFs for all supported languages to visually verify output: ```bash npm run test:generate ``` This creates **242 sample PDFs** in `test-output/` (git-ignored), organized in 37 categories produced by 48 generators (including `charts/` native vector charts, `bidi/` Persian and mirroring showcases, `signatures/` LTV pipelines, and `print/` prepress output added in v1.7.0). See [scripts/README.md](scripts/README.md) for the modular generator architecture. ### Financial Statements (per language) | File | Content | |------|---------| | `sample-latin.pdf` | English / Helvetica | | `sample-th.pdf` | Thai with GSUB + GPOS shaping | | `sample-ja.pdf` | Japanese (CJK ideographs) | | `sample-zh.pdf` | Chinese Simplified | | `sample-ko.pdf` | Korean (Hangul) | | `sample-el.pdf` | Greek | | `sample-hi.pdf` | Hindi (Devanagari) | | `sample-tr.pdf` | Turkish (İ/ı special casing) | | `sample-vi.pdf` | Vietnamese (combining marks) | | `sample-pl.pdf` | Polish (Ł/ł) | | `sample-ar.pdf` | Arabic (RTL, positional shaping) | | `sample-he.pdf` | Hebrew (RTL) | | `sample-ru.pdf` | Russian (Cyrillic) | | `sample-ka.pdf` | Georgian (Mkhedruli) | | `sample-hy.pdf` | Armenian | | `sample-bn.pdf` | Bengali (GSUB conjuncts + GPOS marks) | | `sample-ta.pdf` | Tamil (GSUB + split vowel decomposition) | | `sample-multi.pdf` | Mixed: all 22 scripts in one PDF | | `sample-pagination.pdf` | 200 rows, multi-page layout | ### Diverse Use Cases (non-financial) | File | Content | |------|---------| | `diverse-student-transcript.pdf` | University academic transcript (Latin) | | `diverse-recipe-th.pdf` | Thai recipe — Tom Yum Goong ingredients (Thai) | | `diverse-server-ja.pdf` | Server monitoring dashboard (Japanese) | | `diverse-inventory-zh.pdf` | Warehouse product inventory (Chinese) | | `diverse-sports-ko.pdf` | K-League football standings (Korean) | | `diverse-library-el.pdf` | Classical Greek library catalog (Greek) | | `diverse-medical-hi.pdf` | Blood test lab results (Hindi) | | `diverse-menu-tr.pdf` | Turkish restaurant dinner menu (Turkish) | | `diverse-weather-vi.pdf` | Weekly weather forecast — Hanoi (Vietnamese) | | `diverse-train-pl.pdf` | Train schedule — Warsaw (Polish) | | `diverse-marketplace-ar.pdf` | Gold marketplace catalog — Dubai (Arabic) | | `diverse-museum-he.pdf` | Museum exhibition catalog — Jerusalem (Hebrew) | ### Alphabet / Character Coverage | File | Content | |------|---------| | `alphabet-thai.pdf` | 44 consonants, vowels, tone marks, digits | | `alphabet-japanese.pdf` | Hiragana, Katakana, Kanji numerals & common | | `alphabet-chinese.pdf` | 121 characters by category (HSK frequency) | | `alphabet-korean.pdf` | Hangul jamo, syllables, complex clusters | | `alphabet-greek.pdf` | Full uppercase/lowercase, accented, archaic | | `alphabet-devanagari.pdf` | Vowels, consonants, matras, conjuncts, digits | | `alphabet-turkish.pdf` | 29 letters, İ/ı dotted-I distinction test | | `alphabet-vietnamese.pdf` | 7 base vowels × 6 tones, all diacritics | | `alphabet-polish.pdf` | 32 letters, digraphs, pangram | | `alphabet-arabic.pdf` | 28 letters, harakat, numerals, ligatures | | `alphabet-hebrew.pdf` | 22 letters, final forms, vowel points | | `alphabet-cyrillic.pdf` | 33 Russian letters, Ukrainian/Serbian extended | | `alphabet-georgian.pdf` | 33 Mkhedruli letters, Asomtavruli | | `alphabet-armenian.pdf` | 38 letters, ligatures | | `alphabet-bengali.pdf` | Vowels, consonants, conjuncts, digits | | `alphabet-tamil.pdf` | Vowels, consonants, compound characters, digits | ### PDF/A Conformance Variants | File | Content | |------|---------| | `tagged-pdfa2b-default.pdf` | PDF/A-2b (tagged=true, default) | | `tagged-pdfa2b-explicit.pdf` | PDF/A-2b (tagged='pdfa2b', explicit) | | `tagged-pdfa1b.pdf` | PDF/A-1b (tagged='pdfa1b', legacy) | | `tagged-pdfa2u.pdf` | PDF/A-2u (tagged='pdfa2u', Unicode) | | `tagged-pdfa3b.pdf` | PDF/A-3b (tagged='pdfa3b', embedded file attachments) | ### Encrypted PDFs | File | Content | |------|---------| | `encrypted-aes128.pdf` | AES-128 (V4/R4) owner-only | | `encrypted-aes256.pdf` | AES-256 (V5/R6) owner-only | | `encrypted-aes128-user.pdf` | AES-128 with user+owner passwords | | `encrypted-aes256-user.pdf` | AES-256 with user+owner passwords | | `encrypted-readonly.pdf` | AES-128 read-only (no copy/modify) | | `encrypted-noprint.pdf` | AES-128 fully restricted | **Sample passwords** (for testing only — all documented in `scripts/generate-samples.ts`): | File | Owner Password | User Password | |------|---------------|---------------| | `encrypted-aes128.pdf` | `owner123` | _(none — opens freely)_ | | `encrypted-aes256.pdf` | `owner256` | _(none — opens freely)_ | | `encrypted-aes128-user.pdf` | `owner123` | `user456` | | `encrypted-aes256-user.pdf` | `owner256` | `user789` | | `encrypted-readonly.pdf` | `owner-ro` | _(none — opens freely)_ | | `encrypted-noprint.pdf` | `owner-np` | _(none — opens freely)_ | | `doc-encrypted-aes128.pdf` | `docowner` | `docuser` | | `doc-encrypted-aes256.pdf` | `strongowner256` | _(none — opens freely)_ | ### Document Builder Samples | File | Content | |------|---------| | `doc-headings-paragraphs.pdf` | H1/H2/H3 + paragraphs with text wrapping | | `doc-lists.pdf` | Bullet + numbered lists | | `doc-links.pdf` | External hyperlink annotations | | `doc-table.pdf` | Embedded table in document | | `doc-spacer-pagebreak.pdf` | Spacers + forced page breaks (3 pages) | | `doc-encrypted-aes128.pdf` | Document builder + AES-128 encryption | | `doc-encrypted-aes256.pdf` | Document builder + AES-256 encryption | | `doc-image.pdf` | Image embedding (JPEG, centered) | | `doc-custom-colors.pdf` | Color formats (hex, tuple, PDF operator) | | `doc-japanese.pdf` | Japanese Unicode document (headings, lists, table) | | `doc-arabic.pdf` | Arabic RTL document (headings, lists, table, BiDi) | | `doc-hebrew.pdf` | Hebrew RTL document (headings, lists, table, BiDi) | | `doc-thai.pdf` | Thai user manual (GSUB+GPOS shaping, pricing table) | | `doc-bengali.pdf` | Bengali document (GSUB conjuncts + GPOS marks) | | `doc-tamil.pdf` | Tamil document (GSUB substitution + split vowels) | | `doc-devanagari.pdf` | Hindi (Devanagari) document — GSUB conjuncts, reph reordering, matra reordering, split vowels | | `doc-telugu.pdf` | Telugu document (virama conjuncts + GPOS marks, no reph) | | `doc-sinhala.pdf` | Sinhala document (virama conjuncts + pre-base kombuva reordering) | | `doc-tibetan.pdf` | Tibetan document (vertical subjoined-consonant stacking) | | `doc-khmer.pdf` | Khmer document (USE-lite: coeng subscripts, pre-base vowels) | | `doc-myanmar.pdf` | Myanmar document (USE-lite: medials, pre-base reordering) | | `doc-amharic.pdf` | Amharic/Ethiopic document (syllabic abugida, no reordering) | | `doc-chinese-catalog.pdf` | Chinese product catalog (tables, ordering info) | | `doc-multi-language.pdf` | Multi-language showcase: all 22 Unicode scripts in one PDF | | `doc-invoice.pdf` | Invoice template (line items, totals, payment link) | | `doc-report-multipage.pdf` | 3-page technical report (7 sections, 4 tables) | | `doc-contract-bilingual.pdf` | Bilingual EN/AR contract (legal sections, signatures) | | `doc-showcase-all-blocks.pdf` | All 13 block types in one PDF | ### Compressed PDFs (FlateDecode) | File | Content | |------|---------| | `compressed-latin-100rows.pdf` | 100-row Latin table (87% smaller) | | `uncompressed-latin-100rows.pdf` | Same 100-row table without compression (baseline) | | `compressed-japanese.pdf` | Japanese CIDFont + TTF subset (62% smaller) | | `compressed-arabic.pdf` | Arabic RTL + GSUB shaping (compressed) | | `compressed-thai.pdf` | Thai GSUB+GPOS shaping (compressed) | | `compressed-tagged-pdfa2b.pdf` | FlateDecode + Tagged PDF/A-2b (XMP uncompressed) | | `compressed-encrypted-aes128.pdf` | FlateDecode + AES-128 encryption | | `doc-compressed.pdf` | Document builder with FlateDecode | ### Stress Test PDFs | File | Content | |------|---------| | `stress-test-10k-rows.pdf` | 10,000-row table (167 pages, 4.3MB) | | `doc-extreme-bidi-wrapping.pdf` | Extreme BiDi mixed-script text wrapping | | `table-heavy-text-overflow.pdf` | Dense table with heavy text overflow | | `media-rich-document.pdf` | Media-rich document with multiple images | | `tagged-accessibility-complex.pdf` | Complex tagged PDF/A accessibility tree | | `layout-extreme-customization.pdf` | Extreme layout customization (margins, columns, colors) | ### Edge-Case Stress Tests | File | Content | |------|---------| | `doc-unbreakable-text.pdf` | 1000-char words with no spaces (DNA, URL, Base64) | | `table-micro-columns.pdf` | Extreme column fractions (f=0.025, mx=1) | | `doc-link-annotation-bomb.pdf` | 500 link annotations across 10 pages | | `zero-content-empty-table.pdf` | Table with headers but 0 rows | | `zero-content-empty-doc.pdf` | Document with no blocks | | `zero-content-empty-strings.pdf` | Empty headings, paragraphs, and list items | | `doc-heavy-buffer-5mb.pdf` | 5 MB synthetic JPEG embedded (memory stress) | ### Barcode & QR Code Samples | File | Content | |------|---------| | `barcode-showcase.pdf` | All 5 formats: Code 128, EAN-13, QR Code, Data Matrix, PDF417 | | `barcode-alignment-sizing.pdf` | Alignment (left/center/right) and custom size variations | | `barcode-tagged-pdfa.pdf` | Barcodes in tagged PDF/A-2b mode (/Figure structure elements) | ### SVG Path Rendering Samples | File | Content | |------|---------| | `svg-basic-shapes.pdf` | Rect, circle, ellipse, line, polyline, polygon | | `svg-complex-paths.pdf` | Cubic/quadratic Bézier curves, arcs, combined paths | | `svg-tagged-pdfa.pdf` | SVG elements in tagged PDF/A-2b mode | ### Form Field Samples | File | Content | |------|---------| | `form-fields.pdf` | All field types: text, multiline, checkbox, radio, dropdown, listbox | | `form-contact.pdf` | Contact form with name, email, message, and submit fields | ### Digital Signature Samples | File | Content | |------|---------| | `sig-rsa-self-signed.pdf` | RSA PKCS#1 v1.5 self-signed signature | | `sig-ecdsa-p256.pdf` | ECDSA P-256 digital signature | | `sig-multi-field.pdf` | PDF with multiple signature fields | ### Streaming Output Samples | File | Content | |------|---------| | `streaming-document.pdf` | Document streamed via `buildDocumentPDFStream()` | | `streaming-table.pdf` | Table streamed via `buildPDFStream()` | ### PDF Parser & Modifier Samples | File | Content | |------|---------| | `parser-original.pdf` | Generated → parsed → verified round-trip | | `parser-modified.pdf` | Generated → parsed → modified → incremental save | | `parser-document.pdf` | Document builder → parser round-trip verification | ### Outline & Page Label Samples (v1.4.0) | File | Content | |------|---------| | `outline/outline-explicit.pdf` | Nested bookmarks (`/Outlines`) + roman/decimal page labels | | `outline/outline-auto.pdf` | `outline: 'auto'` — bookmarks derived from headings | | `outline/page-labels.pdf` | Roman front matter + prefixed appendix page labels | ### PDF Manipulation Samples (v1.4.0) | File | Content | |------|---------| | `manipulation/merged.pdf` | `mergePdfs()` — multiple documents combined | | `manipulation/split-report.pdf` | `splitPdf()` — first page range | | `manipulation/split-invoice.pdf` | `splitPdf()` — second page range | | `manipulation/extract-reordered.pdf` | `extractPages()` — selected pages, reordered | | `manipulation/streamed.pdf` | `streamToFile()` — document streamed straight to disk | ## API Reference ### Core | Function | Description | |----------|-------------| | `buildPDF(params, layout?)` | Build table-centric PDF as binary string | | `buildPDFBytes(params, layout?)` | Build table-centric PDF as `Uint8Array` | | `buildDocumentPDF(params, layout?)` | Build free-form document PDF as binary string | | `buildDocumentPDFBytes(params, layout?)` | Build free-form document PDF as `Uint8Array` | | `wrapText(text, maxWidth, fontSize, enc)` | Word-wrap text into lines | | `createPDF(params, options?)` | Smart dispatch (Worker or main thread) | | `initNodeCompression()` | Initialize native zlib for ESM (call once before `compress: true`) | | `downloadBlob(bytes, filename)` | Trigger browser download | | `toBytes(str)` | Convert binary string to `Uint8Array` | | `slugify(str)` | Sanitize string for filename | ### Image Support | Function | Description | |----------|-------------| | `parseImage(bytes)` | Auto-detect and parse JPEG or PNG | | `parseJPEG(bytes)` | Parse JPEG image (DCTDecode) | | `parsePNG(bytes)` | Parse PNG image (FlateDecode) | | `detectImageFormat(bytes)` | Detect JPEG or PNG from magic bytes | | `buildImageXObject(img, smaskObj?)` | Build PDF Image XObject dictionary | | `buildImageOperators(ref, x, y, w, h)` | Build `q cm Do Q` content stream operators | ### Link Annotations | Function | Description | |----------|-------------| | `validateURL(url)` | Validate URL scheme (http/https/mailto only) | | `buildLinkAnnotation(annot)` | Build PDF /Link annotation with /URI action | | `buildInternalLinkAnnotation(link)` | Build PDF /Link with /GoTo action | | `isLinkAnnotation(annot)` | Type guard for LinkAnnotation | ### BiDi & Arabic/Hebrew Shaping | Function | Description | |----------|-------------| | `resolveBidiRuns(text)` | Resolve text into BiDi runs with levels | | `containsRTL(text)` | Check if text contains RTL characters | | `shapeArabicText(str, fontData)` | Arabic GSUB positional shaping | | `containsArabic(text)` | Check for Arabic characters | | `containsHebrew(text)` | Check for Hebrew characters | ### Barcode & QR Code | Function | Description | |----------|-------------| | `renderBarcode(format, data, x, y, opts?)` | Unified barcode renderer (dispatches to format-specific function) | | `encodeCode128(data)` | Encode data into Code 128 barcode pattern (ISO 15417) | | `renderCode128(data, x, y, w, h)` | Render Code 128 barcode as PDF path operators | | `ean13CheckDigit(digits)` | Compute EAN-13 check digit (ISO 15420) | | `renderEAN13(data, x, y, w, h)` | Render EAN-13 barcode with guard bars and digits | | `generateQR(data, ecLevel?)` | Generate QR Code matrix (ISO 18004) | | `renderQR(data, x, y, size, ecLevel?)` | Render QR Code as PDF path operators | | `generateDataMatrix(data)` | Generate Data Matrix ECC 200 matrix (ISO 16022) | | `renderDataMatrix(data, x, y, size)` | Render Data Matrix as PDF path operators | | `encodePDF417(data, ecLevel?)` | Encode data into PDF417 codewords (ISO 15438) | | `renderPDF417(data, x, y, w, h, ecLevel?)` | Render PDF417 barcode as PDF path operators | ### SVG Rendering | Function | Description | |----------|-------------| | `parseSvgPath(d)` | Parse SVG path `d` attribute into segments | | `renderSvg(segments, options?)` | Render SVG segments (paths + ``) as PDF operators | ### Markup Annotations | Function | Description | |----------|-------------| | `buildAnnotation(annot, objNum)` | Build a full markup annotation indirect object (v1.5.0) | | `buildAnnotationBody(annot)` | Build a markup annotation dictionary body (for the modifier) (v1.5.0) | Supported `MarkupAnnotation` types: `text`, `highlight`, `underline`, `strikeout`, `squiggly`, `square`, `circle`, `line`, `freetext`. ### Layout Debug & Inspection | Function | Description | |----------|-------------| | `inspectDocumentLayout(params, layout?)` | Return a programmatic per-page block-geometry `LayoutInspection` (v1.5.0) | Enable the visual overlay via `layout: { debug: true }` or a granular `LayoutDebugOptions` (`showMargins` / `showContentBounds` / `showCells`). Byte-identical when debug is off. ### Font-Data Tools (`pdfnative/tools`) | Function | Description | |----------|-------------| | `compileFontData(buffer, opts?)` | Compile a TTF/OTF `Uint8Array` into a font-data module source string (v1.5.0) | | `parseFontData(buffer, opts?)` | Parse a TTF/OTF `Uint8Array` into a `FontDataObject` (metrics, cmap, widths, glyph coverage) (v1.5.0) | ### AcroForm Fields | Function | Description | |----------|-------------| | `buildFormWidget(field, objNum, pageRef)` | Build form field widget annotation + appearance stream | | `buildAcroFormDict(fieldRefs)` | Build `/AcroForm` dictionary for catalog | | `buildRadioGroupParent(group)` | Build radio button group parent object | | `buildAppearanceStreamDict(width, height)` | Build appearance stream dictionary | | `defaultFieldHeight(type)` | Default height by field type | ### Digital Signatures | Function | Description | |----------|-------------| | `buildSigDict(options)` | Build `/Sig` dictionary with ByteRange/Contents placeholders (`subFilter: 'ETSI.CAdES.detached'` for PAdES, v1.7.0) | | `buildDocTimeStampDict(contentsSize?)` | Build a `/DocTimeStamp` dictionary variant (ISO 32000-2 §12.8.5, v1.7.0) | | `signPdfBytes(pdf, options)` | Sign a PDF with CMS/PKCS#7 detached signature (`profile: 'pades'`, `digestAlgorithm`, multi-signature `fieldName` selector, v1.7.0) | | `signPdfBytesWithTimestamp(pdf, options)` | Sign + embed a verified RFC 3161 signature timestamp (PAdES B-T, v1.7.0) | | `listSignatures(pdf)` | Enumerate signature fields — SubFilter, ByteRange, /Contents, placeholder/timestamp flags (v1.7.0) | | `collectValidationInfo(pdf, opts?)` | Gather certificates + OCSP/CRL material for every signature via the injected `RevocationProvider` (v1.7.0) | | `embedValidationInfo(pdf, data)` | Write pre-collected LTV material as `/DSS` + `/VRI` — sync, offline, deterministic (v1.7.0) | | `addValidationInfo(pdf, opts?)` | Collect + embed in one call (PAdES B-LT, v1.7.0) | | `addDocumentTimestamp(pdf, opts?)` | Append a `/DocTimeStamp` revision (PAdES B-LTA, v1.7.0) | | `estimateContentsSize(certSizes, algorithm?, opts?)` | Estimate `/Contents` size (`{ timestamp: true }` adds RFC 3161 headroom, v1.7.0) | | `setCryptoProvider(provider)` | Install (or clear with `null`) a global native signature provider (v1.4.0) | | `getCryptoProvider()` | Return the current global `CryptoProvider`, or `null` (v1.4.0) | | `setTimestampProvider(provider)` / `getTimestampProvider()` | Global RFC 3161 transport — TimeStampReq bytes in, TimeStampResp bytes out (v1.7.0) | | `setRevocationProvider(provider)` / `getRevocationProvider()` | Global OCSP/CRL transport (v1.7.0) | ### Streaming Output | Function | Description | |----------|-------------| | `buildDocumentPDFStream(params, layout?, streamOpts?)` | Stream document PDF as `AsyncGenerator` | | `buildPDFStream(params, layout?, streamOpts?)` | Stream table PDF as `AsyncGenerator` | | `buildDocumentPDFStreamTrue(params, layout?, streamOpts?)` | **True constant-memory** document streaming — frees each part as it yields (v1.3.0) | | `buildPDFStreamTrue(params, layout?, streamOpts?)` | **True constant-memory** table streaming (v1.3.0) | | `buildDocumentPDFStreamPageByPage(params, layout?)` | Stream document PDF chunked at PDF object boundaries | | `buildPDFStreamPageByPage(params, layout?)` | Stream table PDF chunked at PDF object boundaries | | `validateDocumentStreamable(params, layout?)` | Validate document is compatible with streaming (no TOC, no `{pages}`) | | `validateTableStreamable(params, layout?)` | Validate table is compatible with streaming | | `chunkBinaryString(str, chunkSize)` | Split binary string into `Uint8Array` chunks | | `concatChunks(chunks)` | Concatenate `Uint8Array` chunks into one | | `streamByteLength(stream)` | Count total bytes from an async stream | | `streamToFile(stream, filePath, opts?)` | Drain an `AsyncGenerator` to disk with back-pressure + `AbortSignal` (Node) — returns `{ bytesWritten, path }` (v1.4.0) | ### Crypto (Hashing, ASN.1, RSA, ECDSA, X.509, CMS) | Function | Description | |----------|-------------| | `sha1(data)` | SHA-1 — `/VRI` keying and OCSP CertID identification only, never a security digest (v1.7.0) | | `sha384(data)` / `sha512(data)` | SHA-384 / SHA-512 hash (FIPS 180-4) | | `hmacSha256(key, data)` | HMAC-SHA-256 (RFC 2104) | | `derDecode(data)` | Decode DER-encoded ASN.1 | | `derSetOf(...values)` / `derGeneralizedTime(date)` | Canonical DER SET OF (X.690 §11.6) / GeneralizedTime encoder (v1.7.0) | | `rsaSign(msg, key, digest?)` / `rsaVerify(msg, sig, key, digest?)` | RSA PKCS#1 v1.5 sign/verify — SHA-256/384/512 (digest param v1.7.0) | | `ecdsaSign(hash, key)` / `ecdsaVerify(hash, sig, key)` | ECDSA P-256 sign/verify | | `parseCertificate(der)` | Parse X.509 DER certificate — incl. SKI/AKI, EKU, AIA (OCSP/caIssuers URLs), CRL distribution points (v1.7.0) | | `certHasEku(cert, oid)` | Check an extended-key-usage OID (v1.7.0) | | `buildCmsSignedData(options)` | Build CMS SignedData — PKCS#7 or PAdES profile, SHA-256/384/512 (v1.7.0) | | `parseCmsSignedData(der)` / `addUnsignedAttribute(cms, attr)` / `buildAttribute(oid, ...v)` | CMS inspection + unsigned-attribute surgery, signed bytes untouched (v1.7.0) | | `buildTimestampRequest(imprint, opts?)` / `parseTimestampResponse(der)` / `parseTimestampToken(der)` / `verifyTimestampImprint(info, hash)` | RFC 3161 timestamp protocol (v1.7.0) | | `buildOcspRequest(cert, issuer, opts?)` / `parseOcspResponse(der)` | OCSP RFC 6960 (v1.7.0) | | `parseCrl(der)` / `isSerialRevoked(crl, serial)` | CRL RFC 5280 (v1.7.0) | | `initCrypto()` | Initialize crypto module (lazy load) | ### PDF Parser & Modifier | Function | Description | |----------|-------------| | `openPdf(bytes, opts?)` | Parse a PDF `Uint8Array` and return a `PdfReader`. Pass `{ password }` to open an encrypted document (RC4, AES-128, AES-256) | | `createModifier(reader)` | Create an incremental `PdfModifier` from a `PdfReader` | | `createTokenizer(data, offset?)` | Create a low-level PDF tokenizer | | `parseValue(tok)` | Parse a single PDF value from token stream | | `parseIndirectObject(tok)` | Parse an indirect object (`N M obj ... endobj`) | | `findStartxref(data)` | Find `startxref` offset in PDF bytes | | `parseXrefTable(data, offset)` | Parse xref table/stream at given offset | | `isRef(v)` / `isDict(v)` / `isArray(v)` / `isStream(v)` | Type guards for parsed PDF values | | `dictGet(dict, key)` / `dictGetName(dict, key)` | Dictionary value accessors | | `inflateSync(data)` | Decompress FlateDecode data (zlib inflate) | | `validatePdfUA(bytes)` | Read-only PDF/UA structural checker — returns `{ valid, errors, warnings }` (v1.3.0) | | `mergePdfs(sources, opts?)` | Merge multiple PDFs into one, rebuilding a clean object graph; `opts.maxOutputSize` caps output at 256 MiB by default (v1.4.0); `opts.encrypt` re-encrypts the output (AES-128/AES-256, v1.6.0) | | `splitPdf(src, ranges, opts?)` | Split a PDF into multiple documents by inclusive 0-based page ranges (v1.4.0) | | `extractPages(src, indices, opts?)` | Extract specific pages (0-based) into a new PDF (v1.4.0) | | `reader.getPageLabels()` | Parse an existing `/PageLabels` number tree into `PageLabelRange[]` or `null` (v1.5.0) | | `reader.getAnnotations(pageIndex)` | Read a page's annotations into `ParsedAnnotation[]` (v1.5.0) | | `reader.getPageRef(pageIndex)` | Get the indirect `PdfRef` for a page (v1.5.0) | | `modifier.addAnnotation(pageIndex, body)` | Inject a new annotation on a page via incremental update (v1.5.0) | | `extractText(bytes, opts?)` | Extract per-page reading-order Unicode text (+ optional positioned runs) from any PDF, incl. encrypted (`opts.password`); `ToUnicode`/`Differences`/WinAnsi/MacRoman decoding, hard `maxTextLength` memory cap (v1.6.0) | ### Document Block Types | Type | Description | |------|-------------| | `HeadingBlock` | H1/H2/H3 with color, auto-wrapped | | `ParagraphBlock` | Text with fontSize, lineHeight, align, indent, color | | `TableBlock` | Headers + rows using PdfRow/ColumnDef | | `ListBlock` | Bullet or numbered items; entries may be plain strings or nested `ListItem` `{ text, items }` for hierarchical lists (v1.4.0) | | `ImageBlock` | JPEG/PNG with optional width, height, align, alt text | | `LinkBlock` | Hyperlink with URL, blue underline, tagged /Link | | `SpacerBlock` | Vertical whitespace | | `PageBreakBlock` | Force new page | | `TocBlock` | Auto-generated table of contents with /GoTo links | | `BarcodeBlock` | Barcode / QR code rendered via PDF path operators | | `SvgBlock` | SVG path/shape rendering as native PDF path operators | | `FormFieldBlock` | AcroForm interactive fields (text, checkbox, radio, dropdown, listbox) | ### Tagged PDF & PDF/A | Function | Description | |----------|-------------| | `resolvePdfAConfig(tagged)` | Resolve tagged option → PDF/A config (version, part, conformance) | | `encodePdfTextString(str)` | Encode string as PDF text (PDFDocEncoding or UTF-16BE hex) | ### Encryption Encryption is configured via the `encryption` option in layout options. Since v1.6.0 the reader side is public too — `openPdf(bytes, { password })` plus the `PdfPasswordError`, `PdfEncryptionUnsupportedError` and `PdfEncryptionInfo` exports. ```typescript const pdf = buildPDFBytes(params, { encryption: { userPassword: 'secret', ownerPassword: 'admin', permissions: { print: true } } }); ``` ### Color Utilities | Function | Description | |----------|-------------| | `parseColor(input)` | Parse hex / tuple / PDF string → validated PDF RGB string | | `isValidPdfRgb(str)` | Check if string is valid `"R G B"` format (0.0–1.0) | | `normalizeColors(colors)` | Validate and normalize all fields in a PdfColors object | ### Compression | Function | Description | |----------|-------------| | `initNodeCompression()` | Initialize native zlib (async, call once in ESM before `compress: true`) | | `setDeflateImpl(fn)` | Inject custom DEFLATE function (e.g. for browser polyfill) | **Browser compression** — In browser environments without native zlib, inject a third-party DEFLATE via `setDeflateImpl`: ```typescript import { setDeflateImpl, buildPDFBytes } from 'pdfnative'; import { deflateSync } from 'fflate'; // or pako setDeflateImpl(deflateSync); const pdf = buildPDFBytes(params, { compress: true }); ``` ### Fonts | Function | Description | |----------|-------------| | `registerFont(lang, loader)` | Register a font data loader | | `registerFonts(map)` | Register multiple font loaders | | `loadFontData(lang)` | Lazy-load font data (cached) | | `hasFontLoader(lang)` | Check if loader is registered | | `getRegisteredLangs()` | List registered language codes | | `createEncodingContext(fontEntries)` | Create encoding context | | `validateFontData(data)` | Opt-in structural validation of custom font data — returns `{ valid, errors, warnings }` (v1.4.0) | ### Shaping | Function | Description | |----------|-------------| | `shapeThaiText(str, fontData)` | Thai OpenType shaping (GSUB + GPOS) | | `shapeBengaliText(str, fontData)` | Bengali GSUB conjuncts + GPOS marks | | `shapeTamilText(str, fontData)` | Tamil GSUB + split vowel decomposition | | `shapeDevanagariText(str, fontData)` | Devanagari cluster shaping + GSUB/GPOS | | `shapeTeluguText(str, fontData)` | Telugu GSUB conjuncts + GPOS marks (v1.3.0) | | `shapeSinhalaText(str, fontData)` | Sinhala conjuncts + pre-base reorder + GSUB/GPOS (v1.3.0) | | `shapeTibetanText(str, fontData)` | Tibetan vertical subjoined stacking (v1.3.0) | | `shapeKhmerText(str, fontData)` | Khmer USE-lite — coeng subscripts + pre-base vowels (v1.3.0) | | `shapeMyanmarText(str, fontData)` | Myanmar USE-lite — medials + virama stacking (v1.3.0) | | `detectFallbackLangs(texts, primaryLang)` | Detect needed fallback fonts | | `detectCharLang(codePoint)` | Map codepoint to preferred font language | | `splitTextByFont(str, fontEntries)` | Multi-font text run splitting | | `needsUnicodeFont(str)` | Check if text needs CIDFont | | `containsThai(str)` | Check for Thai characters | | `resolveBidiRuns(text)` | Resolve BiDi runs (UAX #9) | | `containsRTL(text)` | Detect RTL content | | `shapeArabicText(str, fontData)` | Arabic GSUB positional shaping | | `containsArabic(text)` | Detect Arabic content | | `containsHebrew(text)` | Detect Hebrew content | | `containsTelugu(text)` | Detect Telugu content (v1.3.0) | | `isTeluguCodepoint(cp)` | Telugu codepoint predicate (v1.3.0) | | `containsSinhala(text)` / `containsTibetan(text)` / `containsKhmer(text)` / `containsMyanmar(text)` / `containsEthiopic(text)` | Detect script content (v1.3.0) | | `isSinhalaCodepoint(cp)` / `isTibetanCodepoint(cp)` / `isKhmerCodepoint(cp)` / `isMyanmarCodepoint(cp)` / `isEthiopicCodepoint(cp)` | Codepoint predicates (v1.3.0) | | `containsMath(text)` / `isMathCodepoint(cp)` | Detect / test mathematical symbols → lang `'math'` (v1.5.0) | ### Layout Constants | Constant | Description | |----------|-------------| | `PG_W` / `PG_H` | A4 page dimensions (points) | | `DEFAULT_MARGINS` | Default margins `{ t, r, b, l }` | | `DEFAULT_COLORS` | Default color palette | | `DEFAULT_COLUMNS` | Default 5-column layout | | `ROW_H` / `TH_H` | Row / header heights | | `HEADER_H` | Header zone height (15pt) | | `PAGE_SIZES` | Preset page dimensions (A4, Letter, Legal, A3, Tabloid) | | `resolveTemplate(tpl, page, pages, title, date)` | Resolve header/footer template placeholders | ## Ecosystem pdfnative ships as a library, but three official companion packages cover the most common non-library use cases — a CLI, an MCP server, and a React renderer. All live in separate repositories and depend on `pdfnative` only through the public API, so the core library stays zero-dependency. ### pdfnative-cli — command-line interface [`pdfnative-cli`](https://github.com/Nizoka/pdfnative-cli) v1.4.0 is the **official CLI**, built on `pdfnative` v1.7.0. It exposes 21 commands in five groups — create & edit (`render`, `fill`, `annotate`, `metadata`), page tree (`merge`, `split`, `extract`), security (`sign`, `verify`, `ltv`, `doc-timestamp`, `encrypt`, `decrypt`), read & extract (`inspect`, `extract-text`, `compare`), and automation & meta (`batch`, `doctor`, `schema`, `completion`, `govern`) — for use in shell scripts, Makefiles, GitHub Actions, and Docker images. Zero extra runtime dependencies, npm-provenance-signed, with a CycloneDX SBOM attached to every release. Requires Node ≥ 22. **New in v1.1.0:** **22 Unicode scripts + COLRv1 colour emoji** through the `--font`/`--lang` shortcuts, **true constant-memory streaming** (`--stream-true`), a `--max-blocks` cap for very large documents, and a **PDF/UA (ISO 14289-1) structural validator** (`inspect --pdfua` / `--check pdfua`). It also adds an **agent-native contract** — a global `--json` status/error envelope, stable `E_*` error codes, a `--dry-run` validation mode, the new **`schema`** command (Draft 2020-12), and token-economy output projection (`--summary` / `--fields` + compact JSON) that cuts agent output ~90 %. **100 % backward-compatible.** **New in v1.2.0:** five new commands — **`merge`**, **`split`**, **`extract`** (page-tree manipulation via pdfnative 1.5.0), **`annotate`** (markup annotations via incremental save, so existing signatures stay intact), and **`govern`** (the AI-governance / Human-in-the-Loop contract: `govern rules` / `govern policy` / `govern verify-issue`, with a stable `E_POLICY` error code). Plus PDF bookmarks (`--outline auto` or an explicit tree), the bundled math font (`--font math`), layout introspection (`--inspect-layout` / `--debug-layout`), and native constant-time crypto by default in `sign` (opt out with `--pure-crypto`). **New in v1.3.0:** five more commands on the pdfnative 1.6 engine — **`fill`** (fill, flatten, and export existing AcroForms via incremental save, encrypted PDFs included), **`encrypt`** / **`decrypt`** (AES-128/256 re-securing and password removal; RC4 never emitted), **`extract-text`** (reading-order Unicode text as text/JSON/NDJSON, `--runs`, `--password`), and **`doctor`** (offline environment preflight). Also native vector charts in `render`, `--password` + `--encrypt` re-encryption on merge/split/extract, an agent capability manifest (`schema manifest` + `llms.txt`), and PowerShell completion. **New in v1.4.0:** the **complete PAdES ladder** from the shell — `sign --timestamp ` (RFC 3161, B-T), **`ltv`** (B-LT `/DSS`; `collect` gathers revocation evidence as replayable JSON so `embed` can run fully offline in air-gapped environments), and **`doc-timestamp`** (B-LTA document-timestamp revisions) — plus **`metadata`** (signature-safe `/Info` + XMP edits), **`compare`** (text + structure diff with CI exit codes), **`batch --manifest`** declarative pipelines with `@id` references and an `--allow-network` opt-in, `render --strict` PDF/A gating, `inspect --signatures`, RSA-SHA384/512, and a global `--max-inflate-size` zip-bomb cap. Every network path is an explicit opt-in behind an SSRF guard. Built on pdfnative 1.7.0, Node ≥ 22. ```bash # render with full layout coverage (encryption + watermark + PDF/A-2b) npx pdfnative-cli render --input doc.json --output report.pdf \ --tagged pdfa2b --compress \ --watermark-text "DRAFT" --watermark-opacity 0.15 # sign with metadata and intermediate cert chain npx pdfnative-cli sign --input report.pdf --output signed.pdf \ --reason "Approved" --name "Finance Team" \ --signing-time 2026-04-28T10:00:00Z \ --cert-chain intermediate.pem # verify embedded signatures (byte-range + chain + trust + revocation) npx pdfnative-cli verify --input signed.pdf --strict --trust ca-root.pem # inspect with CI assertions, incl. PDF/UA accessibility gate (exit 1 on failure) npx pdfnative-cli inspect --input signed.pdf \ --check pdfa --check signed --check pdfua --json --summary ``` See the [CLI Guide](https://pdfnative.dev/guides/cli.html) for the full v1.4.0 reference, agent contract, security model, and recipes. Try the [interactive CLI playground](https://pdfnative.dev/playgrounds/cli.html) to build commands without leaving the browser. ### pdfnative-mcp — Model Context Protocol server [`pdfnative-mcp`](https://github.com/Nizoka/pdfnative-mcp) v1.6.0 is a **Model Context Protocol server** that bridges pdfnative to any MCP-compatible AI client. Once configured, your AI assistant can generate PDFs and native vector charts, embed barcodes, create, read, fill and flatten forms, sign documents through the complete PAdES ladder (B-B → B-LTA with RFC 3161 timestamps and embedded revocation material), verify signatures and document timestamps, encrypt and decrypt PDFs, validate PDF/UA structure, embed and extract attachments, extract Unicode text, render international text, merge, split and extract pages, annotate existing PDFs, rewrite document metadata, preview pagination without producing a PDF, draft governance-compliant GitHub issues (human-in-the-loop), and inspect existing PDFs — all without writing code. **v1.0.0:** first stable MCP release with 12 tools, `verify_pdf`, `add_attachment` (Factur-X / ZUGFeRD PDF/A-3), `extract_text`, smart-table options, auto-placeholder signing, and `_meta.apiVersion`. **v1.1.0:** adds `validate_pdf`, six additional scripts (Telugu, Sinhala, Tibetan, Khmer, Myanmar, Ethiopic), and COLRv1 colour-emoji support via the pdfnative 1.3.0 engine. **v1.2.0:** adds `extract_attachments`, watermark options on document tools, Unicode `normalize` (NFC/NFD/NFKC/NFKD), token-frugal read modes (`verbosity`/`fields`), and returns base64 PDF bytes once via a `resource` block. **v1.3.0:** adds the page-tree trio `merge_pdfs` / `split_pdf` / `extract_pages` (**17 tools** total), enriched authoring options (`outline`, `pageLabels`, nested lists, `viewerPreferences`, `cellBorders`, `cellVAlign`), a constant-time `node:crypto` signing provider, and DNS-rebinding protection on the HTTP transport — all via the pdfnative 1.4.0 engine. **v1.4.0:** adds `annotate_pdf` (markup via incremental update) and the network-free `draft_governance_issue` (**19 tools**), the MCP `prompts` capability (`governance_contract`, `draft_issue_workflow`), `pageLabels[]` in `inspect_pdf`, and the explicit `math` script — via the pdfnative 1.5.0 engine. **v1.5.0:** adds `add_chart`, `read_form_fields`, `fill_form`, `encrypt_pdf`, `decrypt_pdf` (**24 tools**), `password` support on the read-only and page-tree tools, MCP resources (`pdfnative://output/…`), and tool annotations — via the pdfnative 1.6.0 engine. **v1.6.0:** adds `add_ltv`, `timestamp_pdf`, `update_metadata`, `inspect_layout` (**28 tools**), all 13 block kinds in `generate_basic_pdf`, layout options and build-time `encrypt` on the document tools, image watermarks, print production, charts v2, honest PDF/A (`embedFonts` / `strict` / diagnostics), PAdES timestamps on `sign_pdf`, four new recipe prompts, and the MCP 2026-07-28 spec — via the pdfnative 1.7.0 engine. ```bash npx -y pdfnative-mcp ``` ### Available tools | Tool | Purpose | |------|---------| | `generate_basic_pdf` | Multi-page documents from structured blocks — all 13 block kinds since v1.6.0 (incl. tables, images, links, TOC, barcodes, SVG, form fields); optional `outline`, `pageLabels`, `pdfA`, layout options, build-time `encrypt`, print production | | `add_table` | Smart tables (`wrap`, `repeatHeader`, `zebra`, `caption`, `minRowHeight`, `cellPadding`, `cellBorders`, `cellVAlign`) | | `add_barcode` | QR Code, Code 128, EAN-13, Data Matrix, PDF417 | | `add_international_text` | 25 `lang` font codes (22 Unicode scripts + `latin` + `emoji` + explicit `math`) with BiDi and OpenType shaping | | `add_form` | Interactive AcroForm PDFs (`text`, `textarea`, `checkbox`, `radio`, `dropdown`, `listbox` since v1.6.0) | | `embed_image` | Embed a JPEG or PNG image (base64), with `align` / `alt` since v1.6.0 | | `prepare_signature_placeholder` | PDF with a `/Sig` field ready to be signed (optional — `sign_pdf` auto-injects one); `subFilter` / `reserveTimestamp` since v1.6.0 | | `sign_pdf` | PAdES CMS signatures (RSA-SHA256/384/512 / ECDSA-SHA256 P-256); `profile: 'pades'`, RFC 3161 `timestamp`, cert chains, multiple signatures since v1.6.0 | | `add_ltv` | Embed `/DSS` + `/VRI` long-term-validation material — PAdES B-LT (v1.6.0) | | `timestamp_pdf` | Append a `/DocTimeStamp` through the operator TSA — PAdES B-LTA (v1.6.0) | | `validate_pdf` | Read-only PDF/UA structural validation | | `verify_pdf` | Verify every PAdES signature and `/DocTimeStamp` (integrity + value + optional chain trust; `ltv: true` reports the achieved PAdES level since v1.6.0) | | `add_attachment` | PDF/A-3 with embedded files (Factur-X / ZUGFeRD) | | `extract_attachments` | Extract embedded files (optionally metadata-only) | | `extract_text` | Unicode text extraction (positioned runs; `password` since v1.5.0) | | `merge_pdfs` | Concatenate 2–50 PDFs (encrypted sources via `password`; re-encrypt since v1.5.0) | | `split_pdf` | Split one PDF into one document per page range | | `extract_pages` | Pull an arbitrary, order-preserving page subset into a new PDF | | `annotate_pdf` | Overlay markup annotations (9 types) via incremental update; not a redaction | | `draft_governance_issue` | Governance-compliant GitHub-issue draft, network-free, never submits (HITL) | | `add_chart` | Native vector charts, zero rasterisation — nine types since v1.6.0 (bar, horizontal bar, stacked bar, stacked horizontal bar, line, area, scatter, pie, donut), dual axis, log & time scales | | `read_form_fields` | List an existing AcroForm's fields (types, values, options) | | `fill_form` | Fill and optionally flatten an existing AcroForm (encrypted PDFs supported) | | `encrypt_pdf` | Re-secure with AES-128/AES-256, owner/user passwords + permissions | | `decrypt_pdf` | Remove encryption in-server (RC4 / AES-128 / AES-256 sources) | | `update_metadata` | Rewrite `/Info` (+ XMP) of an existing PDF via incremental update (v1.6.0) | | `inspect_pdf` | Structured report (metadata, pages, signatures, PDF/A, attachments, `encryptionInfo`, `pageLabels`; annotation and signature inventories, `dss`, page boxes since v1.6.0) | | `inspect_layout` | Read-only pagination dry run — page count and block geometry, no PDF produced (v1.6.0) | ### Claude Desktop configuration ```json { "mcpServers": { "pdfnative": { "command": "npx", "args": ["-y", "pdfnative-mcp"], "env": { "PDFNATIVE_MCP_OUTPUT_DIR": "/Users/you/Documents/mcp-pdfs" } } } } ``` See the [MCP Integration Guide](https://pdfnative.dev/guides/mcp.html) and the [pdfnative-mcp repository](https://github.com/Nizoka/pdfnative-mcp) for configuration on Cursor, Continue, Zed, and more. ### pdfnative-react — declarative JSX renderer [`pdfnative-react`](https://github.com/Nizoka/pdfnative-react) v1.2.0 turns declarative **JSX** into real, on-device PDFs powered by the zero-dependency pdfnative engine — no DOM, no headless browser, no SaaS round-trips. A custom React reconciler compiles your component tree synchronously into the pdfnative block model. v1.2.0 follows the pdfnative 1.7.0 engine: charts v2 (9 kinds, secondary axis, log/time scales, data labels), print production via ``, the PDF/A diagnostics channel (`layout.strict` / `onDiagnostic`), HTTP caching on `renderToResponse` (`etag` / `cacheControl`), and 25 lint rules — all additive. Requires **React 19**, **pdfnative ^1.7.0** and **Node.js ≥ 22**. React and pdfnative are peer dependencies; the package itself adds one runtime dependency, `react-reconciler`. The pdfnative engine remains dependency-free. ```tsx import { Document, Heading, Text, Table, renderToBytes } from 'pdfnative-react'; const bytes = renderToBytes( Invoice #1024 Thank you for your business.
, ); // → Uint8Array, a valid PDF ``` Every component (`Document`, `Page`, `Section`, `Heading`, `Paragraph`/`Text`, `List`/`Item`, `Table`/`Row`/`Cell`, `Image`, `Link`, `Spacer`, `PageBreak`, `TableOfContents` (alias `Toc`), `Barcode`, `Svg`, `Chart`, `FormField`) maps 1:1 onto a pdfnative block. Render with `renderToBytes` / `renderToBlob` / `renderToStream` / `renderToFile` / `renderToFileStream` / `renderToResponse`, introspect with `inspectDocument` / `lintDocument`, preview live with the `usePdf` / `usePdfStream` hooks and `PDFViewer` / `PDFDownloadLink` / `BlobProvider` client components, or let AI agents author documents with the token-frugal `DocSpec` (terse JSON tuples that compile to the *same* PDF, validated by a versioned JSON Schema). See the [React Guide](https://pdfnative.dev/guides/react.html) for the full component reference, and try the [interactive React playground](https://pdfnative.dev/playgrounds/react.html) to render JSX to PDF in your browser. ## Architecture ``` src/ ├── index.ts # Public API — single entry point ├── types/ │ ├── pdf-types.ts # Core TypeScript type definitions │ └── pdf-document-types.ts # Document builder type definitions (blocks, params) ├── core/ │ ├── pdf-builder.ts # Table-centric PDF assembly + /Info metadata + tagged PDF │ ├── pdf-document.ts # Free-form document builder (headings, paragraphs, lists, tables, images) │ ├── pdf-assembler.ts # Shared PDF binary assembly primitives (xref, trailer, writer) │ ├── encoding-context.ts # Encoding context factory (dependency inversion from fonts/) │ ├── pdf-image.ts # JPEG/PNG parsing + PDF Image XObject builder │ ├── pdf-text.ts # Text rendering (Latin + CIDFont + shaped + tagged) │ ├── pdf-stream.ts # Binary utilities + download │ ├── pdf-stream-writer.ts # AsyncGenerator streaming output │ ├── pdf-layout.ts # Layout constants & computation │ ├── pdf-tags.ts # Tagged PDF: structure tree, XMP metadata, ICC profile │ ├── pdf-annot.ts # Link annotations: /URI, /GoTo, URL validation + control-char hardening │ ├── pdf-color.ts # Color parsing, validation, normalization │ ├── pdf-compress.ts # FlateDecode stream compression (zlib, stored-block fallback) │ ├── pdf-watermark.ts # Text/image watermarks with ExtGState transparency │ ├── pdf-barcode.ts # Barcode/QR code encoders + PDF path rendering (5 formats) │ ├── pdf-svg.ts # SVG path/shape rendering as native PDF operators │ ├── pdf-form.ts # AcroForm interactive fields with appearance streams │ ├── pdf-signature.ts # CMS/PKCS#7 digital signatures (RSA + ECDSA) │ └── pdf-encrypt.ts # AES-128/256 encryption, MD5, SHA-256, key derivation ├── crypto/ │ ├── sha.ts # SHA-384, SHA-512, HMAC-SHA-256 │ ├── asn1.ts # ASN.1 DER encoding/decoding │ ├── rsa.ts # RSA PKCS#1 v1.5 sign/verify │ ├── ecdsa.ts # ECDSA P-256 sign/verify │ ├── x509.ts # X.509 certificate parsing │ └── cms.ts # CMS SignedData (PKCS#7) builder ├── parser/ │ ├── pdf-inflate.ts # DEFLATE decompression (zlib inflate) │ ├── pdf-tokenizer.ts # PDF lexical scanner (ISO 32000-1 §7.2) │ ├── pdf-object-parser.ts # PDF object parser with type guards │ ├── pdf-xref-parser.ts # Cross-reference table/stream parser │ ├── pdf-reader.ts # High-level PDF reader (page tree, stream decode) │ └── pdf-modifier.ts # Incremental modification (non-destructive save) ├── fonts/ │ ├── encoding.ts # WinAnsi + CIDFont pure encoding functions (no shaping deps) │ ├── font-loader.ts # Configurable font registry + cache │ ├── font-subsetter.ts # TTF subsetting engine (with buffer bounds checking) │ └── font-embedder.ts # CMap builder + width arrays ├── shaping/ │ ├── script-registry.ts # Centralized Unicode range constants & script predicates │ ├── thai-shaper.ts # Thai GSUB + GPOS shaping pipeline │ ├── bengali-shaper.ts # Bengali GSUB conjuncts + GPOS mark positioning │ ├── tamil-shaper.ts # Tamil GSUB + split vowel decomposition │ ├── script-detect.ts # Unicode script range detection (uses script-registry) │ ├── multi-font.ts # Cross-script font run splitting │ ├── bidi.ts # Unicode Bidirectional Algorithm (UAX #9) │ └── arabic-shaper.ts # Arabic GSUB positional shaping (uses script-registry) └── worker/ ├── worker-api.ts # Worker/main-thread dispatch └── pdf-worker.ts # Self-contained worker entry fonts/ # Pre-built font data modules (22 scripts) tools/ # CLI: build-font-data.cjs (TTF → JS module) scripts/ # Modular sample PDF generation (48 generators, 242 PDFs) tests/ # 2691+ tests (123 files: unit + integration + fuzz + parser + docs) bench/ # Performance benchmarks (vitest bench) ``` ## Development ```bash git clone https://github.com/Nizoka/pdfnative.git cd pdfnative npm install npm run build # tsup → dist/ (ESM + CJS + .d.ts) npm run test # vitest run (2691+ tests) npm run test:coverage # vitest with v8 coverage (95.41% statements at the v1.6.0 release; CI gates: 88/80/85/90) npm run test:generate # Generate 242 sample PDFs → test-output/ npm run lint # ESLint 9 + typescript-eslint strict npm run typecheck # tsc --noEmit (src/) npm run typecheck:tests # tsc --project tsconfig.test.json npm run typecheck:scripts # tsc --project tsconfig.scripts.json npm run typecheck:all # Typecheck src/ + tests/ + scripts/ npm run bench # Performance benchmarks (vitest bench) ``` ### Quality Metrics | Metric | Value | |--------|-------| | Tests | 2691+ (123 files) | | Statement coverage | 95.41% (measured at the v1.6.0 release; CI enforces ≥88%, vitest.config.ts) | | Branch coverage | 87.79% (measured at the v1.6.0 release; CI enforces ≥80%) | | Function coverage | 98.5% (measured at the v1.6.0 release; CI enforces ≥85%; lines gate: ≥90%) | | Fuzz tests | 89 tests in 5 files (`tests/fuzzing/`) | | Benchmarks | Latin 500 rows ~10ms, Unicode ~13ms (Apple M1, Node 22) | | Dependencies | 0 runtime | | CI | Node 22/24 matrix | | Provenance | npm signed builds | ## Known Limitations — Visual vs. Semantic PDF pdfnative generates **visually pixel-perfect** PDFs for all 22 supported scripts. However, PDF is fundamentally a *visual* format (a digital printer), not a *semantic* one. This distinction matters for **text extraction** (copy-paste, `pdftotext`, screen readers): ### Complex Text Layout (CTL) scripts For scripts with combining marks — **Thai**, **Devanagari**, **Vietnamese tones** — the shaper positions each mark in its own `BT…ET` block with precise GPOS offsets. PDF viewers **render** this correctly, but text extractors reconstruct content by spatial position rather than logical order. This can produce garbled output when copying text from the PDF. | Scenario | Visual rendering | Text extraction (Ctrl+C) | |----------|:---:|:---:| | Latin, Greek, Polish, Turkish | ✅ Perfect | ✅ Perfect | | CJK (Japanese, Chinese, Korean) | ✅ Perfect | ✅ Perfect | | Vietnamese (combining diacritics) | ✅ Perfect | ⚠️ May show Win-1252 fallback artifacts | | Thai (GSUB + GPOS shaping) | ✅ Perfect | ⚠️ Combining marks may be reordered | | Devanagari (matras, conjuncts) | ✅ Perfect | ⚠️ Combining marks may be reordered | | Bengali (conjuncts, GPOS marks) | ✅ Perfect | ⚠️ Combining marks may be reordered | | Tamil (split vowels, GSUB) | ✅ Perfect | ⚠️ Split vowel recomposition may fail | ### Why this happens This is an inherent limitation of the PDF spec (ISO 32000-1), not a bug in pdfnative. The ToUnicode CMap correctly maps glyph IDs back to Unicode code points, but extractors that rely on spatial reconstruction rather than CMap lookup will produce artifacts. This behavior is shared by most PDF generators that don't use Tagged PDF. ### Tagged PDF, /ActualText & PDF/A — Implemented ✅ All three roadmap items are now implemented and available via the `tagged` layout option: ```ts const pdf = buildPDFBytes(params, { tagged: true }); // PDF/A-2b (default) const pdf1b = buildPDFBytes(params, { tagged: 'pdfa1b' }); // PDF/A-1b (legacy) const pdf2u = buildPDFBytes(params, { tagged: 'pdfa2u' }); // PDF/A-2u (Unicode) ``` When `tagged` is set, the output includes: - **Tagged PDF (PDF/UA)** — full structure tree (`/Document → /Table → /TR → /TH|/TD`, `/H1-H3`, `/P`, `/L → /LI`, `/Figure`, `/Link`) with `/Span` marked content operators and `/StructParents` on every page - **/ActualText** — original Unicode string attached as UTF-16BE hex to every `/Span BDC...EMC` sequence, solving text extraction for GPOS-repositioned glyphs (Thai, Arabic, Devanagari) - **PDF/A-2b compliance** (default) — PDF 1.7, XMP metadata with `pdfaid:part=2` + `pdfaid:conformance=B`, sRGB ICC OutputIntent (`GTS_PDFA1`), `/MarkInfo << /Marked true >>` on Catalog - **PDF/A-1b compatibility** — explicit `tagged: 'pdfa1b'` uses PDF 1.4, `pdfaid:part=1` - **PDF/A-2u variant** — `tagged: 'pdfa2u'` uses PDF 1.7, `pdfaid:conformance=U` The `tagged` option is backward-compatible — omitting it or setting `false` produces the same output as before. > **PDF/A status (v1.1.0).** Every PDF/A-claiming sample now passes > the **veraPDF** reference validator (1b / 2b / 2u / 3b) when the > Latin font module is registered. Trailer `/ID` and > `/Info CreationDate` are byte-equivalent to `xmp:CreateDate` > (with timezone offset). ``, ``, > `` mirror `/Info /Title`, `/Subject`, `/Keywords` > byte-for-byte (ISO 19005-1 §6.7.3 t1 / t4 / t5). Object 3 / Object 4 > are emitted as Type0 redirector dicts pointing to the embedded > CIDFontType2 chain — no more unembedded `Helvetica` references > (ISO 19005-1 §6.3.4 / ISO 19005-2 §6.2.11.4.1). To produce strict > PDF/A: > > ```ts > import { registerFont } from 'pdfnative'; > registerFont('latin', () => import('pdfnative/fonts/noto-sans-data.js')); > ``` > > Run `npm run validate:pdfa` locally (with veraPDF installed, see > [docs/guides/pdfa.html](docs/guides/pdfa.html)) to verify against > the reference validator. CI runs veraPDF as a blocking check. ### PDF Encryption — Implemented ✅ AES-128 and AES-256 encryption with owner/user passwords and granular permissions: ```ts const pdf = buildPDFBytes(params, { encryption: { ownerPassword: 'owner123', // Required — full access password userPassword: 'user456', // Optional — password to open the PDF algorithm: 'aes128', // 'aes128' (default) or 'aes256' permissions: { print: true, // Allow printing (default: true) copy: false, // Allow copy/paste (default: false) modify: false, // Allow modification (default: false) extractText: true, // Allow text extraction (default: true) }, }, }); ``` | Algorithm | PDF Version | Revision | Key Length | CFM | |-----------|------------|----------|------------|-----| | `aes128` | 1.4 | R4 (V4) | 128-bit | /AESV2 | | `aes256` | 1.4 | R6 (V5) | 256-bit | /AESV3 | **Note:** PDF/A and encryption are mutually exclusive (ISO 19005-1 §6.3.2). Setting both `tagged` and `encryption` will throw an error. ## Typography Convention: En-Dash Separator pdfnative uses **en-dash** `–` (U+2013) with surrounding spaces as the standard title and footer separator: ``` "Arabic Script Coverage – الأبجدية العربية" ✅ recommended "Arabic Script Coverage — الأبجدية العربية" ⚠️ works, but wider gap ``` **Why en-dash?** | Property | Em-dash `—` (U+2014) | En-dash `–` (U+2013) | |----------|:---:|:---:| | Helvetica width | 1000 units (1 em) | 556 units (0.56 em) | | Visual gap at 16pt | ~24pt with spaces | ~18pt with spaces | | WinAnsi encodable | ✅ (0x97) | ✅ (0x96) | | International standard | US English only | ISO / Europe / technical | | Cursive script rendering | Disproportionate gap | Balanced spacing | The en-dash is **44% narrower** than the em-dash and follows ISO/international typography standards. This eliminates disproportionate visual gaps in cursive scripts (Arabic, Thai) where compact shaped text amplifies the perceived space around wider separators. Both em-dash and en-dash are **fully supported** by the library (encoding, width metrics, BiDi classification) — this is a typographic recommendation for the best cross-script visual balance, not a restriction. ## Stream Compression (FlateDecode) Enable FlateDecode compression for dramatically smaller PDFs: ```typescript import { initNodeCompression, buildPDFBytes } from 'pdfnative'; // Initialize native zlib (required once in ESM context) await initNodeCompression(); const pdf = buildPDFBytes(params, { compress: true }); ``` | Stream Type | Compressed? | Typical Reduction | |-------------|:-----------:|:-----------------:| | Page content (text operators) | ✅ | 80–90% | | FontFile2 (TTF subset) | ✅ | 60–80% | | ToUnicode CMap | ✅ | 80–90% | | ICC sRGB profile | ✅ | 40–60% | | XMP metadata | ❌ (tagged mode) | — | | JPEG image | ❌ (already DCTDecode) | — | | PNG image | ❌ (already FlateDecode) | — | ### Compression + Encryption Both features compose correctly — compression is applied **before** encryption per ISO 32000-1 §7.3.8: ```typescript const pdf = buildPDFBytes(params, { compress: true, encryption: { ownerPassword: 'owner123', algorithm: 'aes128', }, }); ``` ### Platform Support | Runtime | Compression Method | Performance | |---------|-------------------|-------------| | Node.js 22+ | `zlib.deflateSync()` (native C) | Optimal | | Browser | Stored-block fallback (valid FlateDecode) | No size reduction | | Deno / Bun | CJS require fallback | Depends on compat layer | For browser contexts with full compression, call `setDeflateImpl()` with a custom DEFLATE function. ## Browser & Runtime Compatibility pdfnative targets ES2020 and works in any environment that supports `Uint8Array`, `TextEncoder`, and `crypto.getRandomValues()`. | Runtime | Version | Status | Notes | |---------|---------|:------:|-------| | Node.js | 22, 24+ | ✅ Tested in CI | Full support (ESM + CJS) | | Chrome | 80+ | ✅ | ESM via bundler or ` ``` A stored-block compression fallback works automatically — no native zlib needed in the browser. ## Tabular reports — `buildPDFBytes` For bank statements, invoices, and any single-table report: ```typescript import { buildPDFBytes } from 'pdfnative'; const pdf = buildPDFBytes({ title: 'Monthly Report', infoItems: [ { label: 'Period', value: 'January 2026' }, { label: 'Account', value: 'Main' }, ], balanceText: 'Balance: $1,234.56', countText: '42 transactions', headers: ['Date', 'Description', 'Amount'], rows: [ { cells: ['01/15', 'Grocery', '-$45.00'], type: 'debit', pointed: false }, { cells: ['01/16', 'Salary', '+$3,000.00'], type: 'credit', pointed: true }, ], footerText: 'Generated by MyApp', }); ``` ## Free-form documents — `buildDocumentPDFBytes` For mixed content (manuals, articles, multi-section reports): ```typescript const pdf = buildDocumentPDFBytes({ title: 'Project Report', blocks: [ { type: 'toc' }, { type: 'heading', text: 'Executive Summary', level: 1 }, { type: 'paragraph', text: 'This quarter saw strong growth.' }, { type: 'list', style: 'bullet', items: ['Revenue +15%', 'Costs −8%'] }, { type: 'image', data: chartBytes, width: 400, alt: 'Revenue chart' }, { type: 'barcode', format: 'qr', data: 'https://example.com', width: 80 }, { type: 'pageBreak' }, { type: 'heading', text: 'Details', level: 1 }, { type: 'table', headers: ['Q', 'Revenue'], rows: [ { cells: ['Q1', '$1.2M'], type: '', pointed: false }, { cells: ['Q2', '$1.4M'], type: '', pointed: false }, ] }, ], footerText: 'Confidential', }); ``` 13 block types are available: `heading`, `paragraph`, `list`, `table`, `image`, `link`, `spacer`, `pageBreak`, `toc`, `barcode`, `svg`, `formField`, `chart`. ## Multi-language ```typescript import { registerFonts, loadFontData, buildDocumentPDFBytes } from 'pdfnative'; registerFonts({ th: () => import('pdfnative/fonts/noto-thai-data.js'), ar: () => import('pdfnative/fonts/noto-arabic-data.js'), }); const fontEntries = await Promise.all([ loadFontData('th').then(fd => ({ fontData: fd!, fontRef: '/F3', lang: 'th' })), loadFontData('ar').then(fd => ({ fontData: fd!, fontRef: '/F4', lang: 'ar' })), ]); const pdf = buildDocumentPDFBytes({ blocks: [{ type: 'paragraph', text: 'สวัสดี — مرحبا' }], fontEntries, }); ``` Note that `lang` is a property of each **font entry**, not of a block: pdfnative detects the script per character and routes to the matching font, so a single paragraph can mix Thai, Arabic and Latin. BiDi resolution and OpenType shaping follow from that routing. See the [FAQ → Fonts and Unicode](faq.html#fonts-and-unicode) for the full list of codes. ## Web Worker `createPDF` is the recommended entry point — it decides between the main thread and a worker for you: ```typescript import { createPDF } from 'pdfnative'; const pdf = await createPDF(params, { workerUrl: new URL('./pdf-worker.js', import.meta.url), // your worker script threshold: 500, // rows above this go to the worker (default WORKER_THRESHOLD = 500) onProgress: (p) => console.log(`${p}%`), }); ``` At or below the `threshold` (or when `Worker` / `workerUrl` is unavailable) the PDF is generated on the main thread; above it, the worker at `workerUrl` is spawned, with an automatic main-thread fallback if the worker fails. To drive a worker directly, use `generatePDFInWorker(workerUrl, params, { timeout, onProgress })` — note the worker URL is the **first** argument, and the options are `timeout` (ms, default 60 000) and `onProgress` (there is no threshold at this level). ## Streaming ```typescript import { buildDocumentPDFStream, concatChunks } from 'pdfnative'; // buildDocumentPDFStream(params, layoutOptions?, streamOptions?) // chunkSize lives in the 3rd argument (StreamOptions) const chunks: Uint8Array[] = []; for await (const chunk of buildDocumentPDFStream( params, {}, // layoutOptions { chunkSize: 65536 }, // streamOptions )) { chunks.push(chunk); } const pdf = concatChunks(chunks); ``` The async iterable yields `Uint8Array` chunks as the PDF is produced — no full-document buffering. The three-argument API (`params`, `layoutOptions`, `streamOptions`) keeps layout concerns (tagged, compress, watermark) and streaming concerns (chunk size) separate. ## Playgrounds The interactive playgrounds on [pdfnative.dev](https://pdfnative.dev) run entirely in the browser: - [Extreme scripts](../playgrounds/extreme-scripts.html) — live BiDi, Tamil, Bengali + Devanagari, Arabic harakat - [Scale](../playgrounds/scale.html) — 1,000 to 100,000 pages, Web Worker + true streaming > **Local testing:** opening the playgrounds as `file://` disables the Web Worker > (browsers block cross-origin Worker imports from `file:` origins). > Serve the docs directory instead: > ```bash > npm run docs:serve # → http://localhost:5000 > ``` ## Command line — pdfnative-cli Prefer the terminal? [`pdfnative-cli`](https://github.com/Nizoka/pdfnative-cli) wraps the same library with 21 commands — including `render`, `fill`, `sign`, `verify`, `ltv`, `encrypt`, `decrypt`, `merge`, `split`, `extract`, `extract-text` and `compare`: ```bash # Install once npm install --global pdfnative-cli # Render a JSON document to a PDF pdfnative render --input report.json --output report.pdf # Sign with an RSA key (loaded from env var, never logged) export PDFNATIVE_SIGN_KEY="$(cat private.pem)" export PDFNATIVE_SIGN_CERT="$(cat cert.pem)" pdfnative sign --input report.pdf --output report.signed.pdf # Inspect any PDF (encryption, signatures, PDF/A, metadata) pdfnative inspect --input report.signed.pdf --format text ``` Stdin/stdout makes it composable in shell pipelines: ```bash cat report.json | pdfnative render | pdfnative sign | pdfnative inspect --format text ``` See the dedicated [CLI guide](cli.html) for the full command reference, security model, and CI/CD recipes. ## Next steps - [Architecture](architecture.html) — modules, builders, generation pipeline. - [CLI](cli.html) — pdfnative-cli command-line interface. - [Accessibility](accessibility.html) — tagged PDF, PDF/UA, PDF/A. - [FAQ](faq.html) — fonts, encryption, signatures, comparisons. - [Troubleshooting](troubleshooting.html) — common pitfalls and fixes. - [Sample generators](https://github.com/Nizoka/pdfnative/tree/main/scripts/generators) — 242 PDFs across 37 categories (48 generators). --- # pdfnative-react — Declarative JSX Renderer Guide > **Tracks the latest published `pdfnative-react`** (v1.2.0, built on pdfnative 1.7.0), with **React 19** and `pdfnative` ^1.7.0 as peer dependencies. Live package versions — and the `pdfnative` version each one is built on — are shown at the top of the [documentation home](../index.html). Full history: [pdfnative-react releases](https://github.com/Nizoka/pdfnative-react/releases). [`pdfnative-react`](https://github.com/Nizoka/pdfnative-react) turns declarative **JSX** into real, on-device PDFs powered by the zero-dependency [`pdfnative`](https://github.com/Nizoka/pdfnative) engine — no DOM, no headless browser, no SaaS round-trips. Your documents never leave the process. > **Why a React renderer?** Front-end teams already think in components. `pdfnative-react` lets you author a PDF the same way you author a UI — with familiar `@react-pdf/renderer`-style ergonomics (`Document`, `Page`, `Text`, `usePdf`, `PDFViewer`) — while the actual bytes are produced locally by pdfnative. It is the **frontend gateway** to the pdfnative ecosystem. ```tsx import { Document, Heading, Text, Table, renderToBytes } from 'pdfnative-react'; const bytes = renderToBytes( Invoice #1024 Thank you for your business.
, ); // → Uint8Array, a valid PDF (%PDF-… …%%EOF) ``` --- ## How it works A custom **React reconciler** compiles your component tree — synchronously, with no DOM — into the `pdfnative` `DocumentParams` model, which the engine then renders to bytes. There is **no CSS/flexbox engine** and no ``: it is an honest, declarative **block flow** where every component maps 1:1 onto a pdfnative block. ``` [your JSX tree] │ custom react-reconciler (synchronous, no DOM) ┌──────────────────────────┐ │ pdfnative-react (npm) │ ← components compile to pdfnative blocks └──────────────────────────┘ │ import { buildDocumentPDFBytes, … } from 'pdfnative' ┌──────────────────────────┐ │ pdfnative (npm) │ ← zero-dependency PDF engine └──────────────────────────┘ ``` > **Zero-dependency invariant preserved.** React 19 is a **peer dependency of `pdfnative-react` only**. The core `pdfnative` library remains zero-dependency — adding the React renderer to your app never adds a dependency to the engine itself. --- ## Installation ```bash npm install pdfnative-react pdfnative react ``` **Requirements:** **React 19** and **pdfnative ^1.7.0** (both peer dependencies) · **Node.js ≥ 22**. The package adds one runtime dependency of its own, `react-reconciler`. Works in Node, browsers and SSR frameworks. > **Next.js and other React Server Component setups.** The root barrel is deliberately *not* marked `'use client'`, and importing it from a Server Component or a `'use server'` file **fails** — the reconciler needs `createContext`, which is unavailable under React's `react-server` condition. Render from a **Route Handler** instead (see [Server rendering](#server-rendering) below). The hooks and viewer components carry the directive and are published separately at `pdfnative-react/client`; import them from there in an app that mixes server and client components, because the directive does not survive bundling in the root barrel. The package ships **NPM provenance** — verify the published artifact with `npm audit signatures` or on [npmjs.com](https://www.npmjs.com/package/pdfnative-react). --- ## When to use the React renderer | Use **pdfnative-react** when… | Use the **library** / **CLI** when… | |---|---| | You already build UIs in React and want PDFs the same way | You write a non-React Node service → use `pdfnative` directly | | You want a live `