How to Change the PDF Classification Strategy in pdf-inspector: A Complete Guide

You can change the PDF classification strategy in pdf-inspector by creating a custom DetectionConfig with your desired ScanStrategy variant and passing it to detect_pdf_type_with_config().

The pdf-inspector repository by Firecrawl provides Rust-based PDF analysis that classifies documents into four types: TextBased, Scanned, ImageBased, or Mixed. The classification behavior is controlled through configurable scanning strategies that trade speed for accuracy. This article explains how to customize these strategies using the detector API exported from src/detector.rs.


Understanding the Classification Workflow

Before changing strategies, it helps to understand how pdf-inspector analyzes documents. The detection pipeline runs through six distinct phases as implemented in src/detector.rs:

  1. Document loading – detect_pdf_type() opens the PDF via lopdf::Document
  2. Page selection – The ScanStrategy resolves to specific page indices and an allow_early_exit flag
  3. Per-page analysis – analyze_page_content() extracts text operators, image counts, vector-text flags, and font decodability signals
  4. Signal aggregation – Ratios like text_ratio (text pages ÷ sampled pages) are computed
  5. Heuristic classification – Rules in detect_from_document() (lines 101–134) determine the final PdfType
  6. Optional refinement phases – Newspaper layout detection and per-page OCR recommendations

The ScanStrategy you choose directly affects step 2, controlling which pages contribute to the aggregated signals.


The Four ScanStrategy Variants

The ScanStrategy enum in src/detector.rs defines four approaches for page sampling:

Variant Behavior Best For
EarlyExit Scan sequentially, stop at first non-text page Fast routing of clearly TextBased documents
Full Analyze every page, never exit early Maximum accuracy for Mixed vs. Scanned discrimination
Sample(u32) Scan N evenly distributed pages (first, last, middle) Large PDFs where speed outweighs perfection
Pages(Vec<u32>) Scan exact page numbers you specify Deterministic testing or metadata-driven selection

The default configuration uses Sample(8) as defined near line 84 in src/detector.rs.


Changing the Strategy in Rust Code

To override the default strategy, construct a DetectionConfig and pass it to detect_pdf_type_with_config().

Example 1: Full Scan for Maximum Accuracy

Use ScanStrategy::Full when you cannot afford misclassification on documents with text-only covers followed by scanned content:

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

fn main() -> Result<(), pdf_inspector::PdfError> {
    let cfg = DetectionConfig {
        strategy: ScanStrategy::Full,
        ..Default::default()
    };
    let result = detect_pdf_type_with_config("example.pdf", cfg)?;
    println!("PDF type: {:?}, confidence: {}", result.pdf_type, result.confidence);
    Ok(())
}

Example 2: Sample 4 Pages for Large Documents

Reduce runtime on hundred-page PDFs by sampling just 4 representative pages:

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

fn main() -> Result<(), pdf_inspector::PdfError> {
    let cfg = DetectionConfig {
        strategy: ScanStrategy::Sample(4),
        ..Default::default()
    };
    let result = detect_pdf_type_with_config("big.pdf", cfg)?;
    println!("Detected as {:?} ({}% confidence)", result.pdf_type, result.confidence * 100.0);
    Ok(())
}

Example 3: Specific Pages Only

Pass exact page numbers when external metadata (like a table of contents) indicates relevant sections:

let cfg = DetectionConfig {
    strategy: ScanStrategy::Pages(vec![1, 2, 3, 4, 5]),
    ..Default::default()
};
let result = detect_pdf_type_with_config("document.pdf", cfg)?;

Adjusting Classification Thresholds

Beyond page selection, DetectionConfig exposes thresholds that affect heuristics in lines 101–134 of src/detector.rs:

Field Default Purpose When to Change
min_text_ops_per_page Minimum PDF text operators to count a page as "having text" Raise for stricter TextBased classification
text_page_ratio_threshold Proportion of text pages required for TextBased result Raise to reduce false TextBased positives

Example 4: Strict TextBased Requirements

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

fn main() -> Result<(), pdf_inspector::PdfError> {
    let cfg = DetectionConfig {
        strategy: ScanStrategy::Sample(8),
        min_text_ops_per_page: 7,       // default is lower; requires more text operators
        text_page_ratio_threshold: 0.8, // default is 0.7; demands 80% text pages
        ..Default::default()
    };
    let result = detect_pdf_type_with_config("strict.pdf", cfg)?;
    println!("Result: {:?}", result);
    Ok(())
}

CLI Integration Notes

The detect_pdf binary in src/bin/detect_pdf.rs serves as the command-line interface. It constructs a DetectionConfig from parsed arguments and forwards it to detect_pdf_type_with_config().

To add a new CLI flag like --full-scan, modify src/bin/detect_pdf.rs to:

  1. Parse the flag from arguments
  2. Build DetectionConfig { strategy: ScanStrategy::Full, ..Default::default() }
  3. Pass that config to the detector function

No changes to src/detector.rs are required for basic strategy switching via CLI.


Key Source Files for Customization

File Role Key Locations
src/detector.rs Core detection logic, DetectionConfig, ScanStrategy, PdfType enum Definitions from line 12; strategy handling at lines 92–110; classification rules at lines 101–134
src/bin/detect_pdf.rs CLI entry point Arguments parsed here, config constructed, detect_pdf_type_with_config invoked
src/lib.rs Public API exports Re-exports detector functions for library consumers
src/extractor/ Content stream analysis analyze_page_content() feeds signals to the detector

Summary

  • pdf-inspector classifies PDFs via configurable ScanStrategy variants in src/detector.rs
  • Four strategies exist: EarlyExit, Full, Sample(N), and Pages(Vec<u32>)
  • Default is Sample(8) — override via DetectionConfig passed to detect_pdf_type_with_config()
  • Threshold fields (min_text_ops_per_page, text_page_ratio_threshold) fine-tune heuristics without code changes to classification rules
  • CLI customization requires modifying src/bin/detect_pdf.rs to construct and forward custom configs

Frequently Asked Questions

What is the fastest PDF classification strategy in pdf-inspector?

ScanStrategy::EarlyExit is fastest for documents that start with text pages, as it stops at the first non-text page. For documents known to be large and mixed, ScanStrategy::Sample(4) provides predictable, bounded runtime regardless of content distribution.

When should I use Full scanning instead of the default Sample strategy?

Use ScanStrategy::Full when your pipeline cannot tolerate false TextBased classifications on documents with text covers followed by scanned interiors. The default Sample(8) may miss late-occurring scanned pages in very long PDFs.

Can I change classification thresholds without modifying the source code?

Yes, through DetectionConfig fields. Adjust min_text_ops_per_page to require more text operators before counting a page as textual, or raise text_page_ratio_threshold above 0.7 to demand a higher proportion of text pages for TextBased results. These apply regardless of which ScanStrategy you select.

How do I specify exact pages to analyze for classification?

Use ScanStrategy::Pages(Vec<u32>) with 1-indexed page numbers. This bypasses all sampling logic in lines 92–110 of src/detector.rs and analyzes only your specified pages, giving you deterministic, reproducible classification behavior ideal for testing or metadata-driven workflows.

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 →