Pure-Rust PDF parsing and rendering, with interchangeable CPU (tiny-skia) and GPU (wgpu) renderers whose output matches within <1% of pixels.
- Pure Rust — zero C/C++ dependencies, fully safe.
- PDF parsing — header, traditional xref + xref/object streams + hybrid
/XRefStm, trailer chains, lazy xref repair, object model, stream filters (Flate / LZW / ASCII85 / ASCIIHex / RunLength / DCT / CCITT G3-G4 + predictors) with corrupt-stream salvage. - Malformed-input robustness — opens corrupt, headerless, or garbage-tail
files via full-file object-scan recovery (catalog inside an
/ObjStm, page-tree synthesis from/Type /Pagescan, byte-flipped/Typetolerance, lenient header/dict parsing). Never panics or hangs on adversarial input: path/raster/clip budgets plus interpret/render time backstops degrade to a partial render instead. Recent hardening: predictor overflow protection, safe ObjStm parsing, mesh shading NaN validation, font cache LRU eviction (256-font limit) to prevent memory exhaustion attacks. - Performance — CMYK/ColorSpace caching, zero-copy knockout rendering, in-place dash pattern optimization, and zero-copy PNG saving deliver 2–3× faster rendering on typical workloads (layered PDFs, technical drawings, repeated colors).
- Encryption — RC4 (40/128-bit) and AES-128 / AES-256 (V5 R5/R6) standard
security handler with crypt filters; opens with the user, owner, or empty
password (
open_with_password, CLI--password). - Content interpretation — graphics state, paths, clipping, text (incl.
render modes and rise), inline & XObject images, Form XObjects (full
resources,
/BBoxclip), axial/radial shadings, shading patterns, all 16 blend modes, dash patterns. - Color — DeviceGray/RGB/CMYK, ICCBased (
/N), Indexed, Lab, Separation/DeviceN via a full PDF function evaluator (types 0/2/3/4). - Fonts — embedded TrueType, Type1, Type1C/CFF, CID/Type0 (Identity-H,
/W,/CIDToGIDMapstreams), Type3, the standard-14 fonts; encodings +/Differences; Quartz-subset recovery;/ToUnicodetext extraction. - TXT, Markdown & HTML conversion — text-only conversion skips image
decoding entirely; rich Markdown/HTML exports decoded images as PNG assets and
includes document/page metadata. Unsupported or malformed images are discarded
without interrupting text extraction (
convert_pdf, CLIconvert). - PowerPoint (PPTX) export — converts PDF pages to editable PowerPoint
presentations preserving text (with font/size/color/style), shapes
(rectangles, ellipses, lines with fill/stroke), and embedded images as native
PowerPoint elements rather than rasterizing to images (
zpdf-pptx-export, CLIexport-pptx). - SVG export — vector-faithful page → SVG conversion (
zpdf-svg-export, CLIexport-svg). Paths, glyphs, and strokes stay vectors; images embed as base64 PNG; clips/soft masks/blend modes map to SVG equivalents. Verified against the CPU backend via resvg rasterization (zero systematic drift). - WebAssembly — the full read pipeline (parse + CPU render + text + SVG)
compiles to
wasm32-unknown-unknown(zpdf-wasm). Pure Rust with zero C dependencies makes this feasible where native PDF libraries fail. Includes a fully client-side browser demo (www/) with drag-drop, page navigation, text extraction, and SVG export — nothing uploads. - Images — 1/2/4/8/16-bpc,
/Decode, soft masks, stencil & color-key masks, Indexed palettes, CMYK JPEG; bilinear sampling with box-filter minification. - Page geometry — CropBox-aware rendering, page-tree attribute
inheritance (
/Rotate,/Resources, boxes), page rotation. - Annotations & forms —
/APappearance streams (/ASstates, Hidden/NoView); an AcroForm field model (acro_form(), CLIforms) that generates text/choice field appearances when the producer left none. - Navigation & metadata — the document outline / bookmarks (
outline(), CLIoutline), named & explicit destinations resolved to a page + view (both/Names /Destsand the legacy/Root /Dests), page labels (/PageLabels→page_labels(), decimal/roman/letters + prefix/offset), link annotations resolved to their target page or URI (page_annotations()→dest/uri, CLIlinks), XMP/Metadatavia a hardened, entity-expansion-safe scrape (xmp_metadata()), and the/Infodictionary (info()).zpdf infosurfaces the/Info, XMP, outline, and page-label data. - Digital signatures — parses
/Sigsignature fields from AcroForm, verifies byte-range integrity (recomputes SHA-1/256/384/512 digest of/ByteRangespans vs. CMSmessageDigest) and cryptographic signatures (RSA PKCS#1 v1.5 / ECDSA P-256/P-384 over signed attributes using embedded certificate public keys).signatures()API + CLIzpdf signatures. Optional certificate-chain verification against caller-provided trust anchors (trust::verify_certificate_chain, CLI--trust roots.pem) with validity-period checks; revocation (CRL/OCSP) remains out of scope. - Writing & editing — a full authoring/editing toolkit (
zpdf-writer):- Document creation from scratch (
DocumentBuilder): pages, text (standard-14 or embedded TrueType with automatic font subsetting), JPEG/RGB/RGBA images (alpha → SMask), and vector paths. - Incremental updates (ISO 32000-1 §7.5.6): annotations (with baked
/APappearance streams), form filling, page rotate/delete/reorder, metadata, text & image stamps, digital signature creation (adbe.pkcs7.detached, RSA / ECDSA P-256) — including updates to encrypted documents (new objects encrypted with the document key). - Document merge (
append_document): pages plus outlines, AcroForm fields (collision renaming), and optional-content (layer) configuration; page extraction / split. - Full rewrite (
rewrite_pdf): garbage-collect, renumber, decrypt, Flate-compress, optional image downsampling — and encrypt on save (AES-256 R6 or RC4-128 with user/owner passwords and permissions). - True redaction (
redact_page): removes text/image/path operators intersecting a region from the content stream itself (not a cosmetic box) and drops overlapping annotations. - Linearization (
linearize_pdf): "fast web view" output per ISO 32000-1 Annex F.
- Document creation from scratch (
- PDF/A validation — a best-effort conformance rule engine for
PDF/A-1b and PDF/A-2b (
pdfa::validate, CLIzpdf validate): encryption/ID/header checks, XMPpdfaididentification,GTS_PDFA1output intent, font embedding, forbidden features (JavaScript, embedded files, transparency for A-1). - Text extraction quality — geometric XY-cut reading order with dehyphenation (line-break hyphen joining) and RTL repair (Hebrew / Arabic visual→logical reordering).
- Logical structure / Tagged PDF — the
/StructTreeRootstructure tree (struct_tree(), CLIstruct) read into a navigable model of structure elements with their roles (/Sresolved through/RoleMapto standard types likeH1/Table/Figure), accessibility text (/Alt//ActualText), language, titles, page associations, and marked-content (MCID) / object (/OBJR) kids; plus tagged-ness detection (is_tagged(),/MarkInfo). Text extraction can follow the structure tree's logical reading order with/ActualText//Altsubstitution (struct_ordered_text(), CLItext --struct) — the interpreter binds each text run to its/MCID— instead of the geometric XY-cut default. - CPU rendering — tiny-skia backend, PNG output at any DPI.
- GPU rendering — wgpu backend (fills, strokes, clips, text, images, blend groups); matches the CPU renderer within <1% pixels.
- Tooling — CLI with read commands
(
info/render/text/search/convert/export-pptx/export-svg/tables/forms/outline/links/struct/attachments/signatures/validate/compare/dump/debug-stream) and write commands (fill/merge/split/optimize/annotate/redact/sign/pages/set-meta/stamp), an interactive winit viewer example, and a native GPUI desktop reader (zpdf-viewer-gpui).
- docs/guides/user-guide.md — the
zpdfcommand-line tool. - docs/guides/library.md — using zpdf as a Rust library + architecture.
- docs/architecture/DESIGN.md — architecture spec (Chinese).
- docs/performance/PERFORMANCE.md — rendering performance investigation.
- docs/CHANGELOG.md — release notes.
- docs/planning/ROADMAP.md — development plan.
- zpdf-skill — an agent skill that teaches an AI coding assistant the
zpdfCLI (see below).
Command-line tool — cargo install builds the zpdf binary, or
cargo binstall downloads a prebuilt one (no compile):
cargo binstall zpdf-cli # prebuilt binary (no compilation)
cargo install zpdf-cli # build from source (default)
cargo install zpdf-cli --features gpu # + the wgpu GPU backendzpdf info document.pdf
zpdf render document.pdf -p 1 -o out.png --dpi 150Prebuilt binaries (Windows x86_64, Linux x86_64 gnu/musl + aarch64, macOS
aarch64 + x86_64) are attached to each GitHub Release;
cargo-binstall fetches the one matching your host automatically.
Library — add the zpdf facade crate to your project:
cargo add zpdf # CPU rendering (default)
cargo add zpdf --features gpu-render # + the wgpu GPU backendPublished on crates.io · API docs on docs.rs.
The zpdf-skill submodule is an agent skill that makes an
AI coding assistant proficient with the zpdf CLI. It works across any
agent/skill-capable coding tool — Claude Code,
OpenAI Codex, opencode,
and others that consume a SKILL.md + reference files.
It ships a SKILL.md plus a set of reference files (reading-commands.md,
editing-commands.md, analysis-commands.md, …) that document every command
and flag, with an intelligent loading strategy that pulls in only the reference
relevant to the task at hand (reading vs. editing vs. analysis) to keep
context overhead low.
Install it into your tool's skills/agents directory by symlinking or copying
the submodule's SKILL.md + references/ there (each tool's convention
differs — Claude Code uses ~/.claude/skills/, Codex and opencode read a
project- or user-level skills/config). Then ask the assistant to "use the zpdf
skill" for any PDF task — it will run the right zpdf commands for
inspecting, rendering, converting, editing, or signing PDFs.
The submodule tracks the Xero-Team/zpdf-skill
repository and is kept in sync with the CLI's capabilities.
If you use AI tools when contributing to zpdf itself, that is separate from the skill above — see AI_POLICY.md for the project's AI contribution policy.
Run from a checkout with cargo run (or drop the cargo run -p zpdf-cli --
prefix once the CLI is installed):
# Inspect a document
cargo run -p zpdf-cli -- info document.pdf
# Render page 1 at 150 DPI (CPU)
cargo run -p zpdf-cli -- render document.pdf -p 1 -o out.png --dpi 150
# Render on the GPU (requires the `gpu` feature)
cargo run -p zpdf-cli --features gpu -- render document.pdf -p 1 -o gpu.png --backend wgpu
# Extract text, and compare two renders
cargo run -p zpdf-cli -- text document.pdf -p 1
cargo run -p zpdf-cli -- compare out.png gpu.png --out diff.png
# Convert the whole document to TXT, rich Markdown, or rich HTML + PNG assets
cargo run -p zpdf-cli -- convert document.pdf -o document.txt --mode text
cargo run -p zpdf-cli -- convert document.pdf -o document.md --mode rich
cargo run -p zpdf-cli -- convert document.pdf -o document.html --mode rich
# Export pages as editable PowerPoint or vector SVG
cargo run -p zpdf-cli -- export-pptx document.pdf -o presentation.pptx
cargo run -p zpdf-cli -- export-svg document.pdf -p 1-5 -o page-%d.svg
# Create, edit, and secure PDFs
cargo run -p zpdf-cli -- merge a.pdf b.pdf -o merged.pdf # pages + outlines + forms + layers
cargo run -p zpdf-cli -- annotate document.pdf -p 1 --kind highlight --rect 70,690,340,725 -o annotated.pdf
cargo run -p zpdf-cli -- redact document.pdf -p 1 --rect 60,690,400,730 -o redacted.pdf
cargo run -p zpdf-cli -- optimize document.pdf -o smaller.pdf --max-image-dim 1500
cargo run -p zpdf-cli -- optimize document.pdf -o encrypted.pdf --encrypt aes256 --user-password s3cret
cargo run -p zpdf-cli -- optimize document.pdf -o linear.pdf --linearize
cargo run -p zpdf-cli -- sign document.pdf --key key.p8.der --cert cert.der -o signed.pdf
cargo run -p zpdf-cli -- signatures signed.pdf --trust roots.pem
cargo run -p zpdf-cli -- validate document.pdf --profile pdfa-2b
# Interactive viewer (pan/zoom/page-flip)
cargo run -p zpdf-render-wgpu --example viewer -- document.pdf
# Native desktop reader (GPUI: page list, zoom, fit-width, keyboard nav)
cargo run -p zpdf-viewer-gpui -- document.pdfuse zpdf::{ContentInterpreter, ImageCache, PdfDocument, RenderBackend};
let data = std::fs::read("document.pdf").map_err(zpdf::Error::Io)?;
let doc = PdfDocument::open(data)?;
let page = doc.page(0)?; // 0-based
let mut fonts = doc.load_page_fonts(&page);
let mut images = ImageCache::new();
let content = doc.page_content_bytes(&page)?;
let display_list = ContentInterpreter::new(page.effective_box()) // CropBox ∩ MediaBox
.with_page_rotation(page.rotate)
.with_fonts(&mut fonts)
.with_document(doc.file(), &page.resources)
.with_images(&mut images)
.interpret(&content);
let mut renderer = zpdf::cpu::CpuRenderer::new()
.with_fonts(&fonts)
.with_images(&images);
let page_img = renderer.render_display_list(&display_list, 150.0 / 72.0)?; // 150 DPI
page_img.save_png("out.png")?;Switch zpdf::cpu::CpuRenderer for zpdf::gpu::WgpuRenderer (with features = ["gpu-render"])
to render on the GPU — everything upstream is identical. See docs/guides/library.md.
use zpdf::svg::display_list_to_svg;
let svg = display_list_to_svg(&display_list, &fonts, &images, &Default::default());
std::fs::write("page.svg", svg)?;cd crates/zpdf-wasm
bash build-web.sh
python -m http.server -d www 8080import init, { Pdf } from "./pkg/zpdf_wasm.js";
await init();
const pdf = Pdf.open(pdfBytes);
const bitmap = pdf.render_page(0, 150.0 / 72.0); // page 0, 150 DPI
const text = pdf.page_text(0);
const svg = pdf.page_svg(0);use zpdf::DocumentBuilder;
let mut builder = DocumentBuilder::new();
let page = builder.add_page(612.0, 792.0); // US Letter, points
builder.add_text(page, "Hello, PDF!", 72.0, 700.0, "Helvetica", 24.0, (0.0, 0.0, 0.0))?;
// Embedded fonts are automatically subset to the glyphs actually used.
let font = builder.embed_font(std::fs::read("DejaVuSans.ttf")?)?;
builder.add_text_embedded(page, "Embedded text", 72.0, 650.0, font, 14.0, (0.0, 0.3, 0.7))?;
std::fs::write("hello.pdf", builder.build()?)?;18-crate workspace with a strict one-direction dependency flow. Render backends
depend only on zpdf-display-list, never on the parser — parsing and rendering stay
fully decoupled.
zpdf-core Shared types: ObjectId, PdfObject, Matrix, Rect, Error, ParseLimits
├─ zpdf-parser Lexer, xref/trailer, object & stream decoding, filters
│ └─ zpdf-document Catalog, page tree, resource inheritance, font loading
│ └─ zpdf-content Content-stream interpreter → DisplayList
├─ zpdf-font Type1 / TrueType / CID / Type3 fonts, CMap, encodings
├─ zpdf-image JPEG / Flate / CCITT / masks / palettes → RGBA
├─ zpdf-color Device / Indexed / Lab color + PDF function evaluator
├─ zpdf-display-list Flat RenderCommand sequence (the backend contract)
├─ zpdf-render RenderBackend trait
│ ├─ zpdf-render-cpu tiny-skia backend
│ └─ zpdf-render-wgpu wgpu backend (+ winit viewer example)
├─ zpdf-writer PDF authoring & editing: DocumentBuilder, incremental updates,
│ merge, redaction, encryption, subsetting, linearization
├─ zpdf-pptx-export DisplayList → editable PowerPoint
├─ zpdf-svg-export DisplayList → vector-faithful SVG
├─ zpdf-wasm WebAssembly bindings (parse + render + text + SVG in browser/Node)
├─ zpdf-cli CLI tool
├─ zpdf-viewer-gpui Native desktop reader (GPUI; depends on the facade)
└─ zpdf Facade crate (re-exports; feature-gates cpu / gpu)
| Feature | Status |
|---|---|
| PDF 1.0–2.0 header | ✅ |
Traditional xref + xref/object streams + hybrid /XRefStm |
✅ |
Incremental update (/Prev) chains, lazy xref repair |
✅ |
Corrupt/headerless recovery (object scan, catalog-in-/ObjStm, page-tree synthesis) |
✅ |
| Adversarial-input safety (no panics, no hangs; budget-bounded partial render) | ✅ |
| Flate / LZW / ASCII85 / ASCIIHex / RunLength + predictors | ✅ with corrupt-stream salvage |
| DCTDecode (JPEG, incl. CMYK) / CCITTFaxDecode (G3/G4) | ✅ |
| Encryption: RC4 40/128, AES-128, AES-256 (R5/R6), crypt filters | ✅ user / owner / empty password |
Page tree + attribute inheritance (/Rotate, /Resources, boxes) |
✅ |
| CropBox-aware rendering + page rotation | ✅ |
| Graphics state, paths, painting, clipping, dash patterns | ✅ |
DeviceGray / DeviceRGB / DeviceCMYK / ICCBased (/N) |
✅ |
| Indexed / Lab / Separation / DeviceN (tint transforms) | ✅ |
| PDF functions (sampled / exponential / stitching / PostScript) | ✅ |
Axial & radial shadings (sh + shading patterns) |
✅ |
| Mesh shadings: free-form/lattice Gouraud (type 4/5), Coons/tensor patches (type 6/7) | ✅ |
| Tiling patterns (PatternType 1, colored/uncolored cell replication) | ✅ |
16 blend modes (/BM) |
✅ both backends |
| Text + text state operators, render modes, rise | ✅ (text-as-clip approximated) |
| Type3 / TrueType / Type1 / Type1C / CID-Type0 / standard-14 fonts | ✅ |
Encodings + /Differences, /ToUnicode extraction |
✅ |
/CIDToGIDMap streams, OpenType-wrapped CID CFF |
✅ |
Inline & XObject images: 1–16 bpc, /Decode, SMask, /Mask, palettes |
✅ |
Form XObjects (full resources, /BBox clip, recursion guards) |
✅ |
| CPU rendering (PNG) | ✅ |
| GPU rendering (wgpu) | ✅ |
ExtGState soft masks (/SMask), transparency groups |
✅ (knockout + non-isolated) |
ICC color profiles (real color management, moxcms) |
✅ |
Annotation appearance streams (/AP, /AS, Hidden/NoView) |
✅ |
| Interactive forms (AcroForm): field model + generated text/choice appearances | ✅ |
| Non-embedded font fallback (incl. CJK via system fonts) | ✅ |
| JBIG2 / JPX (JPEG 2000) filters | ✅ |
Optional content groups / layers (/OCG, /OCMD, /VE) |
✅ |
Predefined + embedded CMaps, vertical writing (WMode 1) |
✅ |
| Digital signatures: byte-range integrity + RSA/ECDSA cryptographic verification | ✅ (+ opt-in cert-chain trust; no revocation) |
| PDF creation from scratch (pages, text, images, paths, font embedding + subsetting) | ✅ |
| Incremental update writing (annotations, forms, stamps, signing; encrypted docs too) | ✅ |
| Encryption on save (AES-256 R6, RC4-128; permissions) | ✅ |
| True redaction (content-stream excision + annotation removal) | ✅ |
| Document merge incl. outlines, AcroForm fields, OCG configs | ✅ |
| Linearization ("fast web view", Annex F) | ✅ |
| PDF/A-1b / PDF/A-2b validation (best-effort rule engine) | ✅ |
| PowerPoint (PPTX) export (editable text/shapes/images) | ✅ |
| SVG export (vector-faithful paths/glyphs/clips/masks) | ✅ |
| WebAssembly (parse + render + text + SVG in browser/Node) | ✅ |
All pure Rust:
| Crate | Purpose |
|---|---|
ttf-parser |
TrueType / OpenType / CFF font parsing |
tiny-skia |
CPU 2D rasterization |
flate2 (rust_backend) |
FlateDecode |
zune-jpeg |
JPEG (DCTDecode) |
aes + cbc + sha2 |
AES encryption/decryption (RustCrypto) |
rsa + p256 + p384 |
RSA/ECDSA signing & verification (RustCrypto) |
getrandom |
Key/salt/IV generation for encryption on save |
image |
PNG I/O |
winnow |
Parsing helpers |
wgpu + lyon + pollster |
GPU rendering (gpu-render feature) |
wasm-bindgen |
WebAssembly bindings (zpdf-wasm) |
resvg |
SVG rasterizer (test dependency for SVG export fidelity) |
winit |
Viewer example only (dev-dependency) |
Contributions are welcome. Read CONTRIBUTING.md for project scope, development setup, test expectations, and the pull request process. For usage help, see SUPPORT.md. Report vulnerabilities privately as described in SECURITY.md. If you use AI tools when contributing, follow AI_POLICY.md — you may use AI, but you must understand what it did and add a short human note in your own words to each commit/PR.
cargo build # CPU-only (default)
cargo build --features gpu-render # include the wgpu backend
cargo test # all tests
cargo test -p zpdf --features gpu-render # + the GPU↔CPU acceptance harness
cargo clippy --workspace- Phase 1 — PDF parsing — done
- Phase 2 — Content interpretation + CPU rendering — done
- Phase 3 — wgpu GPU rendering — done
- Phase 4 — Advanced features — done (encryption incl. AES + user/owner passwords, shadings + mesh shadings, blend modes, spot color, CropBox/rotation, tiling-pattern cells, soft masks & transparency groups, annotation appearance streams, interactive forms (AcroForm), optional content, ICC color management, JBIG2 + JPEG 2000, system-font fallback, composite-font CMaps + vertical writing)
- Writer toolkit — done (document creation from scratch, incremental updates incl. encrypted documents, encryption on save, true redaction, full document merge, font subsetting + image downsampling, signature creation + trust-chain verification, linearization, PDF/A validation)
- Robustness — corrupt/adversarial-corpus pass: opens 426/618 of a malformed-PDF corpus (from 166), zero render panics, zero timeouts/hangs
MIT