How to Extract Text from Specific Bounding Box Regions in PDF Pages with pdf‑inspector
The pdf-inspector library provides extract_text_in_regions_mem to extract native PDF text from arbitrary rectangular regions without page rendering, falling back to OCR only when text quality checks fail.
When you need precision text extraction from specific areas of a PDF—such as headers, footers, or isolated table cells—pdf-inspector offers a low‑level Rust API that operates directly on PDF text objects. This approach, implemented in firecrawl/pdf-inspector, avoids the performance cost of full‑page rasterization and gives you fine‑grained control over which regions to process.
Overview of the Region Extraction API
The entry point for bounding‑box extraction is extract_text_in_regions_mem in src/lib.rs. This function accepts raw PDF bytes and a structured list of page‑region pairs, returning extracted text with automatic quality validation.
The workflow follows these stages:
- Single document load – parse the PDF once with
load_document_from_mem - Fast font caching – build minimal ToUnicode maps via
FontCMaps::from_doc_pages_fast, skipping expensive TrueType fallbacks - Text item extraction – retrieve raw
TextItems per page throughextract_page_text_items - Region assignment – calculate overlap between text items and user‑defined bounding boxes
- Quality gating – flag regions needing OCR if decoding issues, CID garbage, or encoding problems are detected
- Text assembly – concatenate matched items with adaptive spacing into final strings
Defining Bounding Boxes for Extraction
Regions are specified in PDF points with a top‑left origin coordinate system. Each entry in the request list contains:
page_number_0indexed– zero‑based page index (internally converted to lopdf's 1‑indexed format)Vec<[x1, y1, x2, y2]>– array of rectangles wherex1,y1is the top‑left corner andx2,y2is the bottom‑right corner
This coordinate scheme aligns directly with layout model outputs, making integration straightforward.
Coordinate System Notes
The API handles page rotation automatically. When a page is rotated 90°, the RegionBounds construction adjusts the coordinate math so your bounding boxes still map correctly to text items.
Basic Usage: Extract Text from Multiple Regions
Here is a complete example demonstrating multi‑page, multi‑region extraction:
use pdf_inspector::{extract_text_in_regions_mem, PdfError};
fn main() -> Result<(), PdfError> {
// 1️⃣ Read the PDF file into memory.
let pdf_bytes = std::fs::read("report.pdf")?;
// 2️⃣ Define the regions you want to extract.
// (page, vec of [x1, y1, x2, y2] in PDF points, top‑left origin)
let regions = vec![
// Page 0 (the first page) – two separate rectangles
(0_u32, vec![
[50.0, 100.0, 300.0, 150.0], // Header block
[50.0, 200.0, 300.0, 350.0], // Body paragraph
]),
// Page 2 – a single rectangle
(2_u32, vec![
[30.0, 400.0, 400.0, 500.0],
]),
];
// 3️⃣ Call the extractor.
let results = extract_text_in_regions_mem(&pdf_bytes, ®ions)?;
// 4️⃣ Process the results.
for page_res in results {
println!("--- Page {} ---", page_res.page + 1);
for (i, region) in page_res.regions.iter().enumerate() {
if region.needs_ocr {
println!("Region {} needs OCR (reason: {:?})", i, region.ocr_reason);
} else {
println!("Region {} extracted text:\n{}", i, region.text);
}
}
}
Ok(())
}
The extract_text_in_regions_mem function returns a Vec<PageRegionResult>. Each result contains:
page– the page index (zero‑based)regions– aVec<RegionText>with one entry per requested bounding box
Each RegionText provides:
text– the extracted string (empty if no text objects overlap the region)needs_ocr– boolean flag indicating reliability concernsocr_reason– optional description such as"suspected_garbled_text"
Handling Overlapping Regions
The region assignment algorithm uses exclusive assignment by maximum overlap. For each text item, the code calculates overlap area with all candidate regions and assigns the item to exactly one region—the one with the largest overlap.
This prevents duplicate text when bounding boxes overlap. If you need overlapping regions with shared text, make separate API calls.
Quality Detection and OCR Fallback
After collecting text items for a region, pdf-inspector runs the same quality checks used for full‑page extraction (defined in src/text_utils.rs):
| Check | Function | Purpose |
|---|---|---|
| Decoding issues | region_items_have_decoding_issue |
Detect font decoding failures |
| CID garbage | is_cid_garbage |
Identify raw CID values masquerading as text |
| Encoding problems | detect_encoding_issues |
Catch mojibake and malformed UTF‑16BE |
If any check fails, needs_ocr is set to true and ocr_reason is populated. Your application can then route the region to GPU‑based OCR for reliable extraction.
Extracting Structured Tables from Regions
For tabular data extraction, use the companion function extract_tables_in_regions_mem. It follows identical region selection logic but applies table detection heuristics, returning markdown pipe tables when structure is recognized.
use pdf_inspector::{extract_tables_in_regions_mem, PdfError};
fn main() -> Result<(), PdfError> {
let pdf_bytes = std::fs::read("financials.pdf")?;
let regions = vec![(0_u32, vec![[72.0, 500.0, 540.0, 720.0]])];
let table_results = extract_tables_in_regions_mem(&pdf_bytes, ®ions)?;
for page in table_results {
for region in page.regions {
if region.needs_ocr {
println!("Region needs OCR – fall back to image OCR.");
} else {
println!("Extracted markdown table:\n{}", region.text);
}
}
}
Ok(())
}
The table detection pipeline lives in src/tables/mod.rs and operates on the same TextItem stream used for plain text extraction.
Key Source Files and Implementation Details
Understanding the internal architecture helps debug extraction issues and customize behavior:
-
src/lib.rs–extract_text_in_regions_memandextract_tables_in_regions_memimplement the public API; coordinates the full workflow from document loading through result assembly -
src/extractor/content_stream.rs–extract_page_text_itemsparses PDF content streams, returning positionedTextItems with font and transformation matrix information -
src/text_utils.rs– quality helpers includingregion_items_have_decoding_issuefor decoding validation andcollect_text_from_matched_itemsfor adaptive‑spacing text concatenation -
src/tables/mod.rs– table detection pipelines that transform region items into structured markdown output
Performance Characteristics
The region‑based approach delivers significant advantages over rasterization‑based extraction:
- No page rendering – operations stay in vector space, eliminating GPU memory overhead
- Minimal font processing –
FontCMaps::from_doc_pages_fastskips TrueType fallback parsing, building only essential ToUnicode caches - Targeted item streaming – only pages with requested regions are processed; text items outside all regions are ignored
Fonts that cannot be decoded produce empty or garbage text, which triggers the OCR flag rather than crashing extraction. This fail‑forward design maintains throughput on documents with corrupted or exotic font encodings.
Summary
- Use
extract_text_in_regions_memto pull native PDF text from arbitrary rectangular regions without page rendering - Specify regions in PDF points with top‑left origin; the API handles rotated pages automatically
- Each text item is assigned exclusively to the region with maximum overlap area
needs_ocrandocr_reasonflag unreliable extractions so you can fall back to GPU OCR- Use
extract_tables_in_regions_memfor structured table extraction within the same bounding boxes - Core logic resides in
src/lib.rswith supporting modules insrc/extractor/content_stream.rs,src/text_utils.rs, andsrc/tables/mod.rs
Frequently Asked Questions
How do I convert pixel coordinates from an image to PDF points for region extraction?
PDF points are a physical unit (1/72 inch) independent of image resolution. If you have pixel coordinates from a rendered preview, you need the page's crop box dimensions in points and the image DPI used for rendering. The conversion is: point = pixel × (72 / DPI). For non‑cropped pages, use the MediaBox width/height from the PDF as your reference rectangle.
What happens if a region contains no text objects?
The text field returns an empty string and needs_ocr is set to false. An empty region with needs_ocr == false means the extraction succeeded but found no content—distinguishing it from a region with needs_ocr == true where content was found but deemed unreliable.
Can I extract text from the same region across all pages without listing each page?
The current API requires explicit page numbers. You must build the regions vector with entries for every target page. A common pattern iterates over your page range and clones the coordinate array for each page index before calling extract_text_in_regions_mem.
Why does my region return needs_ocr even when text appears correct?
The quality gates in src/text_utils.rs are conservative. Certain font encodings—especially legacy Type 1 fonts with non‑standard encodings or subset fonts with incomplete ToUnicode maps—can pass visual inspection but fail heuristic checks. Inspect the ocr_reason field: "suspected_garbled_text" suggests encoding issues, while CID‑related reasons indicate raw glyph IDs escaping the parser.
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 →