npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

modern-pdf-lib

v0.26.0

Published

A modern, WASM-accelerated PDF creation engine for every JavaScript runtime

Readme

The PDF engine for modern JavaScript

Create, parse, fill, merge, sign, and manipulate PDF documentsin Node, Deno, Bun, Cloudflare Workers, and every browser.

npm version bundle size tests TypeScript License: MIT

Get Started · Features · API · Why This?


Quick Start

npm install modern-pdf-lib
import { createPdf, PageSizes, rgb } from 'modern-pdf-lib';

const doc = createPdf();
const page = doc.addPage(PageSizes.A4);

page.drawText('Hello from modern-pdf-lib', {
  x: 50,
  y: 750,
  size: 28,
  color: rgb(0.13, 0.13, 0.13),
});

const bytes = await doc.save();          // Uint8Array
const stream = doc.saveAsStream();       // ReadableStream
const blob = await doc.saveAsBlob();     // Blob (browsers)

CDN (no install)

Use directly in the browser via CDN — no bundler required:

<script type="module">
  import { createPdf, PageSizes, rgb } from 'https://cdn.jsdelivr.net/npm/modern-pdf-lib/dist/browser.mjs';

  const doc = createPdf();
  const page = doc.addPage(PageSizes.A4);
  page.drawText('Hello from CDN!', { x: 50, y: 750, size: 24, color: rgb(0, 0, 0) });
  const bytes = await doc.save();
  console.log('PDF size:', bytes.length, 'bytes');
</script>

Also available via:

  • unpkg: https://unpkg.com/modern-pdf-lib/dist/browser.mjs
  • esm.sh: https://esm.sh/modern-pdf-lib

Script Tag (no modules)

For environments without ES module support, use the IIFE bundle which exposes a window.ModernPdf global:

<script src="https://cdn.jsdelivr.net/npm/modern-pdf-lib/dist/modern-pdf-lib.iife.js"></script>
<script>
  const { createPdf, PageSizes, rgb } = ModernPdf;

  const doc = createPdf();
  const page = doc.addPage(PageSizes.A4);
  page.drawText('Hello from script tag!', { x: 50, y: 750, size: 24, color: rgb(0, 0, 0) });
  doc.save().then(function (bytes) {
    console.log('PDF size:', bytes.length, 'bytes');
  });
</script>

Features

Create & Draw

  • Pages, text, images, shapes, SVG paths
  • TrueType & OpenType font embedding
  • Automatic font subsetting
  • JPEG / PNG image embedding
  • Image optimization (JPEG recompression, dedup, grayscale)
  • RGB, CMYK, grayscale colors
  • Linear & radial gradients, tiling patterns
  • Text layout (multiline, combed, auto-size)

Parse & Modify

  • Load existing PDFs (encrypted too)
  • Extract text with positions
  • Fill & flatten AcroForm fields
  • Merge, split, copy pages
  • Add / remove / reorder pages
  • Incremental saves

Secure & Compliant

  • AES-256 / RC4 encryption & decryption
  • Digital signatures (PKCS#7, visible/invisible, timestamps)
  • CRL/OCSP revocation checking & certificate chain validation
  • Incremental save with signature preservation
  • Multi-signature chains, MDP certification, LTV archival
  • Counter-signatures & field locking
  • PDF/A-1b through PDF/A-3u validation
  • Tagged PDF / PDF/UA accessibility
  • Structure tree & marked content
  • Redaction with content removal

Advanced

  • QR codes & barcodes (9 formats)
  • Table layout engine with pagination
  • JPEG2000 (JPXDecode) image support
  • WebP image embedding (lossy, lossless, alpha)
  • TIFF image embedding (multi-page, CMYK, direct mapping)
  • Image format auto-detection (PNG/JPEG/WebP/TIFF)
  • Form field JavaScript evaluation & sandboxing
  • Outlines / bookmarks
  • Optional content layers (OCGs)
  • File attachments & watermarks
  • Linearization (fast web view)
  • Browser helpers (download, blob, data URL)
  • Service Worker & Web Worker support
  • CLI: npx modern-pdf optimize

Why modern-pdf-lib?

Runtimes

| Runtime | Version | Status | |:---|:---|:---:| | Node.js | 25.7+ | Fully supported | | Deno | 1.40+ | Fully supported | | Bun | 1.0+ | Fully supported | | Cloudflare Workers | — | Fully supported | | Chrome / Edge | 109+ | Fully supported | | Firefox | 115+ | Fully supported | | Safari | 16.4+ | Fully supported |

API Surface

import { createPdf, loadPdf, PageSizes } from 'modern-pdf-lib';

// Create from scratch
const doc = createPdf();
doc.setTitle('Invoice #1042');
doc.setLanguage('en');

// Load existing
const existing = await loadPdf(pdfBytes, { password: 'secret' });

// Save
const bytes = await doc.save();
const stream = doc.saveAsStream();
const page = doc.addPage(PageSizes.LETTER);

page.drawText('Hello', { x: 50, y: 700, size: 24 });
page.drawImage(imageRef, { x: 50, y: 400, width: 200, height: 200 });
page.drawRectangle({ x: 50, y: 300, width: 100, height: 50, color: rgb(0, 0.5, 1) });
page.drawCircle({ x: 200, y: 325, radius: 25 });
page.drawSvgPath('M 0 0 L 100 0 L 50 80 Z', { x: 300, y: 300 });
// Standard fonts (no embedding needed)
const helvetica = doc.embedStandardFont('Helvetica');

// Custom TrueType / OpenType
const fontBytes = await readFile('Inter.ttf');
const inter = await doc.embedFont(fontBytes, { subset: true });

page.drawText('Custom font', { x: 50, y: 500, font: inter, size: 18 });
const form = doc.getForm();

form.getTextField('name').setText('Jane Doe');
form.getCheckbox('agree').check();
form.getDropdown('country').select('Canada');

form.flatten(); // Burn values into page content
import { mergePdfs, splitPdf, copyPages } from 'modern-pdf-lib';

const merged = await mergePdfs([pdf1Bytes, pdf2Bytes]);
const pages = await splitPdf(pdfBytes, [
  { start: 0, end: 4 },   // Pages 1-5
  { start: 5, end: 9 },   // Pages 6-10
]);
const bytes = await doc.save({
  userPassword: 'reader',
  ownerPassword: 'admin',
  permissions: { printing: true, copying: false },
});
import { signPdf, verifySignatures } from 'modern-pdf-lib';

const signed = await signPdf(pdfBytes, 'Signature1', {
  certificate: certDer,
  privateKey: keyDer,
  reason: 'Approved',
  appearance: {                    // optional visible signature
    rect: [50, 50, 200, 80],
    fontSize: 10,
  },
});

const results = await verifySignatures(signed);
import { loadPdf, extractTextWithPositions } from 'modern-pdf-lib';

const doc = await loadPdf(pdfBytes);
const page = doc.getPage(0);
const items = extractTextWithPositions(page.getOperators(), page.getResources());

for (const item of items) {
  console.log(`"${item.text}" at (${item.x}, ${item.y})`);
}
import { loadPdf, initWasm, optimizeAllImages, deduplicateImages } from 'modern-pdf-lib';

await initWasm({ jpeg: true });

const doc = await loadPdf(pdfBytes);

// Deduplicate identical images
const dedupReport = deduplicateImages(doc);

// Optimize all images (JPEG recompression)
const report = await optimizeAllImages(doc, {
  quality: 75,
  progressive: true,
  autoGrayscale: true,
});

console.log(`${report.optimizedImages}/${report.totalImages} images optimized`);
console.log(`Savings: ${report.savings.toFixed(1)}%`);

const optimized = await doc.save();

CLI:

npx modern-pdf optimize report.pdf report-opt.pdf --quality 60 --grayscale --dedup -v
import { createPdf, PageSizes, professionalPreset, applyPreset } from 'modern-pdf-lib';

const doc = createPdf();
const page = doc.addPage(PageSizes.A4);

page.drawTable(applyPreset(professionalPreset(), {
  x: 50,
  y: 750,
  width: 495,
  headerRows: 1,
  rows: [
    { cells: ['Product', 'Qty', 'Price', 'Total'] },
    { cells: ['Widget A', '10', '$5.00', '$50.00'] },
    { cells: ['Widget B', '25', '$3.50', '$87.50'] },
    { cells: [{ content: 'Grand Total', colSpan: 3, align: 'right' }, '$137.50'] },
  ],
  columns: [{ flex: 2 }, { width: 60 }, { width: 80 }, { width: 80, align: 'right' }],
}));
import { createPdf, PageSizes } from 'modern-pdf-lib';

const doc = createPdf();
const page = doc.addPage(PageSizes.A4);

// QR code
page.drawQrCode('https://example.com', { x: 50, y: 700, size: 120 });

// Barcodes (Code 128, EAN-13, UPC-A, Code 39, ITF, PDF417, Data Matrix)
import { encodeCode128, encodeEan13, renderStyledBarcode } from 'modern-pdf-lib';

const barcode = encodeCode128('ABC-12345');
const ops = renderStyledBarcode(barcode, { x: 50, y: 500, height: 60 });
import { enforcePdfA, checkAccessibility } from 'modern-pdf-lib';

// Enforce PDF/A-2b compliance
const archival = enforcePdfA(pdfBytes, '2b');

// Check accessibility
const issues = checkAccessibility(doc);
for (const issue of issues) {
  console.log(`[${issue.severity}] ${issue.code}: ${issue.message}`);
}

Install

# npm
npm install modern-pdf-lib

# pnpm
pnpm add modern-pdf-lib

# yarn
yarn add modern-pdf-lib

# bun
bun add modern-pdf-lib

# deno
import { createPdf } from 'npm:modern-pdf-lib';

WASM Acceleration

All WASM modules are optional. Without them, identical output is produced using pure-JS fallbacks.

import { initWasm } from 'modern-pdf-lib';

await initWasm({
  deflate: true,   // Faster compression
  png: true,       // Faster PNG decoding
  fonts: true,     // Faster font subsetting
  jpeg: true,      // JPEG encode/decode for image optimization
});

| Module | Purpose | Speedup | |:---|:---|:---:| | libdeflate | Stream compression | ~2x | | png | PNG image decoding | ~5x | | ttf | Font parsing & subsetting | ~3x | | shaping | Complex script layout | ~10x | | jbig2 | JBIG2 bilevel image decoding | ~3x | | jpeg | JPEG encode/decode for image optimization | Required |

Project Structure

modern-pdf-lib/
  src/
    core/           PDF document model, objects, writer, pages
    parser/         PDF loading, text extraction, content streams
    form/           AcroForm fields (7 types) + appearances
    annotation/     18 annotation types + appearance generators
    accessibility/  Structure tree, marked content, PDF/UA checker
    compliance/     PDF/A validation & enforcement
    signature/      PKCS#7 signatures, timestamps, verification, CRL/OCSP
    crypto/         AES-256, RC4, MD5, SHA-256/384/512
    compression/    Deflate (fflate + optional WASM)
    assets/         Font metrics/embed/subset, image embed, SVG
    barcode/        QR, Code 128, EAN, UPC, Code 39, ITF, PDF417, Data Matrix
    layout/         Table engine (spanning, pagination, presets, overflow)
    browser/        Download helpers, Service Worker, Web Worker
    layers/         Optional content groups (OCG)
    outline/        Bookmarks / document outline
    metadata/       XMP metadata, viewer preferences
    wasm/           Rust crate sources (6 modules)
    cli/            CLI tool (modern-pdf optimize)
  tests/            4,282 tests across 199 suites
  docs/             VitePress documentation

Contributing

git clone https://github.com/ABCrimson/modern-pdf-lib.git
cd modern-pdf-lib
npm install
npm test          # 4,282 tests
npm run typecheck # TypeScript 6.0 strict
npm run build     # ESM + CJS + declarations

License

MIT © 2026