How pdf-inspector Classifies PDFs: Architecture, Configuration, and Code Examples
pdf-inspector determines whether a PDF is TextBased, Scanned, ImageBased, or Mixed by sampling pages and counting text operators, without loading the entire document.
The pdf-inspector library from Firecrawl provides fast, lightweight PDF classification for high-throughput pipelines. This article explains precisely how the classification system works based on the source code implementation, with runnable examples you can adapt immediately.
Core Detection Architecture
The classification logic lives primarily in src/detector.rs, which exposes two main entry points:
detect_pdf_type(path)– runs detection with default configurationdetect_pdf_type_with_config(path, config)– allows custom scan strategies and thresholds
Both functions return a PdfTypeResult containing the classification, confidence metrics, and OCR recommendations. The implementation avoids full document parsing by using page sampling heuristics [source lines 92-100].
Scan Strategy: Four Modes for Speed vs. Accuracy
The ScanStrategy enum defines how pages are inspected [source lines 25-40]:
| Strategy | Behavior | Best For |
|---|---|---|
EarlyExit |
Stop at first non-text page | Fast rejection of scanned documents |
Full |
Inspect every single page | Maximum accuracy, slower processing |
Sample(N) |
Check N evenly-distributed pages (default: 8) | Balanced speed and precision |
Pages(vec) |
Only check user-specified page numbers | Targeted analysis |
The default Sample(8) strategy provides optimal throughput for most use cases while maintaining reliable classification accuracy.
Per-Page Text Detection
For each selected page, pdf-inspector parses the PDF content stream using lopdf and counts text operators (Tj and TJ). A page qualifies as text-rich when the count exceeds min_text_ops_per_page (default: 3) [source lines 73-76].
This operator-based approach is more reliable than simple font detection because it directly measures actual text rendering commands in the content stream.
Classification Rules and Thresholds
After sampling, the detector builds aggregate metrics in PdfTypeResult [source lines 44-66]:
total_pages– document page countpages_sampled– pages actually inspectedpages_with_text– pages exceeding text operator thresholdconfidence– calculated reliability of the classificationocr_recommended– boolean flag for downstream processingpages_needing_ocr– specific page numbers requiring OCR
The final PDF type derives from the ratio pages_with_text / total_pages compared against text_page_ratio_threshold (default: 0.6):
- TextBased – ratio ≥ 0.6
- Scanned – ratio = 0 (no text operators found)
- Mixed – ratio between 0 and threshold (partial text)
- ImageBased – very low ratio with high image page count
OCR Recommendation System
When pages lack sufficient text operators, pdf-inspector sets ocr_recommended = true and records specific page numbers in pages_needing_ocr. This enables downstream pipelines to invoke OCR only where necessary, avoiding expensive full-document processing.
Code Examples
Basic PDF Classification with Defaults
use pdf_inspector::detector::{detect_pdf_type, PdfType};
fn main() -> Result<(), pdf_inspector::PdfError> {
let result = detect_pdf_type("example.pdf")?;
println!("PDF type: {:?}", result.pdf_type);
if result.ocr_recommended {
println!("OCR needed on pages: {:?}", result.pages_needing_ocr);
}
Ok(())
}
Custom Configuration for Maximum Accuracy
use pdf_inspector::detector::{
detect_pdf_type_with_config, DetectionConfig, ScanStrategy, PdfType,
};
fn main() -> Result<(), pdf_inspector::PdfError> {
let cfg = DetectionConfig {
strategy: ScanStrategy::Full,
min_text_ops_per_page: 5,
text_page_ratio_threshold: 0.7,
};
let result = detect_pdf_type_with_config("large.pdf", cfg)?;
println!("Detected type: {:?}", result.pdf_type);
Ok(())
}
Command-Line Usage
# Output structured JSON for pipeline integration
detect-pdf --json path/to/document.pdf
Key Source Files
| File | Purpose | Link |
|---|---|---|
src/detector.rs |
Core detection logic, ScanStrategy, DetectionConfig, PdfTypeResult |
view |
src/lib.rs |
Public API re-exports for library consumers | view |
src/bin/detect_pdf.rs |
CLI binary with --json flag support |
view |
src/extractor/content_stream.rs |
Content stream parser, text operator counting | view |
src/extractor/mod.rs |
Low-level PDF object handling coordination | view |
Summary
- pdf-inspector classifies PDFs using lightweight page sampling rather than full document loading
ScanStrategyoffers four modes fromEarlyExittoFullscans, withSample(8)as the balanced default- Classification relies on counting
Tj/TJtext operators in content streams, with configurable thresholds - The system returns detailed
PdfTypeResultmetrics including per-page OCR recommendations - All detection logic resides in
src/detector.rswith clear separation between configuration, sampling, and classification phases
Frequently Asked Questions
How accurate is pdf-inspector's classification compared to OCR-based approaches?
pdf-inspector achieves high accuracy for document routing decisions while being orders of magnitude faster than OCR. The default Sample(8) strategy correctly identifies document types in typical scenarios because text-rich pages distribute evenly in most PDFs. For critical applications requiring certainty, switch to ScanStrategy::Full to inspect every page.
Can I customize what counts as a "text-rich" page?
Yes. The DetectionConfig struct exposes min_text_ops_per_page to adjust the text operator threshold. Increase this value for documents with heavy header/footer metadata you want to ignore, or decrease it for documents with sparse text layouts.
What happens if a PDF contains both scanned and text-based pages?
The classifier returns Mixed when the text page ratio falls between 0 and the threshold (default 0.6). The pages_needing_ocr field specifically identifies which pages lack sufficient text operators, enabling targeted OCR rather than processing the entire document.
Is pdf-inspector suitable for real-time document processing pipelines?
Absolutely. The design prioritizes speed through lazy page sampling and avoids full document materialization. According to the firecrawl/pdf-inspector source code, even ScanStrategy::Full processes only content streams rather than rendering pages, maintaining throughput suitable for high-volume automated systems.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →