How to Extract Text from Specific Regions of a PDF Page Using pdf-inspector

pdf-inspector provides a fast, pure-Rust API that extracts text from arbitrary rectangular regions of PDF pages while automatically flagging content that requires OCR fallback.

The firecrawl/pdf-inspector repository offers a high-performance solution for targeted text extraction from PDF documents. This Rust-based library enables precise retrieval of textual content from specific coordinates without writing temporary files, making it ideal for serverless architectures and hybrid OCR pipelines.

Core API and Data Structures

The primary entry point for region-based extraction is extract_text_in_regions_mem, defined in src/lib.rs. This function accepts PDF bytes along with a specification of page indices and bounding rectangles, returning a vector of PageRegionResult structs.

Each PageRegionResult contains the page index and a vector of RegionText objects. According to the source code in src/lib.rs (lines 738-752), each RegionText provides three critical fields:

  • text: The extracted string content
  • needs_ocr: A boolean indicating whether the extraction is unreliable
  • ocr_reason: An optional diagnostic message (e.g., "GID font" or "garbage text")

Step-by-Step Extraction Process

The extraction pipeline operates entirely in memory through six distinct stages:

PDF Loading and Parsing

First, load_document_from_mem parses the entire PDF file once, creating a lopdf::Document instance that persists for both layout detection and text extraction (lines 770-802 in src/lib.rs). This single-pass approach eliminates redundant I/O operations when processing multiple regions on the same page.

Fast Font Handling

The library uses FontCMaps::from_doc_pages_fast to scan only requested pages, bypassing expensive TrueType fallback operations. As implemented in src/lib.rs (lines 808-811), fonts that cannot decode via their ToUnicode CMap automatically trigger the needs_ocr flag rather than producing garbled output.

Content Stream Extraction

For each target page, the system invokes extract_page_text_items from src/extractor/content_stream.rs. This function traverses the PDF content stream and generates TextItem structs containing the glyph text, precise bounding box coordinates, and item classification (text versus image).

Region Assignment via Best-Overlap Heuristic

The caller provides axis-aligned rectangles in PDF points with a top-left origin. The helper function region_bounds (lines 1270-1290 in src/lib.rs) constructs RegionBounds objects that account for page height and coordinate space transformations, including 90-degree rotations.

Each TextItem is examined exactly once and assigned to the region exhibiting the largest overlap area. This "best-overlap" heuristic, implemented in src/lib.rs (lines 1030-1060), ensures each text element appears in only one result, preventing duplicate content from overlapping region definitions.

Quality Validation and OCR Detection

After grouping items, the extractor performs sanity checks on concatenated text (lines 1065-1085 in src/lib.rs). The system sets needs_ocr when encountering:

  • Empty or whitespace-only content
  • GID-encoded fonts containing unreadable glyph IDs
  • Text flagged by is_garbage_text or detect_encoding_issues

Result Compilation

The final output comprises vectors of PageRegionResult containing per-page, per-region text with reliability metadata. All processing occurs without temporary file creation, supporting high-throughput document analysis workflows.

Implementation Examples

Rust Implementation

The following example demonstrates loading a PDF, defining multiple regions across different pages, and processing the extraction results:

use pdf_inspector::{extract_text_in_regions_mem, RegionText, PageRegionResult};

fn main() -> Result<(), pdf_inspector::PdfError> {
    // Load PDF into memory from file or network source
    let pdf_bytes = std::fs::read("sample.pdf")?;

    // Define regions: (page_index, vec of [x1, y1, x2, y2])
    // Coordinates use PDF points with top-left origin
    let regions = vec![
        (0, vec![[100.0, 200.0, 300.0, 250.0]]),
        (1, vec![
            [50.0, 400.0, 400.0, 450.0],
            [50.0, 460.0, 400.0, 510.0],
        ]),
    ];

    // Execute region-based extraction
    let results: Vec<PageRegionResult> = extract_text_in_regions_mem(&pdf_bytes, &regions)?;

    // Process results with OCR fallback logic
    for PageRegionResult { page, regions } in results {
        println!("Page {}", page + 1);
        for (i, RegionText { text, needs_ocr, ocr_reason }) in regions.iter().enumerate() {
            println!("  Region {}: {}", i + 1, text);
            if *needs_ocr {
                println!("    → OCR needed ({})", ocr_reason.as_deref().unwrap_or("unknown"));
            }
        }
    }
    Ok(())
}

Python Implementation

Using the PyO3 bindings provided in src/python.rs, Python applications can leverage the same functionality:

import pdf_inspector

# Load PDF bytes from file, HTTP response, or memory buffer

with open("sample.pdf", "rb") as f:
    data = f.read()

# Define regions: (page_index, [[x1, y1, x2, y2], ...])

# Coordinates are PDF points, origin = top-left

regions = [
    (0, [[100.0, 200.0, 300.0, 250.0]]),
    (1, [[50.0, 400.0, 400.0, 450.0],
         [50.0, 460.0, 400.0, 510.0]])
]

# Extract text from specified regions

page_results = pdf_inspector.extract_text_in_regions(data, regions)

for page in page_results:
    print(f"Page {page.page + 1}")
    for i, region in enumerate(page.regions):
        print(f"  Region {i + 1}: {region.text}")
        if region.needs_ocr:
            print(f"    → OCR needed ({region.ocr_reason or 'unknown'})")

Key Source Files and Architecture

Understanding the repository structure facilitates advanced customization and debugging:

  • src/lib.rs: Contains the public API including extract_text_in_regions_mem, result structs (RegionText, PageRegionResult), and the core region-assignment logic using the best-overlap heuristic.
  • src/extractor/content_stream.rs: Implements extract_page_text_items, which walks PDF content streams and produces TextItem objects with positional metadata.
  • src/extractor/fonts.rs: Provides FontCMaps::from_doc_pages_fast for efficient font decoding without expensive TrueType operations.
  • src/python.rs: PyO3 bindings exposing extract_text_in_regions and extract_text_in_regions_bytes to Python environments.
  • src/napi/src/lib.rs: Node.js N-API bindings offering equivalent functionality for JavaScript applications.

Summary

  • pdf-inspector enables precise text extraction from arbitrary rectangular regions using pure-Rust implementations that operate entirely in memory.
  • The extract_text_in_regions_mem function processes PDF bytes and returns structured results indicating both text content and extraction reliability.
  • The library employs a best-overlap heuristic (lines 1030-1060 in src/lib.rs) to ensure text items appear in exactly one region, preventing duplicates from overlapping boundaries.
  • Automatic OCR detection occurs through validation of empty content, GID-encoded fonts, and garbage text detection, providing clear fallback signals via needs_ocr and ocr_reason fields.
  • Both Rust and Python implementations support coordinate-based extraction using PDF points with top-left origin, suitable for integration with layout detection models and hybrid OCR pipelines.

Frequently Asked Questions

What coordinate system does pdf-inspector use for region definitions?

pdf-inspector uses PDF points with a top-left origin for all region specifications. The region_bounds function in src/lib.rs (lines 1270-1290) handles coordinate space transformations automatically, including accommodations for 90-degree page rotations. When defining regions, provide coordinates as [x1, y1, x2, y2] where x1, y1 represents the top-left corner and x2, y2 represents the bottom-right corner of the target rectangle.

How does pdf-inspector handle text that spans multiple regions?

The library implements a best-overlap heuristic that assigns each text item to exactly one region. As coded in src/lib.rs (lines 1030-1060), the system calculates overlap areas between each TextItem bounding box and all specified regions, assigning the text to the region with the largest intersection area. This approach eliminates duplicate text extraction that would otherwise occur with overlapping region definitions.

What triggers the needs_ocr flag in the extraction results?

The needs_ocr boolean activates during post-extraction quality validation when content exhibits specific reliability issues. According to src/lib.rs (lines 1065-1085), triggers include empty or whitespace-only strings, GID-encoded fonts containing unreadable glyph identifiers, and text failing garbage detection heuristics. The accompanying ocr_reason field provides specific diagnostic context such as "GID font" or "garbage text" to guide fallback processing decisions.

Can pdf-inspector process PDFs without writing temporary files?

Yes. The extract_text_in_regions_mem function operates entirely on byte buffers held in memory, utilizing load_document_from_mem to parse PDF structures without disk I/O. This architecture, defined in src/lib.rs (lines 770-802), makes the library suitable for serverless environments and high-throughput applications where file system access is restricted or latency-sensitive operations require pure memory processing.

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 →