How to Extract Tables from Specific Regions of a PDF Page Using pdf-inspector
pdf-inspector enables precise table extraction from user-defined rectangular regions on PDF pages through the extract_tables_in_regions_mem Rust function and its Node.js N-API wrapper, returning structured Markdown tables for each bounding box.
The pdf-inspector library from Firecrawl provides a high-level API for targeted table extraction, allowing developers to isolate specific areas of a PDF page rather than processing the entire document. This region-aware approach is implemented in Rust with bindings for Node.js, making it ideal for extracting tables from complex layouts or multi-table pages without interference from decorative graphics or adjacent tables.
How Region-Aware Table Extraction Works
The extraction pipeline is deliberately designed to operate only on the subset of content that falls inside caller-supplied bounding boxes. This architecture makes it possible to extract a single table from a multi-table page or ignore decorative elements outside your area of interest.
The process follows eight distinct stages:
- PDF Validation – The loader at
src/lib.rsvalidates the byte stream and builds alopdf::Documentto guarantee the file is a valid PDF before extraction begins. - Font Mapping –
FontCMaps::from_doc_pages_fastpre-loads Unicode mappings only for the pages you request, keeping memory usage low and operations fast. - Content Stream Parsing – The extractor in
src/extractor/content_stream.rswalks the page's content streams, decodes text operators, and returns three collections per page:TextItem,PdfRect, andPdfLine. - Region Filtering – Functions like
region_overlaps_item,region_overlaps_rect, andregion_overlaps_linefilter the collections to keep only items intersecting your supplied bounding box. - Quality Validation – Garbage-text, CID-garbage, and encoding-issue checks run in
src/lib.rs; if the region appears corrupted, the function returnsneeds_ocr = trueso you can fall back to OCR. - Table Detection – Three strategies execute in order until one produces a plausible table:
- Rect-backed detector (
src/tables/detect_rects.rs) – First-choice strategy using vector rectangles - Line-grid detector (
src/tables/detect_lines.rs) – Second-choice strategy using ruling lines - Heuristic text-only detector (
src/tables/detect_heuristic.rs) – Fallback when vector data is insufficient
- Rect-backed detector (
- Markdown Conversion –
tables::table_to_markdowninsrc/tables/format.rsconverts the internalTablerepresentation into Markdown pipe-table syntax. - Result Assembly – The function returns a
RegionTextstruct containing thetext,needs_ocrboolean, andocr_reasonfor each region.
Extracting Tables from Specific Regions in Rust
Use the extract_tables_in_regions_mem function from the public crate to process multiple regions across multiple pages in a single call.
use pdf_inspector::{extract_tables_in_regions_mem, PageRegionResult};
fn main() -> Result<(), pdf_inspector::PdfError> {
// Load a PDF file into memory
let pdf_bytes = std::fs::read("report.pdf")?;
// Define one or more regions: (page_index, Vec<[x1, y1, x2, y2]>)
// Page index is zero-based. Coordinates are in PDF user space (origin bottom-left).
let regions = vec![
(0, vec![[50.0, 500.0, 550.0, 750.0]]), // page 0, a single rectangle
(2, vec![[100.0, 200.0, 400.0, 600.0], [420.0, 200.0, 720.0, 600.0]]), // page 2, two boxes
];
// Run the extractor
let results: Vec<PageRegionResult> = extract_tables_in_regions_mem(&pdf_bytes, ®ions)?;
// Iterate over the results
for page_res in results {
for (idx, region) in page_res.regions.iter().enumerate() {
if region.needs_ocr {
eprintln!("Region {} on page {} needs OCR", idx, page_res.page);
} else {
println!("--- Table from page {} region {} ---\n{}", page_res.page, idx, region.text);
}
}
}
Ok(())
}
The regions parameter accepts a vector where each tuple contains a zero-based page index and a vector of bounding boxes. Each bounding box is defined as [x1, y1, x2, y2] in PDF user space coordinates (origin at bottom-left). The function returns a Vec<PageRegionResult> where each entry corresponds to a page and contains a list of RegionText results matching your input order.
Node.js Implementation Using N-API Bindings
The N-API wrapper defined in napi/src/lib.rs exposes the same functionality to JavaScript through the extract_tables_in_regions function, maintaining identical parameter signatures.
const { readFileSync } = require('fs');
const { extract_tables_in_regions } = require('pdf-inspector'); // npm package
(async () => {
const pdf = readFileSync('report.pdf');
// Regions follow the same convention as the Rust API.
const regions = [
[0, [[50, 500, 550, 750]]],
[2, [[100, 200, 400, 600], [420, 200, 720, 600]]],
];
try {
const results = await extract_tables_in_regions(pdf, regions);
results.forEach(page => {
page.regions.forEach((r, i) => {
if (r.needs_ocr) {
console.warn(`Page ${page.page} region ${i} needs OCR`);
} else {
console.log(`--- Table from page ${page.page} region ${i} ---\n${r.text}`);
}
});
});
} catch (e) {
console.error('Extraction failed:', e);
}
})();
The JavaScript wrapper forwards directly to extract_tables_in_regions_mem, ensuring consistent behavior across languages. Region coordinates use the same PDF user space system, and the returned objects contain identical needs_ocr flags and Markdown-formatted text.
Handling OCR Fallbacks and Quality Guards
When extract_tables_in_regions_mem detects encoding issues or garbage text in a region, it sets needs_ocr to true rather than returning corrupted data. This quality guard, implemented in src/lib.rs between lines 1016-1020, allows your application to decide whether to process the Markdown text or route the specific region to a raster OCR pipeline.
Check the ocr_reason field in the RegionText struct to determine why OCR was recommended—common reasons include CID-garbage detection, font encoding issues, or insufficient text items in the bounding box.
Core Source Files for Region Extraction
Understanding the source structure helps debug extraction issues or extend functionality:
src/lib.rs– Entry point exposingextract_tables_in_regions_memand quality validation logic.src/extractor/content_stream.rs– Parses PDF operators and buildsTextItem,PdfRect, andPdfLinecollections.src/tables/detect_rects.rs– Rect-based table detector used as the primary strategy.src/tables/detect_lines.rs– Line-grid detector for tables defined by ruling lines.src/tables/detect_heuristic.rs– Heuristic text-only fallback when vector graphics are absent.src/tables/format.rs– Converts detectedTablestructs to Markdown pipe-table syntax.napi/src/lib.rs– N-API bindings at line 405 that bridge Rust and Node.js.
Summary
- Region-specific extraction uses
extract_tables_in_regions_mem(Rust) orextract_tables_in_regions(Node.js) to target exact bounding boxes on PDF pages. - Coordinate system expects PDF user space with origin at bottom-left, using
[x1, y1, x2, y2]arrays. - Three-phase detection tries rect-based, line-grid, and heuristic strategies in sequence until a valid table is found.
- Quality assurance returns
needs_ocr = truewhen regions contain corrupted or garbled text, allowing selective OCR fallback. - Output format is Markdown pipe-table text contained in the
textfield of eachRegionTextresult.
Frequently Asked Questions
What coordinate system does pdf-inspector use for regions?
pdf-inspector uses standard PDF user space coordinates with the origin (0,0) at the bottom-left corner of the page. When defining regions, provide coordinates as [x1, y1, x2, y2] where x1,y1 represents the lower-left corner and x2,y2 represents the upper-right corner of your target rectangle. Page indices are zero-based.
How does pdf-inspector handle tables that span multiple pages?
Each region definition is tied to a specific page index in the regions parameter. To extract a table that spans multiple pages, define separate bounding boxes for each page segment. The function returns a PageRegionResult for each page containing an array of RegionText objects matching the order of your input regions.
What happens if the specified region contains no table or corrupted text?
If the region contains corrupted encoding or garbage text, extract_tables_in_regions_mem sets needs_ocr to true and provides an ocr_reason explaining the failure. If no table structure is detected but the text is clean, you may receive the raw text content or an empty result depending on whether the heuristic detector finds tabular patterns.
Can I extract multiple tables from different regions on the same page?
Yes. Supply multiple bounding boxes in the vector for a single page index. For example, (0, vec![[50.0, 500.0, 300.0, 700.0], [320.0, 500.0, 570.0, 700.0]]) extracts two separate tables from page 0. The results array maintains the same order as your input regions, allowing you to correlate outputs with specific bounding boxes.
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 →