Motivation
Reading a PDF shouldn't mean linking a C library. pdfboss is a clean-room reader built straight from the ISO 32000 specification: no C dependencies, no bindings to anyone else's engine — just safe Rust with a small, obvious API. The same core powers a CLI and a native Python extension, so a script and a service share one implementation.
It is a lenient reader: real-world files are damaged, and pdfboss recovers rather than refuses — reconstructing broken cross-reference tables, tolerating wrong stream lengths, and skipping garbage operators instead of erroring out.
Install
Python
Prebuilt abi3 wheels (CPython ≥ 3.12) for Linux and macOS; no toolchain required.
Rust
Usage
CLI
Explorer subcommands, each accepting a local path or an http(s):// URL (range-fetched, never downloaded whole):
Python
= # or Document(data=raw_bytes)
=
= # or doc.extract_text() for all pages
= # PNG bytes
# lazy: physical + logical, byte spans included
# Async access over files or http(s) URLs, without reading the whole document.
= await
Rust
use Document;
let doc = open?;
let page = doc.page?;
let text = extract_text?;
let pixmap = render_page?;
pixmap.save_png?;
What's inside
| Crate | Responsibility |
|---|---|
pdfboss-core |
Tokenizer, object model, stream filters, cross-references, object streams, document & page tree, content-stream operators |
pdfboss-text |
Simple and CID/Type0 fonts, standard encodings, ToUnicode CMaps, positional text extraction |
pdfboss-render |
Anti-aliased vector rasterizer — paths, fills, strokes, clipping, color, images — to RGBA/PNG |
pdfboss-aio |
Async I/O: range-fetching document access over files or HTTP, without reading the whole file |
pdfboss-cli |
The pdfboss command-line tool |
pdfboss-tui |
Interactive terminal explorer (pdfboss tui), built on pdfboss-aio |
pdfboss-py |
PyO3 extension module (pdfboss._pdfboss) built with maturin |
Supported: classic, stream, and hybrid cross-references with recovery scanning · object streams · FlateDecode, LZWDecode, ASCII85Decode, ASCIIHexDecode, RunLengthDecode + PNG/TIFF predictors · DCTDecode (JPEG) images · Standard-handler decryption — RC4 and AES-128/256 (empty user password) · page-tree attribute inheritance · text extraction with ToUnicode and WinAnsi/MacRoman/Standard encodings · rasterization of paths, fills (nonzero & even-odd), strokes, transforms, clipping, image/form XObjects, and embedded-TrueType glyph outlines · lazy element iteration over physical (objects, xref sections, trailer, with byte spans) and logical (pages, fonts, images, annotations, content operators) elements.
Benchmarks
Against other Python PDF libraries over 40 real-world PDFs (best-of-3 per file, aggregated over the files every library handled; pages/sec, higher is faster):
pdfboss is the fastest library measured on both operations — including against the C-backed PyMuPDF. On text extraction it reaches 1,539 pages/s versus PyMuPDF's 279 (≈5.5×), and 25–80× the pure-Python readers. On open + parse it reaches 19,114 pages/s versus PyMuPDF's 3,766 (≈5×): lazy page-tree loading means opening a document reads only its declared page count instead of parsing every page dictionary up front. Rendering is not compared — pdfboss's rasterizer does not yet paint every glyph, so timing it against full renderers would be misleading.
Numbers are machine-dependent; reproduce with benchmarks/bench.py.
Limitations
Rendered pages paint the outlines of embedded TrueType glyphs (Type0/CIDFontType2 under Identity, and simple /TrueType fonts via their cmap). Text in other fonts (CFF/Type1 programs, the standard 14, subset fonts without a usable cmap) is still positioned but not drawn.
Not yet supported in v0.1 (they error or degrade gracefully, and are on the roadmap): password-protected documents (the empty user password is handled for both RC4 and AES) · non-TrueType glyph outlines (CFF/Type1) · shadings and tiling patterns · JPXDecode (JPEG 2000).
The sync and async APIs are not at parity on encryption: Document/Page (and the CLI's info/text/render/obj) decrypt empty-user-password RC4/AES files transparently, as above. AsyncDocument (pdfboss tui, any http(s):// target, and the Python AsyncDocument) currently rejects every encrypted document outright, real password or not — async decryption parity is a tracked follow-up.
Development
License
Dual-licensed under either of
- MIT license (LICENSE-MIT)
- Apache License, Version 2.0 (LICENSE-APACHE)
at your option. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual-licensed as above, without any additional terms or conditions.