lopdf

A pure Rust library for low-level PDF document creation, parsing, editing, and merging

Library
Cargo
v0.44.0
2,230stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
85/100Excellent
Development Activity100
Maintenance72
Community68
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
75/100Good
Architecture80
Code Quality82
Innovation75
Learning Curve62

lopdf is a Rust library that gives developers direct, low-level access to the internal object graph of a PDF document — dictionaries, streams, cross-reference tables, and the trailer — rather than a high-level “add text here” API. It can parse existing PDFs, mutate their object trees in place, merge multiple documents into one, and serialize the result back to a valid PDF file, including compressed object streams for smaller output.

Because it works at the object level, lopdf is often reached for by tools that need precise control over PDF internals: form fillers, PDF mergers/splitters, redaction tools, and document-processing pipelines that need to inspect or rewrite specific PDF objects rather than treat the file as an opaque blob.

What You Get

  • A Document type modeling the full PDF object graph (dictionaries, streams, arrays, references)
  • Parsing of existing PDFs including xref tables, object streams, and linearized files
  • PDF merging utilities with bookmark/outline preservation across merged documents
  • Content stream encoding/decoding for reading and writing page operators (text, graphics)
  • Encryption and decryption support (RC4/AES) including password-protected PDFs
  • Optional feature flags for font embedding, async I/O (tokio), and serde support

Common Use Cases

  • Programmatically generating PDF reports or invoices from application data
  • Merging multiple PDF files into a single document while preserving bookmarks
  • Extracting text and metadata from existing PDF files
  • Building redaction or form-filling tools that need direct object-level edits
  • Decrypting and inspecting password-protected PDFs for archival processing

Under The Hood

Architecture: lopdf centers on a Document struct holding a BTreeMap<ObjectId, Object> plus a trailer dictionary, directly mirroring the PDF file format’s own object-graph structure (src/document.rs, src/object.rs). Reading a file (src/reader.rs, ~1500 lines) parses the header, cross-reference table/streams, and trailer, then lazily resolves indirect references into this map; writing (src/writer.rs) walks the same map to serialize objects, optionally grouping them into compressed PDF 1.5+ object streams (src/object_stream.rs) via save_modern(). Content streams (text/graphics operators) are handled separately in src/content.rs, keeping page-drawing concerns decoupled from the object model.

Tech Stack: Pure Rust (edition 2024, MSRV 1.88) with #![forbid(unsafe_code)]. Core dependencies are narrowly scoped to their task: nom for binary/text parsing, flate2 for stream compression, aes/cbc/ecb/md-5/sha2 for encryption, indexmap for order-preserving dictionaries, and thiserror for error types. Heavier capabilities (image, tokio, serde, rayon, chrono/jiff, font embedding) are all gated behind optional Cargo features, keeping the default build lean.

Code Quality: The crate ships an extensive tests/ suite (12+ integration test files covering object streams, linearized files, fonts, metadata, encryption edge cases) plus numerous runnable examples/. Error handling is centralized through a thiserror-based Error/ParseError/DecompressError enum rather than panics, and clippy::all is denied at the crate root, indicating an enforced lint baseline.

API Design: The public surface (src/lib.rs) re-exports a compact set of types — Document, Object, Dictionary, Stream, Reader — with a dictionary! macro that makes constructing nested PDF dictionaries readable without heavy boilerplate. The trade-off for this low-level, spec-mirroring design is a real learning curve: callers need PDF-format literacy (object IDs, xref, content operators) that a page-drawing abstraction would hide, though the README’s FAQ and worked examples mitigate this.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search