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 contentneeds_ocr: A boolean indicating whether the extraction is unreliableocr_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_textordetect_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, ®ions)?;
// 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 includingextract_text_in_regions_mem, result structs (RegionText,PageRegionResult), and the core region-assignment logic using the best-overlap heuristic.src/extractor/content_stream.rs: Implementsextract_page_text_items, which walks PDF content streams and producesTextItemobjects with positional metadata.src/extractor/fonts.rs: ProvidesFontCMaps::from_doc_pages_fastfor efficient font decoding without expensive TrueType operations.src/python.rs: PyO3 bindings exposingextract_text_in_regionsandextract_text_in_regions_bytesto 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_memfunction 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_ocrandocr_reasonfields. - 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →