How Tiled-Scan Detection Identifies JBIG2 and Strip-Image PDFs in PDF Inspector

Tiled-scan detection identifies JBIG2 and strip-image PDFs by aggregating the pixel area of all image objects per page and flagging documents where the total exceeds ~2 million pixels while the count of large tiles remains low.

PDF Inspector, an open-source Rust library maintained by Firecrawl, classifies PDFs into three categories: TextBased, Scanned, and Mixed. The tiled-scan detection algorithm specifically targets edge-case documents that appear to be mixed or text-based but are actually constructed from many small image tiles. This commonly occurs with JBIG2-compressed documents and "strip-image" PDFs where each scan line is stored as a separate image object.

How Tiled-Scan Detection Works

The detection algorithm in src/detector.rs follows a four-step process to identify these problematic PDFs before extraction begins.

1. Page-Wise Image Enumeration

The detector walks through PDF objects and gathers every XObject of type Image on each page. This collection phase captures all raster elements regardless of how they're structured in the document hierarchy.

2. Tile Size Aggregation

For every image object discovered, the algorithm records pixel dimensions (width × height). No filtering occurs at this stage—all image objects contribute to the aggregate statistics.

3. Threshold-Based Scoring

The tiled_scan_detection function applies two critical thresholds:

  • Total pixel count must surpass a configurable limit (default 2,000,000 pixels)
  • Large tile count must remain below a secondary threshold (tiles > 256 px on either dimension)

When the aggregate area exceeds 2 million pixels but few individual tiles qualify as "large," the page triggers the tiled-scan flag. This pattern indicates many small image fragments rather than one or two full-page raster images.

4. JBIG2/Strip-Image Inference

JBIG2-encoded PDFs and strip-image formats store scan lines as 1-pixel-high individual images. The algorithm catches these because:

  • Hundreds or thousands of tiny tiles sum to exceed the pixel threshold
  • The large-tile count stays minimal (few strips exceed 256×256)
  • The document exhibits image-like total coverage without obvious full-page images

Upon detection, PDF Inspector reclassifies the document from Mixed to Scanned, forcing the raster-only extraction path for more reliable text extraction.

Implementation Details in src/detector.rs

The core logic resides in the tiled_scan_detection function within src/detector.rs. This function returns PdfType::Scanned when criteria are satisfied, as defined in src/types.rs:

// From src/types.rs - PdfType enum variants
pub enum PdfType {
    TextBased,
    Scanned,
    Mixed,
}

The detector feeds into src/extractor/mod.rs, which orchestrates the extraction strategy. Early tiled-scan detection prevents costly mixed-mode processing on documents that behave better as pure image PDFs.

Running Tiled-Scan Detection

Command-Line Usage

Analyze any PDF and view classification details including tiled-scan flags:

RUST_LOG=pdf_inspector::detector=debug cargo run --release --bin detect-pdf -- \
  --analyze --json path/to/document.pdf

Example JSON output for a detected tiled-scan document:

{
  "type": "Scanned",
  "tiled_scan": true,
  "details": {
    "total_pixels": 2137425,
    "large_tile_count": 3
  }
}

Programmatic API

use pdf_inspector::process_pdf_with_options;
use pdf_inspector::options::PdfOptions;

let opts = PdfOptions::default();
let result = process_pdf_with_options("my.pdf", opts)
    .expect("PDF processing failed");

// Check classification after tiled-scan detection
println!("PDF classification: {:?}", result.pdf_type);

if let Some(details) = result.tiled_scan_details {
    println!("Tiled-scan detected: {} tiles, {} total pixels",
             details.large_tile_count, details.total_pixels);
}

Key Source Files

File Purpose
src/detector.rs Implements tiled_scan_detection and page sampling logic
src/extractor/mod.rs Chooses extraction strategy based on detector output
src/types.rs Defines PdfType enum and tiled_scan_details metadata
src/bin/detect-pdf.rs CLI binary exposing detector functionality
AGENTS.md Architecture overview documenting tiled-scan detection

Summary

  • Tiled-scan detection identifies PDFs built from many small image tiles rather than full-page rasters
  • The 2 million pixel threshold catches JBIG2 and strip-image documents where aggregate coverage indicates scanned content
  • The large-tile count filter distinguishes true tiled scans from documents with a few oversized images
  • Detection triggers raster-only extraction, improving text extraction quality for edge-case formats
  • All logic is implemented in Rust within src/detector.rs and exposed via library and CLI interfaces

Frequently Asked Questions

What is the default pixel threshold for tiled-scan detection?

The default threshold is approximately 2 million pixels (2,000,000 px) total area per page. This value is configurable in the detection parameters within src/detector.rs.

Why do JBIG2 PDFs require special handling?

JBIG2 compression stores each scan line or small strip as an individual 1-pixel-high image object. Without tiled-scan detection, PDF Inspector might classify these as Mixed documents and attempt text extraction alongside image processing, yielding poor results. The pixel-aggregation approach correctly identifies the image-dominated nature of these files.

How does tiled-scan detection affect extraction performance?

Detection adds minimal overhead during the initial PDF analysis phase. However, it prevents costly mixed-mode extraction on documents that perform better with pure raster extraction. The net effect improves both accuracy and processing time for JBIG2 and strip-image PDFs.

Can tiled-scan detection be disabled?

Yes. When using the programmatic API with PdfOptions, detection behavior inherits from the default configuration. Review src/options.rs for configuration parameters that control detector thresholds and enablement.

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 →