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

> Explore pdf-inspector ScanStrategy options: EarlyExit, Full, Sample, and Pages. Choose the best strategy for speed, accuracy, or page control in your PDF analysis.

- Repository: [Firecrawl/pdf-inspector](https://github.com/firecrawl/pdf-inspector)
- Tags: deep-dive
- Published: 2026-08-14

---

**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`](https://github.com/firecrawl/pdf-inspector/blob/main/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`](https://github.com/firecrawl/pdf-inspector/blob/main/src/detector.rs)**:

```rust
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:

```rust
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<u32>): 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:

```rust
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`](https://github.com/firecrawl/pdf-inspector/blob/main/src/bin/detect_pdf.rs) exposes these as `--sample N` and `--pages 1,2,3` flags.

## Key Source Files

- **[`src/detector.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/detector.rs)**: Defines `ScanStrategy`, `DetectionConfig`, `PdfType`, and the `detect_from_document` implementation
- **[`src/lib.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/lib.rs)**: Public API surface with `detect_pdf_type_with_config` and convenience functions
- **[`src/bin/detect_pdf.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/bin/detect_pdf.rs)**: Command‑line interface forwarding flags to `DetectionConfig`
- **[`tests/integration_tests.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/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`](https://github.com/firecrawl/pdf-inspector/blob/main/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`](https://github.com/firecrawl/pdf-inspector/blob/main/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.