🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

pdfnative

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

pdfnative

Zero-dependency native PDF generation library. 16 scripts (Arabic, Hebrew, Thai, CJK, Devanagari, Bengali, Tamil, Cyrillic, Greek, Georgian, Armenian, Latin), BiDi, PDF/A-1b/2b/3b, AES encryption, digital signatures, AcroForm, barcodes, SVG. Pure JavaScri

Source
npmnpm
Version
1.1.0
Version published
Weekly downloads
370
156.94%
Maintainers
1
Weekly downloads
 
Created
Source

pdfnative

CI CodeQL npm version npm downloads bundle size zero dependencies TypeScript License: MIT npm provenance website pdfnative-mcp pdfnative-cli

Pure native PDF generation library — zero vendor dependencies. ISO 32000-1 (PDF 1.7) compliant.

Highlights

  • Zero dependencies — built from scratch in pure TypeScript. Zero runtime dependencies, tree-shakeable, auditable
  • ISO 32000-1 compliant — valid xref tables, /Info metadata, proper font embedding
  • 16 Unicode scripts — Thai, Japanese, Chinese (SC), Korean, Greek, Devanagari, Turkish, Vietnamese, Polish, Arabic, Hebrew, Cyrillic, Georgian, Armenian, Bengali, Tamil
  • 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 — simplified Unicode Bidirectional Algorithm (UAX #9) with glyph mirroring
  • 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)
  • PDF Encryption — AES-128 (V4/R4) and AES-256 (V5/R6), owner + user passwords, granular permissions
  • Free-form document builder — headings, paragraphs, lists, tables, images, barcodes, SVG paths, form fields, spacers, page breaks, table of contents
  • Barcode & QR code generation — Code 128, EAN-13, QR Code, Data Matrix, PDF417 — pure PDF path operators (no images)
  • SVG path rendering — path, rect, circle, ellipse, line, polyline, polygon as native PDF operators
  • AcroForm fields — text, multiline, checkbox, radio, dropdown, listbox with appearance streams (ISO 32000-1 §12.7)
  • Digital signatures — CMS/PKCS#7 detached signatures with RSA + ECDSA, SHA-256/384/512, X.509 parsing (ISO 32000-1 §12.8)
  • Streaming output — AsyncGenerator-based progressive PDF emission with configurable chunk size
  • PDF parser & modifier — read existing PDFs (tokenizer, xref, object parser, FlateDecode inflate) + incremental modification
  • 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
  • 95%+ test coverage — 1588+ tests across 40 files, fuzz suite, performance benchmarks
  • 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
  • Command-line interface — render, sign, and inspect PDFs from the shell with pdfnative-cli — zero-config, scriptable, ideal for CI/CD pipelines

Installation

npm install pdfnative

Requirements: Node.js >= 22 | Modern browsers | Deno | Bun

Documentation

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:

FeaturepdfnativejsPDFpdfkitpdf-libpdfmake
Runtime dependencies03643
TypeScript declarationsBuilt-inBuilt-in@types/*Built-in@types/*
PDF/A (ISO 19005)1b, 2b, 2u, 3b
Tagged PDF / PDF/UA
EncryptionAES-128/256
Complex text shaping (GSUB/GPOS)✅ Thai, Arabic, Devanagari, Bengali, TamilVia fontkitVia @pdf-lib/fontkitVia pdfkit
BiDi (RTL) layout
Modify existing PDFs✅ (incremental)
Forms (AcroForms)
Digital signatures✅ (RSA + ECDSA)
Barcode / QR code (native)✅ 5 formatsQR
SVG path rendering
Streaming output
PDF parser
Tree-shakeable (ESM)
NPM provenance (SLSA)

Data sources: npm registry metadata and official README/documentation for each library as of April 2026. Dependency counts reflect direct dependencies listed in each package's package.json. "—" 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

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:

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

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'),
  // 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

LanguageCodeFontScript
ThaithNoto Sans ThaiGSUB + GPOS shaping
JapanesejaNoto Sans JPCJK ideographs + kana
Chinese (Simplified)zhNoto Sans SCCJK ideographs
KoreankoNoto Sans KRHangul syllables
GreekelNoto Sans GreekGreek alphabet
Hindi (Devanagari)hiNoto Sans DevanagariGSUB conjuncts + GPOS marks
TurkishtrNoto Sans TurkishLatin extended (İ/ı)
VietnameseviNoto Sans VietnameseLatin + combining marks
PolishplNoto Sans PolishLatin extended (Ł/ł)
ArabicarNoto Sans ArabicGSUB positional shaping
HebrewheNoto Sans HebrewRight-to-left script
Russian (Cyrillic)ruNoto SansCyrillic alphabet
GeorgiankaNoto Sans GeorgianMkhedruli script
ArmenianhyNoto Sans ArmenianArmenian alphabet
BengalibnNoto Sans BengaliGSUB conjuncts + GPOS marks
TamiltaNoto Sans TamilGSUB ligatures + split vowels
Latin (PDF/A)latinNoto Sans VFWinAnsi-extended Latin (curly quotes, em-dash, ellipsis…)
EmojiemojiNoto EmojiMonochrome emoji (BMP/SMP, Fitzpatrick, ZWJ, VS-15/16)

Multi-Font (Mixed Scripts)

Generate PDFs with multiple scripts in the same document:

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)

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:

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

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:

FormatExampleDescription
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)
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):

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)
  },
});
ZoneKeyDefaultDescription
Titletitle16PDF title text
Info barinfo9Key-value pairs below title
Table headerth8Column header row
Table cellstd7.5Data row cells
Footerft7Page 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:

  • Navigate to the font's GitHub repository (e.g., github.com/notofonts/bengali)
  • Find the TTF file under fonts/NotoSansBengali/unhinted/ttf/ (or similar path)
  • Click the file, then click "Download raw file" (or use the raw URL)
  • 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:

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.

Visual PDF Inspection

Generate sample PDFs for all supported languages to visually verify output:

npm run test:generate

This creates 150+ PDF files in test-output/ (git-ignored), organized in twenty-five categories (including emoji/ and pdfa-latin/ added in v1.1.0). See scripts/README.md for the modular generator architecture.

Financial Statements (per language)

FileContent
sample-latin.pdfEnglish / Helvetica
sample-th.pdfThai with GSUB + GPOS shaping
sample-ja.pdfJapanese (CJK ideographs)
sample-zh.pdfChinese Simplified
sample-ko.pdfKorean (Hangul)
sample-el.pdfGreek
sample-hi.pdfHindi (Devanagari)
sample-tr.pdfTurkish (İ/ı special casing)
sample-vi.pdfVietnamese (combining marks)
sample-pl.pdfPolish (Ł/ł)
sample-ar.pdfArabic (RTL, positional shaping)
sample-he.pdfHebrew (RTL)
sample-ru.pdfRussian (Cyrillic)
sample-ka.pdfGeorgian (Mkhedruli)
sample-hy.pdfArmenian
sample-bn.pdfBengali (GSUB conjuncts + GPOS marks)
sample-ta.pdfTamil (GSUB + split vowel decomposition)
sample-multi.pdfMixed: all 16 scripts in one PDF
sample-pagination.pdf200 rows, multi-page layout

Diverse Use Cases (non-financial)

FileContent
diverse-student-transcript.pdfUniversity academic transcript (Latin)
diverse-recipe-th.pdfThai recipe — Tom Yum Goong ingredients (Thai)
diverse-server-ja.pdfServer monitoring dashboard (Japanese)
diverse-inventory-zh.pdfWarehouse product inventory (Chinese)
diverse-sports-ko.pdfK-League football standings (Korean)
diverse-library-el.pdfClassical Greek library catalog (Greek)
diverse-medical-hi.pdfBlood test lab results (Hindi)
diverse-menu-tr.pdfTurkish restaurant dinner menu (Turkish)
diverse-weather-vi.pdfWeekly weather forecast — Hanoi (Vietnamese)
diverse-train-pl.pdfTrain schedule — Warsaw (Polish)
diverse-marketplace-ar.pdfGold marketplace catalog — Dubai (Arabic)
diverse-museum-he.pdfMuseum exhibition catalog — Jerusalem (Hebrew)

Alphabet / Character Coverage

FileContent
alphabet-thai.pdf44 consonants, vowels, tone marks, digits
alphabet-japanese.pdfHiragana, Katakana, Kanji numerals & common
alphabet-chinese.pdf121 characters by category (HSK frequency)
alphabet-korean.pdfHangul jamo, syllables, complex clusters
alphabet-greek.pdfFull uppercase/lowercase, accented, archaic
alphabet-devanagari.pdfVowels, consonants, matras, conjuncts, digits
alphabet-turkish.pdf29 letters, İ/ı dotted-I distinction test
alphabet-vietnamese.pdf7 base vowels × 6 tones, all diacritics
alphabet-polish.pdf32 letters, digraphs, pangram
alphabet-arabic.pdf28 letters, harakat, numerals, ligatures
alphabet-hebrew.pdf22 letters, final forms, vowel points
alphabet-cyrillic.pdf33 Russian letters, Ukrainian/Serbian extended
alphabet-georgian.pdf33 Mkhedruli letters, Asomtavruli
alphabet-armenian.pdf38 letters, ligatures
alphabet-bengali.pdfVowels, consonants, conjuncts, digits
alphabet-tamil.pdfVowels, consonants, compound characters, digits

PDF/A Conformance Variants

FileContent
tagged-pdfa2b-default.pdfPDF/A-2b (tagged=true, default)
tagged-pdfa2b-explicit.pdfPDF/A-2b (tagged='pdfa2b', explicit)
tagged-pdfa1b.pdfPDF/A-1b (tagged='pdfa1b', legacy)
tagged-pdfa2u.pdfPDF/A-2u (tagged='pdfa2u', Unicode)
tagged-pdfa3b.pdfPDF/A-3b (tagged='pdfa3b', embedded file attachments)

Encrypted PDFs

FileContent
encrypted-aes128.pdfAES-128 (V4/R4) owner-only
encrypted-aes256.pdfAES-256 (V5/R6) owner-only
encrypted-aes128-user.pdfAES-128 with user+owner passwords
encrypted-aes256-user.pdfAES-256 with user+owner passwords
encrypted-readonly.pdfAES-128 read-only (no copy/modify)
encrypted-noprint.pdfAES-128 fully restricted

Sample passwords (for testing only — all documented in scripts/generate-samples.ts):

FileOwner PasswordUser Password
encrypted-aes128.pdfowner123(none — opens freely)
encrypted-aes256.pdfowner256(none — opens freely)
encrypted-aes128-user.pdfowner123user456
encrypted-aes256-user.pdfowner256user789
encrypted-readonly.pdfowner-ro(none — opens freely)
encrypted-noprint.pdfowner-np(none — opens freely)
doc-encrypted-aes128.pdfdocownerdocuser
doc-encrypted-aes256.pdfstrongowner256(none — opens freely)

Document Builder Samples

FileContent
doc-headings-paragraphs.pdfH1/H2/H3 + paragraphs with text wrapping
doc-lists.pdfBullet + numbered lists
doc-links.pdfExternal hyperlink annotations
doc-table.pdfEmbedded table in document
doc-spacer-pagebreak.pdfSpacers + forced page breaks (3 pages)
doc-encrypted-aes128.pdfDocument builder + AES-128 encryption
doc-encrypted-aes256.pdfDocument builder + AES-256 encryption
doc-image.pdfImage embedding (JPEG, centered)
doc-custom-colors.pdfColor formats (hex, tuple, PDF operator)
doc-japanese.pdfJapanese Unicode document (headings, lists, table)
doc-arabic.pdfArabic RTL document (headings, lists, table, BiDi)
doc-hebrew.pdfHebrew RTL document (headings, lists, table, BiDi)
doc-thai.pdfThai user manual (GSUB+GPOS shaping, pricing table)
doc-bengali.pdfBengali document (GSUB conjuncts + GPOS marks)
doc-tamil.pdfTamil document (GSUB substitution + split vowels)
doc-devanagari.pdfHindi (Devanagari) document — GSUB conjuncts, reph reordering, matra reordering, split vowels
doc-chinese-catalog.pdfChinese product catalog (tables, ordering info)
doc-multi-language.pdfMulti-language: EN + Arabic + Japanese in one PDF
doc-invoice.pdfInvoice template (line items, totals, payment link)
doc-report-multipage.pdf3-page technical report (7 sections, 4 tables)
doc-contract-bilingual.pdfBilingual EN/AR contract (legal sections, signatures)
doc-showcase-all-blocks.pdfAll 12 block types in one PDF

Compressed PDFs (FlateDecode)

FileContent
compressed-latin-100rows.pdf100-row Latin table (87% smaller)
uncompressed-latin-100rows.pdfSame 100-row table without compression (baseline)
compressed-japanese.pdfJapanese CIDFont + TTF subset (62% smaller)
compressed-arabic.pdfArabic RTL + GSUB shaping (compressed)
compressed-thai.pdfThai GSUB+GPOS shaping (compressed)
compressed-tagged-pdfa2b.pdfFlateDecode + Tagged PDF/A-2b (XMP uncompressed)
compressed-encrypted-aes128.pdfFlateDecode + AES-128 encryption
doc-compressed.pdfDocument builder with FlateDecode

Stress Test PDFs

FileContent
stress-test-10k-rows.pdf10,000-row table (167 pages, 4.3MB)
doc-extreme-bidi-wrapping.pdfExtreme BiDi mixed-script text wrapping
table-heavy-text-overflow.pdfDense table with heavy text overflow
media-rich-document.pdfMedia-rich document with multiple images
tagged-accessibility-complex.pdfComplex tagged PDF/A accessibility tree
layout-extreme-customization.pdfExtreme layout customization (margins, columns, colors)

Edge-Case Stress Tests

FileContent
doc-unbreakable-text.pdf1000-char words with no spaces (DNA, URL, Base64)
table-micro-columns.pdfExtreme column fractions (f=0.025, mx=1)
doc-link-annotation-bomb.pdf500 link annotations across 10 pages
zero-content-empty-table.pdfTable with headers but 0 rows
zero-content-empty-doc.pdfDocument with no blocks
zero-content-empty-strings.pdfEmpty headings, paragraphs, and list items
doc-heavy-buffer-5mb.pdf5 MB synthetic JPEG embedded (memory stress)

Barcode & QR Code Samples

FileContent
barcode-showcase.pdfAll 5 formats: Code 128, EAN-13, QR Code, Data Matrix, PDF417
barcode-alignment-sizing.pdfAlignment (left/center/right) and custom size variations
barcode-tagged-pdfa.pdfBarcodes in tagged PDF/A-2b mode (/Figure structure elements)

SVG Path Rendering Samples

FileContent
svg-basic-shapes.pdfRect, circle, ellipse, line, polyline, polygon
svg-complex-paths.pdfCubic/quadratic Bézier curves, arcs, combined paths
svg-tagged-pdfa.pdfSVG elements in tagged PDF/A-2b mode

Form Field Samples

FileContent
form-fields.pdfAll field types: text, multiline, checkbox, radio, dropdown, listbox
form-contact.pdfContact form with name, email, message, and submit fields

Digital Signature Samples

FileContent
sig-rsa-self-signed.pdfRSA PKCS#1 v1.5 self-signed signature
sig-ecdsa-p256.pdfECDSA P-256 digital signature
sig-multi-field.pdfPDF with multiple signature fields

Streaming Output Samples

FileContent
streaming-document.pdfDocument streamed via buildDocumentPDFStream()
streaming-table.pdfTable streamed via buildPDFStream()

PDF Parser & Modifier Samples

FileContent
parser-original.pdfGenerated → parsed → verified round-trip
parser-modified.pdfGenerated → parsed → modified → incremental save
parser-document.pdfDocument builder → parser round-trip verification

API Reference

Core

FunctionDescription
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

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

FunctionDescription
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

FunctionDescription
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 Path Rendering

FunctionDescription
parseSvgPath(d)Parse SVG path d attribute into segments
renderSvg(segments, options?)Render SVG segments as PDF path operators

AcroForm Fields

FunctionDescription
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

FunctionDescription
buildSigDict(options)Build /Sig dictionary with ByteRange/Contents placeholders
signPdfBytes(pdf, options)Sign a PDF with CMS/PKCS#7 detached signature
estimateContentsSize(options)Estimate hex-encoded /Contents size for pre-allocation

Streaming Output

FunctionDescription
buildDocumentPDFStream(params, layout?, streamOpts?)Stream document PDF as AsyncGenerator<Uint8Array>
buildPDFStream(params, layout?, streamOpts?)Stream table PDF as AsyncGenerator<Uint8Array>
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

Crypto (Hashing, ASN.1, RSA, ECDSA, X.509, CMS)

FunctionDescription
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
rsaSign(msg, key) / rsaVerify(msg, sig, key)RSA PKCS#1 v1.5 sign/verify
ecdsaSign(hash, key) / ecdsaVerify(hash, sig, key)ECDSA P-256 sign/verify
parseCertificate(der)Parse X.509 DER certificate
buildCmsSignedData(options)Build CMS SignedData (PKCS#7)
initCrypto()Initialize crypto module (lazy load)

PDF Parser & Modifier

FunctionDescription
openPdf(bytes)Parse a PDF Uint8Array and return a PdfReader
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)

Document Block Types

TypeDescription
HeadingBlockH1/H2/H3 with color, auto-wrapped
ParagraphBlockText with fontSize, lineHeight, align, indent, color
TableBlockHeaders + rows using PdfRow/ColumnDef
ListBlockBullet or numbered items
ImageBlockJPEG/PNG with optional width, height, align, alt text
LinkBlockHyperlink with URL, blue underline, tagged /Link
SpacerBlockVertical whitespace
PageBreakBlockForce new page
TocBlockAuto-generated table of contents with /GoTo links
BarcodeBlockBarcode / QR code rendered via PDF path operators
SvgBlockSVG path/shape rendering as native PDF path operators
FormFieldBlockAcroForm interactive fields (text, checkbox, radio, dropdown, listbox)

Tagged PDF & PDF/A

FunctionDescription
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. Internal encryption functions are not part of the public API.

const pdf = buildPDFBytes(params, {
  encryption: { userPassword: 'secret', ownerPassword: 'admin', permissions: { printing: true } }
});

Color Utilities

FunctionDescription
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

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

import { setDeflateImpl, buildPDFBytes } from 'pdfnative';
import { deflateSync } from 'fflate'; // or pako

setDeflateImpl(deflateSync);

const pdf = buildPDFBytes(params, { compress: true });

Fonts

FunctionDescription
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

Shaping

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

Layout Constants

ConstantDescription
PG_W / PG_HA4 page dimensions (points)
DEFAULT_MARGINSDefault margins { t, r, b, l }
DEFAULT_COLORSDefault color palette
DEFAULT_COLUMNSDefault 5-column layout
ROW_H / TH_HRow / header heights
HEADER_HHeader zone height (15pt)
PAGE_SIZESPreset 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 two official companion packages cover the most common non-library use cases. Both live in separate repositories and depend on pdfnative only through the public API.

pdfnative-cli — command-line interface

pdfnative-cli v0.2.0 is the official CLI. It exposes four commands — render, sign, inspect, verify — covering the full pdfnative v1.0.5 surface for use in shell scripts, Makefiles, GitHub Actions, and Docker images. Zero extra runtime dependencies, npm-provenance-signed.

Highlights (v0.2.0): hybrid flags + --layout file.json model, encryption (AES-128/256), watermarks (text + image), header/footer page templates with {page}/{pages}/{date}/{title}, PDF/A-3 attachments (Factur-X / ZUGFeRD pattern), multilingual fonts via --lang, table-variant rendering, signing metadata + intermediate cert chains, inspect --verbose/--pages/--check, and a brand-new verify command for byte-range integrity and certificate-chain validation. 100 % backward-compatible with v0.1.0.

# 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)
npx pdfnative-cli verify --input signed.pdf --strict --trust ca-root.pem

# inspect with CI assertions (exit 1 on failure)
npx pdfnative-cli inspect --input signed.pdf \
  --check pdfa --check signed --format json

See the CLI Guide for the full v0.2.0 reference, security model, recipes, and the --conformance--tagged migration path. Try the interactive CLI playground to build commands without leaving the browser.

pdfnative-mcp — Model Context Protocol server

pdfnative-mcp is a Model Context Protocol server that bridges pdfnative to any MCP-compatible AI client. Once configured, your AI assistant can generate PDFs, embed barcodes, create forms, sign documents, and render international text — all without writing code.

npx -y pdfnative-mcp

Available tools

ToolPurpose
generate_basic_pdfMulti-page documents from structured blocks (headings, paragraphs, lists)
add_tableTabular reports from column headers and data rows
add_barcodeQR Code, Code 128, EAN-13, Data Matrix, PDF417
add_international_text16 non-Latin scripts with BiDi & OpenType shaping
add_formInteractive AcroForm PDFs (text, checkbox, radio, dropdown)
embed_imageEmbed a JPEG or PNG image (base64)
prepare_signature_placeholderPDF with a /Sig field ready to be signed
sign_pdfCMS/PKCS#7 digital signatures (RSA-SHA256 / ECDSA-SHA256)

Claude Desktop configuration

{
  "mcpServers": {
    "pdfnative": {
      "command": "npx",
      "args": ["-y", "pdfnative-mcp"],
      "env": {
        "PDFNATIVE_MPC_OUTPUT_DIR": "/Users/you/Documents/mcp-pdfs"
      }
    }
  }
}

See the MCP Integration Guide and the pdfnative-mcp repository for configuration on Cursor, Continue, Zed, and more.

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 (16 scripts)
tools/                    # CLI: build-font-data.cjs (TTF → JS module)
scripts/                  # Modular sample PDF generation (23 generators, 140+ PDFs)
tests/                    # 1726+ tests (48 files: unit + integration + fuzz + parser)
bench/                    # Performance benchmarks (vitest bench)

Development

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 (1588+ tests)
npm run test:coverage    # vitest with v8 coverage (95%+)
npm run test:generate       # Generate 150+ 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

MetricValue
Tests1588+ (40 files)
Statement coverage95.41%
Branch coverage87.79%
Function coverage98.5%
Fuzz tests48 edge-case scenarios
BenchmarksLatin 500 rows ~10ms, Unicode ~13ms (Apple M1, Node 22)
Dependencies0 runtime
CINode 22/24 matrix
Provenancenpm signed builds

Known Limitations — Visual vs. Semantic PDF

pdfnative generates visually pixel-perfect PDFs for all 16 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.

ScenarioVisual renderingText 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:

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 varianttagged: '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). <dc:title>, <dc:description>, <pdf:Keywords> 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:

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

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)
    },
  },
});
AlgorithmPDF VersionRevisionKey LengthCFM
aes1281.4R4 (V4)128-bit/AESV2
aes2561.4R6 (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?

PropertyEm-dash (U+2014)En-dash (U+2013)
Helvetica width1000 units (1 em)556 units (0.56 em)
Visual gap at 16pt~24pt with spaces~18pt with spaces
WinAnsi encodable✅ (0x97)✅ (0x96)
International standardUS English onlyISO / Europe / technical
Cursive script renderingDisproportionate gapBalanced 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:

import { initNodeCompression, buildPDFBytes } from 'pdfnative';

// Initialize native zlib (required once in ESM context)
await initNodeCompression();

const pdf = buildPDFBytes(params, { compress: true });
Stream TypeCompressed?Typical Reduction
Page content (text operators)80–90%
FontFile2 (TTF subset)60–80%
ToUnicode CMap80–90%
ICC sRGB profile40–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:

const pdf = buildPDFBytes(params, {
  compress: true,
  encryption: {
    ownerPassword: 'owner123',
    algorithm: 'aes128',
  },
});

Platform Support

RuntimeCompression MethodPerformance
Node.js 22+zlib.deflateSync() (native C)Optimal
BrowserStored-block fallback (valid FlateDecode)No size reduction
Deno / BunCJS require fallbackDepends 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().

RuntimeVersionStatusNotes
Node.js22, 24+✅ Tested in CIFull support (ESM + CJS)
Chrome80+ESM via bundler or <script type="module">
Firefox80+ESM via bundler or <script type="module">
Safari14+ESM via bundler or <script type="module">
Edge80+Chromium-based
Deno1.0+Native ESM imports
Bun1.0+Native ESM imports
Web WorkersVia pdfnative/worker entry point
React Native⚠️Requires TextEncoder polyfill

Bundle format: ESM (dist/index.js) + CJS (dist/index.cjs) + TypeScript declarations (dist/index.d.ts). Tree-shakeable with sideEffects: false.

Origin

pdfnative was born inside plika.app — a personal finance application where high-quality, multi-language PDF generation (bank statements, transaction reports) was a core requirement. Rather than depending on heavy third-party libraries, the PDF engine was built from scratch with zero dependencies, strict ISO compliance, and native support for 16 Unicode scripts.

The decision was then made to extract the engine into an independent open-source library so that everyone can benefit from production-grade PDF generation — not just plika.app users.

Where it all started — the PDF engine that became pdfnative was originally built inside plika.app, a personal finance app generating multi-language bank statements and financial summaries across 16 scripts.

Security

  • No eval(), Function(), or dynamic code execution
  • Input validation at buildPDF() and buildDocumentPDF() entry: type checks, row/block limits
  • URL validation at validateURL(): blocks javascript:, file:, data: URI schemes + control characters (U+0000–U+001F, U+007F–U+009F)
  • RGBA PNG rejection: unsupported color types rejected at parse boundary with descriptive errors
  • PDF string escaping for \, (, ) — prevents injection
  • CIDFont hex encoding — no string injection vector
  • TTF subsetting uses typed arrays with bounds checking + compound glyph iteration limits
  • XRef offset guard: validates byte offsets before writing cross-reference table
  • JPEG parser robustness: validates SOF markers and handles edge-case byte sequences
  • PDF encryption: AES-128/256 with per-object keys, random IVs — no ECB mode
  • No external crypto dependencies — pure TypeScript AES, MD5, SHA-256 implementations
  • NPM provenance — signed builds via GitHub Actions OIDC

For more details, see SECURITY.md.

Contributing

We welcome contributions! See CONTRIBUTING.md for:

  • Development environment setup
  • Running tests, linting, and type checking
  • Code style requirements (strict TypeScript, pure functions, ESM-first)
  • Branch strategy and PR process

Citing pdfnative

If you use pdfnative in academic, governmental, or compliance work, please cite it. Citation metadata is available in CITATION.cff.

@software{pdfnative,
  author  = {Nizoka},
  title   = {pdfnative: Zero-dependency, ISO 32000-1 compliant PDF generation for TypeScript},
  url     = {https://github.com/Nizoka/pdfnative},
  year    = {2026}
}

License

MIT — see LICENSE.

Font data files in fonts/ are licensed under SIL Open Font License 1.1.

Keywords

pdf

FAQs

Package last updated on 29 Apr 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts