pdftract/docs/user-docs/src/sdk/rust.md
jedarden 39ca6a3552 feat(pdftract-2b7ff): implement image_coverage_fraction signal evaluator
Add image_coverage_fraction signal evaluator that computes the union
image coverage fraction from individual image XObject areas.

- Computes total image coverage as sum of image_xobject_areas
- Divides by page area (width * height) to get coverage fraction
- Clamps to [0.0, 1.0] to handle overlapping images (defensive)
- Returns Some(Vote::scanned(0.85)) if fraction > 0.85

Implementation uses sum for simplicity (overestimates coverage when
images overlap), which is acceptable for the 0.85 threshold as it's
a conservative signal. Can be revisited with Klee's algorithm for
greater accuracy if needed.

Acceptance criteria PASS:
✓ Page with one image covering 90% area → Some(Vote { 0.85, Scanned })
✓ Page with multiple small images totaling 50% → None (below threshold)
✓ Page with no images → None
✓ Coverage clamped to 1.0 on overlapping images

Also includes pre-existing infrastructure:
- tr3_op_count field in PageContext
- image_xobject_areas field in PageContext
- all_tr3_with_full_page_image function
- CharDensityRatioSignal evaluator

These were necessary dependencies for the new evaluator to function.

Refs: Plan section Phase 5.1.2, coordinator pdftract-22p
2026-05-31 23:42:38 -04:00

5.2 KiB

Rust SDK

The Rust SDK is the pdftract-core crate. It provides native PDF text extraction with zero-copy memory mapping and streaming support.

Installation

Add to your Cargo.toml:

[dependencies]
pdftract-core = "1.0"

For OCR support, enable the ocr feature:

[dependencies]
pdftract-core = { version = "1.0", features = ["ocr"] }

Basic Extraction

use pdftract_core::{extract, ExtractionOptions};

fn main() -> anyhow::Result<()> {
    let opts = ExtractionOptions::default();
    let result = extract("document.pdf", &opts)?;

    for (i, page) in result.pages.iter().enumerate() {
        println!("Page {}: {} spans", i + 1, page.spans.len());
        for span in &page.spans {
            println!("  {}", span.text);
        }
    }
    Ok(())
}

Streaming Extraction

For large PDFs, stream pages one at a time to keep memory usage bounded:

use pdftract_core::{extract_stream, ExtractionOptions};
use std::path::Path;

fn main() -> anyhow::Result<()> {
    let opts = ExtractionOptions::default();
    let pages = extract_stream(Path::new("large_document.pdf"), &opts)?;

    for page_result in pages {
        let page = page_result?;
        println!("Page {}: {} spans", page.index, page.spans.len());
    }
    Ok(())
}

Options

ExtractionOptions

Field Type Default Use Case
receipts ReceiptsMode Off Generate cryptographic receipts
max_parallel_pages usize 4 Control memory for concurrent page processing
memory_budget_mb usize 512 Target peak RSS in MB
full_render bool false Enable PDFium rendering (requires full-render feature)
ocr_dpi_override Option<u32> None Override automatic DPI selection
ocr_language Vec<String> vec!["eng"] Tesseract language codes
markdown_anchors bool false Emit HTML comment anchors in Markdown
max_decompress_bytes u64 512 MiB Bomb limit for decompressed streams
output OutputOptions default() Output filtering options
pages Option<String> None Page range (e.g., "1-5,7,12-")
password Option<SecretString> None PDF password for encrypted documents

OutputOptions

Field Type Default Use Case
include_invisible bool false Include invisible text in output
extract_forms bool true Extract AcroForm fields
extract_attachments bool true Extract embedded attachments

Receipts

Generate cryptographic receipts for verification:

use pdftract_core::{extract, ExtractionOptions};
use pdftract_core::options::ReceiptsMode;

fn main() -> anyhow::Result<()> {
    let opts = ExtractionOptions {
        receipts: ReceiptsMode::Lite,
        ..Default::default()
    };
    let result = extract("document.pdf", &opts)?;

    // Receipts are embedded in page metadata
    if let Some(receipt) = &result.pages[0].receipt {
        println!("Receipt: {}", receipt);
    }
    Ok(())
}

Remote PDFs

With the remote feature, fetch PDFs via HTTP:

use pdftract_core::{extract, ExtractionOptions};
use std::path::Path;

fn main() -> anyhow::Result<()> {
    let opts = ExtractionOptions::default();
    let result = extract(Path::new("https://example.com/document.pdf"), &opts)?;
    Ok(())
}

Error Handling

Most functions return anyhow::Result<T> which wraps various error types:

use pdftract_core::{extract, ExtractionOptions};
use std::path::Path;

fn main() {
    let opts = ExtractionOptions::default();

    match extract(Path::new("document.pdf"), &opts) {
        Ok(result) => {
            println!("Extracted {} pages", result.pages.len());
        }
        Err(e) => {
            eprintln!("Extraction failed: {}", e);
            // Inspect error chain
            for cause in e.chain() {
                eprintln!("  caused by: {}", cause);
            }
        }
    }
}

Feature Flags

Feature Adds Default
serde JSON serialization support
decrypt Decryption of encrypted PDFs
quick-xml Conformance detection via XML metadata
ocr Tesseract OCR for scanned documents -
full-render PDFium-based rendering (requires ocr) -
remote HTTP range fetching for remote PDFs -
profiles Extraction profiles -
receipts Cryptographic receipt generation -
cjk CJK text extraction via predefined CMap registry -
schemars JSON Schema generation -

Source Types

The SDK supports multiple source types via the PdfSource trait:

use pdftract_core::source::{FileSource, MmapSource, MemorySource};

// Memory-mapped source (zero-copy for large files)
let source = MmapSource::open("document.pdf")?;

// In-memory source (for byte buffers)
let data = std::fs::read("document.pdf")?;
let source = MemorySource::new(data);

// Standard file source
let source = FileSource::open("document.pdf")?;

See Also