PDF‑Inspector ScanStrategy Options Explained: EarlyExit, Full, Sample, and Pages

Use ScanStrategy::EarlyExit for speed on clearly text‑based PDFs, Full for maximum accuracy, Sample(N) for large documents, and Pages(Vec) when you need precise control over which pages to inspect.

The pdf‑inspector crate classifies PDF documents by scanning page content for text operators (Tj/TJ) to determine whether a file is Text‑based, Scanned, or Mixed. The ScanStrategy enum in src/detector.rs controls which pages get examined and whether the detector can stop early—letting you trade speed for classification fidelity.

ScanStrategy Variants and Their Behavior

The ScanStrategy enum is defined at lines 27–40 of src/detector.rs:

pub enum ScanStrategy {
    EarlyExit,           // Scan all pages, stop at first non‑text page
    Full,                // Scan every page regardless
    Sample(u32),         // Scan up to N evenly‑distributed pages
    Pages(Vec<u32>),     // Scan only the specified page numbers (1‑indexed)
}

The core detection logic in detect_from_document (lines 92–101) unpacks each variant into a page list and an early‑exit flag:

let (sample_indices, allow_early_exit) = match &config.strategy {
    ScanStrategy::EarlyExit => ((1..=total_pages).collect::<Vec<_>>(), true),
    ScanStrategy::Full      => ((1..=total_pages).collect::<Vec<_>>(), false),
    ScanStrategy::Sample(max_pages) => {
        let n = (*max_pages).min(total_pages);
        (distribute_pages(n, total_pages), false)
    }
    ScanStrategy::Pages(pages) => (pages.clone(), false),
};

When to Use Each ScanStrategy Option

EarlyExit: Fast Default for Text‑Heavy Pipelines

EarlyExit scans pages sequentially from 1 to N but returns immediately upon finding the first page without text operators. This was the historic default behavior.

  • Best for: High‑throughput pipelines processing mostly clean, text‑based PDFs
  • Trade‑off: May misclassify Mixed PDFs as Scanned if a non‑text cover page appears first
  • Performance: Fastest option when the input is genuinely text‑based

Example: A batch job processing generated reports where you want minimal overhead and can tolerate occasional false negatives.

Full: Complete Accuracy for OCR Decisions

Full examines every page without early termination, building a complete picture of the document's text distribution.

  • Best for: Workflows requiring precise distinctions between Scanned and Mixed PDFs
  • Trade‑off: Slower on large documents, but eliminates sampling uncertainty
  • Performance: Linear with page count; use when downstream OCR costs depend on exact page classification

Example: An invoice processing system where you need to know exactly which pages require OCR versus which can use fast text extraction.

Sample(N): Balanced Approximation for Large Files

ScanStrategy::Sample(N) selects N evenly‑distributed pages across the document using the distribute_pages helper, then scans only those.

  • Best for: Very large PDFs (hundreds or thousands of pages) where full scanning is prohibitively slow
  • Trade‑off: Statistical approximation—accuracy improves with larger N
  • Performance: Bounded by N regardless of document length

The sampling algorithm spreads selections across first, middle, and late pages to capture structural variations (e.g., cover sheets, appendices).

Example: Archival processing of multi‑thousand‑page legal documents where you need a reasonable classification without reading every page.

Pages(Vec): Surgical Precision for Known Content

ScanStrategy::Pages(Vec<u32>) scans only the specific page numbers you provide, using 1‑based indexing.

  • Best for: Callers with prior knowledge of interesting pages
  • Trade‑off: Minimal work, but misses content outside the specified set
  • Performance: Optimal when page relevance is pre‑determined

Example: A UI letting users preview specific pages, or a workflow extracting only cover pages and final signatures for verification.

Practical Code Examples

The DetectionConfig struct carries your chosen strategy into detect_pdf_type_with_config. Here's how to instantiate each variant:

use pdf_inspector::detector::{
    detect_pdf_type_with_config, DetectionConfig, ScanStrategy,
};

fn main() -> Result<(), pdf_inspector::PdfError> {
    let path = "example.pdf";

    // 1️⃣ Early‑exit (fast default)
    let cfg_early = DetectionConfig {
        strategy: ScanStrategy::EarlyExit,
        ..Default::default()
    };
    let res_early = detect_pdf_type_with_config(path, cfg_early)?;
    println!("Early‑exit result: {:?}", res_early.pdf_type);

    // 2️⃣ Full scan (maximum accuracy)
    let cfg_full = DetectionConfig {
        strategy: ScanStrategy::Full,
        ..Default::default()
    };
    let res_full = detect_pdf_type_with_config(path, cfg_full)?;
    println!("Full scan result: {:?}", res_full.pdf_type);

    // 3️⃣ Sample 5 pages (good for large PDFs)
    let cfg_sample = DetectionConfig {
        strategy: ScanStrategy::Sample(5),
        ..Default::default()
    };
    let res_sample = detect_pdf_type_with_config(path, cfg_sample)?;
    println!("Sample‑5 result: {:?}", res_sample.pdf_type);

    // 4️⃣ Custom page list (e.g., only cover & last page)
    let cfg_pages = DetectionConfig {
        strategy: ScanStrategy::Pages(vec![1, 10]),
        ..Default::default()
    };
    let res_pages = detect_pdf_type_with_config(path, cfg_pages)?;
    println!("Pages‑[1,10] result: {:?}", res_pages.pdf_type);

    Ok(())
}

For CLI usage, src/bin/detect_pdf.rs exposes these as --sample N and --pages 1,2,3 flags.

Key Source Files

  • src/detector.rs: Defines ScanStrategy, DetectionConfig, PdfType, and the detect_from_document implementation
  • src/lib.rs: Public API surface with detect_pdf_type_with_config and convenience functions
  • src/bin/detect_pdf.rs: Command‑line interface forwarding flags to DetectionConfig
  • tests/integration_tests.rs: Validation suite ensuring each strategy produces correct OCR recommendations

Summary

  • EarlyExit — fastest for text‑based PDFs; stops at first non‑text page
  • Full — complete accuracy; scans every page to distinguish Scanned from Mixed
  • Sample(N) — scalable approximation for large documents using N distributed pages
  • Pages(Vec) — maximal control; scans only specified pages when relevance is known

Choose based on your document size, required precision, and prior knowledge of page structure.

Frequently Asked Questions

What happens if Sample(N) requests more pages than the document contains?

The detector clamps N to total_pages via (*max_pages).min(total_pages) in src/detector.rs line 97, then distributes all available pages. No error occurs—Sample(100) on a 5‑page PDF simply scans all 5 pages.

Can EarlyExit and Full return different PdfType results for the same file?

Yes. EarlyExit may classify a Mixed PDF as Scanned if page 1 lacks text, while Full would correctly identify it as Mixed after finding text on later pages. Use Full when this distinction matters for downstream OCR costs.

How does the distribute_pages function select pages for Sample(N)?

The implementation spreads selections evenly across the document range, typically including first and last pages plus interior pages at calculated intervals. This captures structural patterns (covers, headers, content bodies) better than random sampling.

Is ScanStrategy configurable when using the CLI binary?

Yes. The detect_pdf binary in src/bin/detect_pdf.rs accepts --sample N for Sample(N) and --pages 1,3,5 for Pages. Without flags, it defaults to EarlyExit behavior for backward compatibility.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →