What it does
Opens a PDF, resolves objects through the cross-reference (classic tables,
xref streams with /W field widths and /Index runs, /Prev
incremental-update chains, and /ObjStm object streams), walks the page
tree and extracts text from content streams:
- text operators
Tj,TJ,',"plus the positioning opsTd,TD,Tm,T*;Dorecurses into Form XObjects; - font decoding:
/ToUnicodeCMaps (bfchar,bfrangeincl. array destinations and surrogate pairs), the five predefined encodings plus/Differences(AGL names +uniXXXX/uXXXXXX), and CID-keyed fonts (/Type0,/Identity-H/-Vand embedded CMap streams); - stream filters
FlateDecode(zlib + raw-deflate fallback),ASCII85,ASCIIHexwith/DecodeParmsPNG/TIFF predictors.
Refusals, never guesses: encrypted documents refuse per page with object
context, CID fonts without /ToUnicode refuse, unsupported stream filters
refuse naming the filter, and a corrupt xref is rebuilt by scanning when
possible (reported via Document::xref_was_rebuilt). Every page failure
carries the page number; every object-level refusal carries the object.
The pith suite contract
pith-pdf is part of the pith suite (pith-hash). Every suite repository follows the same rules; CI enforces them mechanically:
- Naming: a library is always
pith-<domain>(pith-image,pith-audio,pith-zip, ...). The curator/repository of repositories is the barepith-hash. Never invent a second naming scheme inside the suite. - Version pinning: cross-library dependencies pin
~0.1(e.g.pith-image = { version = "~0.1", path = "../pith-image" }). The whole suite moves together inside 0.1.x; breaking changes require a suite-wide version bump, never a silent minor drift. - Zero third-party dependencies: every crate depends only on other
pith-*crates plusstd.scripts/check-zero-deps.py(run in CI) fails the build on any other crate, for normal, build and dev dependencies alike. - No unsafe: every crate root carries
#![forbid(unsafe_code)]. - Hex-exact vectors:
reference.jsonat the repo root is the cross-language source of truth. Thegen-referencebinary regenerates it; CI verifies the committed copy is current (gen-reference verify), and CD ships the regenerated file with every SDK artifact. Python, Node and Go SDKs MUST test against the same bytes.
Repository layout
src/ the pith-pdf library (no_std + alloc)
tests/fixtures generated PDF corpus with expected extractions (PROVENANCE.md)
tools/gen-reference the vector generator binary (bin name: gen-reference)
reference.json hex-exact cross-SDK test vectors
Install
Rust (the core library):
Python / Node / Go SDKs are published from the same cdylib on every release; see the release assets or the package registries for the matching version.
Quick start
let pdf = read?;
let text = extract_text?;
// pages are joined by \x0c (form feed)
for in text.split.enumerate
Contributing
See CONTRIBUTING.md.
Security
See SECURITY.md.
License
MIT © pith-hash