Safe-PDF is a modular PDF reader and renderer written in Rust.
The project is still pre-alpha and under active development. APIs change quickly, rendering coverage is incomplete, and the current value of the repo is its architecture: strict safety constraints, clear layering, and extension points for new renderers or non-rendering PDF tooling.
Safe-PDF is organized as a Cargo workspace under crates/, with examples and build tooling alongside it.
At a high level, the pipeline looks like this:
PDF bytes
-> pdf-tokenizer
-> pdf-parser
-> pdf-object
-> pdf-document
-> pdf-page
-> pdf-content-stream / pdf-content-stream-operators
-> pdf-canvas
-> pdf-renderer
-> pdf-graphics-skia / pdf-graphics-femtovg
pdf-tokenizer: lexical analysis for PDF byte streams.pdf-parser: syntax-level parsing for objects, streams, xref data, headers, and related structures.pdf-object: in-memory PDF object model, including dictionaries, streams, trailers, versions, and object resolution support.pdf-document: document loading, decryption/encryption handling, object stream support, and high-level document access.pdf-page: page tree traversal, resource lookup, forms, patterns, shadings, external graphics state, and page-level caches.pdf-content-stream: content stream parsing and operator stream handling.pdf-content-stream-operators: trait-based operator categories used to dispatch path, text, color, graphics-state, clipping, shading, image, and marked-content operations.pdf-canvas: stateful PDF drawing engine that interprets page content against a generic backend.pdf-renderer: page rendering orchestration, plus recording-canvas based page caching and replay.
pdf-filter: PDF stream filters such as ASCII85, ASCIIHex, LZW, predictors, and CCITT Fax support.pdf-decode: sample decoding helpers and indexed/ranged decode utilities.pdf-image: image XObject and inline-image handling.pdf-color-space: PDF color space parsing and conversion support, including Indexed, ICCBased, Separation, DeviceN, Lab, CalGray, and CalRGB.pdf-function: sampled, stitching, exponential interpolation, and PostScript-backed PDF functions.pdf-shading: shading model parsing and paint generation for gradients and mesh-based shadings.pdf-font: font decoding and mapping support for Type 0, Type 1, TrueType, Type 3, encodings, widths, CMaps, and ToUnicode handling.pdf-postscript: PostScript parser and calculator used by higher-level PDF functionality.pdf-graphics: shared geometry, color, path, transform, and rendering data structures.pdf-object-collection: utility collection support for PDF objects.
pdf-graphics-skia: Skia-backedCanvasBackendimplementation.pdf-graphics-femtovg: FemtoVG-backedCanvasBackendimplementation.
Two design points matter most if you are evaluating the repo:
CanvasBackendinpdf-canvaskeeps PDF interpretation separate from the concrete graphics engine. A backend supplies drawing primitives; the PDF pipeline stays backend-agnostic.pdf-content-stream-operatorsexposes trait-based operator handling, so the same parsed operator stream can drive a renderer, recorder, analyzer, or extraction tool without rewriting the parser.
safe-pdf/
├── crates/ # Core workspace crates
├── examples/ # Native and web-facing demos
├── fuzz/ # Fuzz targets for parser-oriented testing
├── xtask/ # Build automation, including emscripten packaging
├── Cargo.toml
└── README.md
The workspace members are crates/*, examples, and xtask.
The current rendering path is intentionally layered:
- Parse a document into structured PDF objects and pages.
- Resolve page resources such as fonts, forms, patterns, images, shadings, and color spaces.
- Parse content streams into PDF operators.
- Execute those operators against
PdfCanvas. - Forward low-level draw calls into a chosen
CanvasBackend.
pdf-renderer also supports recording a page into a RecordingCanvas, then replaying it later. That cache is resolution-independent and backend-agnostic, which is useful for page reuse, navigation, and future prefetch strategies.
The examples workspace member contains the currently supported demos.
cargo run --example skia --features skia -- examples/assets/webgl.pdfOpens the native Skia viewer.cargo run --example femtovg --features femtovgRuns the FemtoVG prototype renderer.cargo xtask emscripten --features skia-wasmBuilds the web target and copies artifacts intoexamples/web/dist/.cargo xtask emscripten --features skia-wasm --serve --port 8080Builds and serves the web example locally.
Feature flags in examples/Cargo.toml:
skia: native Skia viewer withwinitandglutin.skia-wasm: emscripten/web build without the native windowing stack.femtovg: FemtoVG renderer withwgpu.
Sample PDFs for experiments and debugging live in examples/assets/.
Common commands:
cargo test
cargo test -p pdf-parser
cargo test -p pdf-parser -- test_name
cargo check
cargo clippy --all --workspace
cargo fmt
cargo build --example skia --features skia
cargo run --example skia --features skia -- examples/assets/webgl.pdf
cargo xtask emscripten --features skia-wasm
cargo fuzz run parse_objectImportant workspace constraints:
unsafe_codeis forbidden workspace-wide.unwrapandexpectare denied in non-test code.- indexing and slicing are denied by Clippy policy.
- errors are expected to propagate through
Resultrather than panic paths.
These constraints are not cosmetic. They shape the implementation style across the entire repo.
Safe-PDF is licensed under the MIT License. See LICENSE.
The repository also embeds Roboto and Roboto Mono font assets under the SIL Open Font License 1.1. See crates/pdf-font/assets/OFL.txt for details.