oxidizePdf
App Listed
Pure Rust PDF library for AI/RAG: structure-aware chunking, no ML, no C deps.
- Downloads
- 62,285
- Dependents
- Not applicable
- Stars
- 194
- Forks
- 28
- Contributors
- 12
- Commits
- 2,135
- Latest release
- 5.5.7 ·
About
Documentation · Context7 · Documentation publishing and indexing
A comprehensive PDF toolkit written in pure Rust. Generate, parse, modify, extract and validate PDFs without C bindings. Use one crate for ordinary PDF workflows or continue into structure-aware chunks for AI/RAG applications.
| I need to… | Start here |
|---|---|
| Generate PDFs with text, graphics, images and tables | Document |
| Parse PDFs and extract text | PdfDocument |
| Split, merge, rotate or reorder pages | operations |
| Validate PDF/A or inspect signatures | PDF/A validation and signatures |
| Build an AI/RAG ingestion pipeline | rag_chunks |
[dependencies]
oxidize-pdf = "5.5.7"
Structure-aware RAG remains a first-class workflow:
let chunks = PdfDocument::open("paper.pdf")?.rag_chunks()?;
// Each chunk: text, pages, bounding boxes, element types, heading context, token estimate
Read the full README
Why oxidize-pdf?
- One toolkit: generation, parsing, manipulation, extraction and validation.
- Pure Rust deployment: PDF processing and certificate verification use Rust implementations without a native crypto library. See the dependency gate and architecture for supported builds, platform interfaces and the optional Tesseract integration.
- AI-ready when needed: page references, bounding boxes, element types, heading context and token estimates are available from the same parser.
- Explicit scope: page rasterization is not provided; use a renderer such as Pdfium when bitmap output is required.
- Auditable capability claims: the claims inventory records the source, version, verification evidence and limits for the supported PDF/A, signature and enterprise-scope statements.
Structure-aware RAG
Most PDF libraries give you a wall of text. oxidize-pdf gives you structured, metadata-rich chunks ready for your vector store:
| What you get | Why it matters |
|---|---|
chunk.full_text | Heading context prepended -- better embeddings |
chunk.page_numbers | Citation back to source pages |
chunk.bounding_boxes | Spatial position for visual grounding |
chunk.element_types | Filter by "table", "title", "paragraph" |
chunk.token_estimate | Right-size chunks for your model's context window |
chunk.heading_context | Section awareness without post-processing |
Measured generation: 6,311 one-page documents/sec and 732 ten-page reports/sec (medians, oxidize-pdf 5.1.5, synthetic text-only workloads on an Intel i7-3770). See the protocol, environment and comparison.
Quick Start
[dependencies]
oxidize-pdf = "5.5.7"
RAG Pipeline
use oxidize_pdf::parser::PdfDocument;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let doc = PdfDocument::open("document.pdf")?;
// Structure-aware chunking with full metadata
let chunks = doc.rag_chunks()?;
for chunk in &chunks {
println!("Chunk {}: pages {:?}, ~{} tokens",
chunk.chunk_index, chunk.page_numbers, chunk.token_estimate);
println!(" Types: {}", chunk.element_types.join(", "));
if let Some(heading) = &chunk.heading_context {
println!(" Section: {}", heading);
}
// Use chunk.full_text for embeddings (includes heading context)
// Use chunk.text for display (content only)
}
Ok(())
}
Custom Chunk Size
use oxidize_pdf::pipeline::HybridChunkConfig;
// Smaller chunks for more precise retrieval
let config = HybridChunkConfig {
max_tokens: 256,
..HybridChunkConfig::default()
};
let chunks = doc.rag_chunks_with(config)?;
Contextual Retrieval (no-ML)
Prepend a deterministic context snippet to each chunk's full_text before
embedding — the no-ML analogue of Contextual Retrieval
/ Late Chunking, which cut retrieval failures substantially by situating each
chunk in its document. No LLM, no GPU: the prefix is a pure function of the
document metadata and the chunk's heading breadcrumb, so it is fully
reproducible (stable chunk_id). The display text field stays context-free.
use oxidize_pdf::pipeline::{ContextFormat, ContextMode, DocumentSource, HybridChunkConfig};
let config = HybridChunkConfig {
context_mode: ContextMode::Contextual(ContextFormat::Labeled),
..HybridChunkConfig::default()
};
let source = DocumentSource::with_file(Some("annual.pdf".into()), Some("sha256-…".into()));
let chunks = doc.rag_chunks_with_source_and_config(source, config)?;
// chunk.full_text now reads, e.g.:
// Document: Annual Report — Acme Corp
// Section: 1 Introduction › 1.2 Scope (p. 3–4)
//
// <chunk text>
ContextFormat::Prose renders the same facts as one natural-language sentence.
Modes: ContextMode::None (bare text), Heading (leaf heading only, the
default), Contextual(_) (document + section prefix).
JSON for Vector Store Ingestion
// Serialize all chunks to JSON (requires `semantic` feature)
let json = doc.rag_chunks_json()?;
std::fs::write("chunks.json", json)?;
Element Partitioning
For fine-grained control, access the typed element pipeline directly:
use oxidize_pdf::pipeline::ExtractionProfile;
let doc = PdfDocument::open("document.pdf")?;
// Partition into typed elements
let elements = doc.partition()?;
for el in &elements {
println!("page {} : {}", el.page(), el.text());
}
// Or with a pre-configured profile
let elements = doc.partition_with_profile(ExtractionProfile::Academic)?;
// Build a relationship graph (parent/child sections)
let (elements, graph) = doc.partition_graph(Default::default())?;
for section in graph.top_level_sections() {
println!("Section: {}", elements[section].text());
}
Also in the box
Beyond RAG, the same crate also handles PDF parsing (99.3 % success on 9,000+ real-world PDFs, CJK, lenient recovery), generation (see the measured workloads below), encryption (RC4-40/128, AES-128, AES-256 R5 — read and write; AES-256 R6 — read), digital signatures (detection, PKCS#7 verification, certificate validation and incremental-signature preparation), PDF/A validation (8 conformance levels), JBIG2 image decoding (pure-Rust ITU-T T.88), invoice extraction (ES/EN/DE/IT), and split/merge/rotate operations. One dependency for the full pipeline.
Signature preparation is not a completed cryptographic signature: an external signer produces CMS and finalization embeds it. PAdES is outside the scope of oxidize-pdf. Anyone can implement it as an independent external extension using the existing signing interfaces, without incorporating it into this library. The extension author is responsible for implementing and validating the chosen profile, including timestamps and long-term validation data where required. Embedding CMS alone does not establish profile compliance or certification. See the operation-level signature contract.
Version 5.2.0 rejects simulated public-key operations and malformed Flate/predictor data, adds explicit recovery diagnostics, and makes build identification optional. See the versioned inventory and migration guides for the exact behavior and remaining limits.
Certificate-based recipient encryption is unsupported. The legacy
PublicKeySecurityHandler returns explicit errors for cryptographic operations;
certificate verification for signatures is separate. See the
support and migration boundary.
See oxidize-pdf-core/examples/ for working samples (133 examples) and docs.rs for the API surface.
Full Feature Set
AI/RAG Pipeline
- Structure-aware chunking with
RagChunkmetadata (pages, bboxes, types, headings) - Element partitioning: Title, Paragraph, Table, ListItem, Image, CodeBlock, KeyValue
ElementGraphfor parent/child section relationships- 6 extraction profiles (Standard, Academic, Form, Government, Dense, Presentation)
- Reading order strategies (Simple, XYCut)
- LLM-optimized export formats (Markdown, Contextual, JSON)
- Invoice data extraction (ES, EN, DE, IT)
PDF Processing
- Parse PDF 1.0-1.7 with 99.3% success rate (9,000+ PDFs tested)
- Generate multi-page documents with text, graphics, images
- Encryption: RC4-40/128, AES-128, AES-256 R5 -- read and write; AES-256 R6 -- read
- Digital signatures: detection, PKCS#7 verification, certificate validation, incremental-signature preparation
- PDF/A validation: 8 conformance levels (1a/b, 2a/b/u, 3a/b/u)
- JBIG2 decoder: pure Rust (ITU-T T.88)
- Split, merge, rotate operations
- CJK text support (Chinese, Japanese, Korean)
- Corruption recovery and lenient parsing
- Decompression bomb protection
Performance
Measured with oxidize-stats pdf-generation-v1 on 2026-09-28: oxidize-pdf 5.1.5,
Intel Core i7-3770 @ 3.40 GHz, Linux x86_64, Rust 1.96.0 release build. Twenty
samples per workload; construction and serialization to memory, without file IO.
| Synthetic text-only workload | Documents per sample | Median documents/sec | p95 batch-average ms/document | Maximum process RSS |
|---|---|---|---|---|
| One-page invoice-like document | 1,000 | 6,311 | 0.197 | 5.0 MiB |
| Ten-page report | 100 | 732 | 1.587 | 5.4 MiB |
The p95 describes batch averages, not individual-request tail latency. RSS includes runtime and warmup, not just PDF allocation. Each sample's representative PDF was checked independently for structure, page count and exact text. This shared-host measurement does not establish performance for images, embedded fonts or arbitrary real-world documents. The comparison now includes pdf_oxide 0.3.78 alongside lopdf, pdf-writer and printpdf. All four have higher median throughput in these workloads, but the one-page uncertainty intervals of oxidize-pdf and pdf_oxide overlap. Serialization defaults and output sizes differ. See the full comparison and reproducible protocol.
Testing
7,993 tests across unit, integration, and doc tests. 7-tier corpus (T0-T6) with 9,000+ PDFs.
cargo test --workspace # Full test suite
cargo clippy -- -D warnings # Lint check
cargo run --example rag_pipeline -- path/to/file.pdf
License
MIT -- see LICENSE.
Links
Compatibility
- Runs on
- GPU support unknown
What shows it
- no dependency or feature matches a backend row
- Native code
- None found
- No native code found
- Python bindings
- No Python binding crate found
- License
- MIT
Compare with similar projects
Order: strongest tier first, then most downloads, then name, with unmeasured values last. A library counts downloads over 30 days. An app counts binary downloads per release. An app with none counts its crate downloads over 30 days. ML Rust runs this catalogue, so its closest project always gets a row.
| Project | Downloads | Dependents | Stars | Latest release | Runs on (GPU) | Native code | License |
|---|---|---|---|---|---|---|---|
|
Pure Rust PDF library for AI/RAG: structure-aware chunking, no ML, no C deps. |
62,285 downloads over 30 days | Not applicable | 194 | 5.5.7 | GPU support unknown | No native code found | MIT |
|
pdf_oxide Featured
The fastest Rust PDF library — 0.8ms mean, 5× faster than the industry leaders, 100% pass rate on 3,830 real-world PDFs. Text extraction, Markdown/HTML conversion, PDF creation and editing. Python bindings Also in Build LLM apps and agents. |
316,729 downloads over 30 days | 30 | 1,180 | 0.3.78 | GPU support unknown | Binds native code: aws-lc-rs (feature fips), lcms2-sys (feature icc-lcms2), ort-sys (feature gpu) | Apache-2.0 OR MIT |
|
toon-rust Featured
Token-Oriented Object Notation (TOON) - a token-efficient JSON alternative for LLM prompts Also in Build LLM apps and agents. |
160,383 downloads over 30 days | 67 | 190 | 0.7.0 | GPU support unknown | No native code found | MIT |
|
kreuzberg-lts Listed
High-performance document intelligence library for Rust. Extract text, metadata, and structured data from PDFs, Office documents, images, and 91+ formats and 248 programming languages via tree-sitter code intelligence with async/sync APIs. Also in Documents and OCR. |
54,366 downloads over 30 days | 7 | 21 | 4.10.4 | GPU support unknown | Binds native code: kreuzberg_tesseract, clipper-sys, ort-sys, tree-sitter (feature tree-sitter), tree-sitter-language (feature tree-sitter). Build uses a native toolchain: pkg-config, cc (feature build-tesseract), cmake (feature build-tesseract) | MIT |
|
edgeparse Listed
EdgeParse core library — PDF parsing and structured data extraction Also in Build LLM apps and agents. |
6,764 downloads over 30 days | 2 | 155 | 0.3.2 | GPU support unknown | No native code found | Apache-2.0 |
|
Extractous provides a fast and efficient way to extract content from all kind of file formats including PDF, Word, Excel CSV, Email etc... Internally it uses a natively compiled Apache Tika for formats are not supported natively by the Rust core Also in Documents and OCR. |
1,515 downloads over 30 days | 3 | 1,787 | 0.3.0 | GPU support unknown | No native code found | Apache-2.0 |
|
Inference server for LLMs, speech and embeddings: OpenAI-compatible routes with streaming, plus speech synthesis (TTS) and transcription (ASR). Serves Llama, Mistral, Qwen, Mamba2, MLA+MoE and hybrid models from SafeTensors, AWQ, GPTQ and GGUF. Also in Build LLM apps and agents. |
8 binary downloads per release | Not applicable | 7 | 0.7.1 | CUDA, WebGPU | Binds native code: ring (feature distributed) | Apache-2.0 |
All projects in Build LLM apps and agentsAll projects in Documents and OCR
Why ListedNo archive, New or Featured rule places it, so it is Listed.
What it lacks for Featured
- The check holds no value for Homebrew installs on request over 365 days, Repology repository families, Docker pull growth over 90 days. A gate that lacks its signal does not pass.
What else the check found
- The last activity is on 6 Nov 2026, 3 days ago. The rules expect an update within 365 days. Dormancy rule
Not measured: Homebrew installs on request over 365 days, Repology repository families, Docker pull growth over 90 days.
Exact rules: Listed, Featured app. The check on applied thresholds version 9.
Every rule outcome, as the check records it
expected-interval: app: E = 365 daysdormancy: last activity 2026-11-06, 3 days ago, E = 365: activefeatured: not featured: unknown homebrew_on_request_365d, repology_families, docker_pull_growth_90dlisted: listed: no archive, new or featured rule applies
Crates2 crates
- oxidize-pdf Primary
- oxidize-pdf-cli
Measurements and sources
Each signal row shows the raw value, its source and the fetch date. The Sources list gathers every distinct source on this page. Movement needs more history.
Sources6 sources
- Description: the GitHub repository description
- crates.io database dump, fetched
- GitHub releases, fetched
- GitHub repository, fetched
- crates.io package, fetched
- GitHub contributors, fetched
Adoption0 binary downloads per release4 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Active dependents | Not measured | Yes | ||
| New dependents (365 days) | Not measured | Yes | ||
| Peak active dependents | Not measured | Yes | ||
| Active dependents as a share of the peak | Not measured | Yes | ||
| Binary downloads per release | 0 | GitHub releases | Yes |
MaintenanceLatest human commit: 3 days ago4 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Latest human commit | 2026-11-06 | GitHub repository | Yes | |
| Latest release | 2026-11-06 | GitHub releases | Yes | |
| First release | 2025-07-10 | crates.io database dump | Yes | |
| Latest version | 5.5.7 | crates.io database dump | No | |
| Days the oldest outside issue waits for a reply | 6 | GitHub repository | Yes | |
| Maintainer replies over 365 days | 2 | GitHub repository | Yes | |
| Repository archived | false | GitHub repository | Yes | |
| Repository gone | false | GitHub repository | Yes | |
| Release commit or manifest in the repo | true | crates.io package | No | |
| Published docs | Not measured | Yes | ||
| Latest release fails cargo check | Not measured | Yes | ||
| Build check date | Not measured | Yes | ||
| Build check toolchain | Not measured | Yes |
SecurityNot measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Unpatched vulnerabilities past the grace window | Not measured | Yes | ||
| RustSec unmaintained advisory | Not measured | Yes | ||
| Deprecation notice | Not measured | Yes | ||
| Deprecated requirement | Not measured | Yes |
Distribution125 releases, 62,285 downloads over 30 days6 not measured
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| Releases | 125 | crates.io database dump | No | |
| Downloads over 30 days | 62285 | crates.io database dump | No | |
| Binary downloads over the last 3 releases | 0 | GitHub releases | Yes | |
| Homebrew installs on request over 365 days | Not measured | Yes | ||
| Repology repository families | Not measured | Yes | ||
| Docker pull growth over 90 days | Not measured | Yes | ||
| Docker pulls at the growth baseline | Not measured | Yes | ||
| Every version a prerelease | false | crates.io database dump | Yes | |
| Every version 0.0.x | false | crates.io database dump | Yes | |
| Every version yanked | Not measured | Yes | ||
| Crate deleted from crates.io | Not measured | Yes |
Repository194 stars, 28 forks, 12 contributors, 2,135 commits. Stars alone never qualify a project.
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| GitHub stars | 194 | GitHub repository | Yes — one part of the repository route | |
| GitHub forks | 28 | GitHub repository | Yes — one part of the repository route | |
| Contributors with a GitHub account | 12 | GitHub contributors | Yes — one part of the repository route | |
| Commits on the default branch | 2135 | GitHub repository | No | |
| Repository's main crate left out of the entry | none | crates.io database dump | Yes |
Facts that never count
| Signal | Value | Source | Fetched | Counts |
|---|---|---|---|---|
| License | MIT | crates.io database dump | No | |
| Runs on, from listed crates and their direct dependencies | GPU support unknown | crates.io database dump | No | |
| What shows each backend | no dependency or feature matches a backend row | crates.io database dump | No | |
| Native code, from listed crates and their dependencies | No native code found | crates.io database dump | No | |
| Python bindings, from direct dependencies of listed crates | No Python binding crate found | crates.io database dump | No | |
| Crates that depend on a listed crate directly | Not measured | No |
Corrections and review history
No correction applies to this entry.
Judgments
A judgment enters only through an approved issue and a merged pull request.
No judgment applies to this entry.