# How Vector-Grid Detection Works for Table Extraction in pdf-inspector

> Discover how pdf-inspector's vector-grid detection extracts tables by analyzing PDF paths and clustering lines into precise cell boundaries for accurate data retrieval.

- Repository: [Firecrawl/pdf-inspector](https://github.com/firecrawl/pdf-inspector)
- Tags: internals
- Published: 2026-08-08

---

**Vector-grid detection in pdf-inspector identifies tables by analyzing PDF path operators to find dense grids of horizontal and vertical lines, then clustering them into column and row boundaries before assigning text to cells.**

The `firecrawl/pdf-inspector` repository implements three complementary table extraction strategies: **rect-based**, **line-based** (vector-grid), and **heuristic** detection. The vector-grid approach specifically targets PDFs containing explicit ruling lines, making it ideal for scanned forms and structured documents where text stream analysis alone proves unreliable.

## What Is Vector-Grid Detection?

Vector-grid detection operates by inspecting the raw PDF drawing operators that create horizontal and vertical strokes. Unlike heuristic methods that infer structure from text positioning alone, this **line-based** strategy recognizes regular grids of lines that physically define column edges and row boundaries. Once identified, the algorithm assigns surrounding text items to these geometric cells, producing a structured `Table` representation.

## The Vector-Grid Pipeline: Step-by-Step

The implementation lives primarily in [`src/tables/detect_lines.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/tables/detect_lines.rs), where the `detect_dense_line_chart_regions` function orchestrates the extraction process.

### 1. Classifying PDF Path Operators

Every `PdfLine` is inspected to determine its orientation. The algorithm calculates slope ratios to classify lines as **vertical** (`dx / dy ≤ ANGLE_TOLERANCE`) or **horizontal** (`dy / dx ≤ ANGLE_TOLERANCE`). Segments shorter than `MIN_GRID_LINE_LENGTH` are discarded immediately to eliminate noise from decorative borders or dashes.

This classification occurs in `detect_dense_line_chart_regions` at lines 28-44.

### 2. Collecting Line Candidates

Valid vertical lines are stored as tuples of `(x, y_min, y_max)`, while horizontal lines are stored as `(y, x_min, x_max)`. This coordinate extraction enables subsequent geometric analysis of the grid structure.

See lines 45-51 in [`src/tables/detect_lines.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/tables/detect_lines.rs).

### 3. Early Exit for Sparse Drawings

The algorithm enforces a **density-first heuristic** to distinguish tables from charts or decorative graphics. If the region contains fewer than `DENSE_CHART_MIN_VERTICAL_EDGES` (27) vertical lines or fewer than three horizontal lines, the function returns early, ignoring the region as non-tabular.

This validation appears at lines 51-53.

### 4. Bucketing Vertical Extents

To group vertical lines that belong to the same table panel, the algorithm quantizes the y-extent of each line into buckets using `extent_key` with a tolerance of `EXTENT_TOLERANCE` (6 pt). This bucketing prevents the repeated scanning of every line during the family-building phase.

Implementation details are found at lines 55-61.

### 5. Building Families of Vertical Lines

For each bucket, the code computes the average bottom (`anchor_bottom`) and top (`anchor_top`) coordinates. Adjacent buckets (±1) are merged if their extents fall within `EXTENT_TOLERANCE`, producing a **family** representing a candidate dense column set. This isolation prevents cross-contamination between separate tables on the same page.

See lines 62-78 for the family construction logic.

### 6. Snapping Column X-Coordinates

The X positions of all vertical lines within a family are fed to `snap_edges`, a clustering routine with a 3 pt tolerance. This groups nearby coordinates affected by anti-aliasing or rendering variations. Only families producing at least 27 distinct column edges survive this filtering.

This clustering occurs at lines 80-93.

### 7. Deriving Row Y-Coordinates

Horizontal rules intersecting the vertical family are examined to establish row boundaries. The algorithm collects Y-values per **span**—contiguous X-ranges containing sufficient vertical edges. A span is retained only if it contains at least three distinct Y values after snapping (`snap_edges(&ys, 3.0)`), ensuring the horizontal rule truly belongs to the grid rather than serving as a decorative element.

This derivation logic spans lines 103-126.

### 8. Validating Panel Dimensions

Before accepting a detected grid, the algorithm rejects panels that are too narrow (`width < 100 pt`) or too short (`height < 20 pt`). This prevents tiny graphic elements or separator lines from being misidentified as tables.

See the validation checks at lines 27-30.

### 9. Assigning Text to the Grid

With final `col_edges` and `row_edges` vectors established, the code calls `assign_items_to_grid` (imported from [`src/tables/detect_rects.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/tables/detect_rects.rs)) at line 59. This function places each `TextItem` into the appropriate cell based on its center point coordinates.

### 10. Constructing the Table Structure

The collected cells, column and row coordinates, and the indices of used text items are wrapped in a `Table` struct via `Table::new`. The completed table object is then returned to the higher-level detector at lines 50-55, where it may be merged with rect-based or heuristic candidates.

## Why the Algorithm Works

The vector-grid detector achieves high precision through four specific design decisions:

- **Density-first heuristic**: Real tables produce dense vertical stroke patterns (≥ 27 distinct X positions) because column separators repeat across many rows. Charts typically exhibit far fewer vertical divisions, allowing the threshold to filter them out early.
- **Robust edge clustering**: The `snap_edges` utility groups coordinates within a few points of each other, ensuring that minor rendering variations or anti-aliasing artifacts do not fracture the grid detection.
- **Span-aware row extraction**: Horizontal rules must span at least 80% of the table width and intersect enough vertical edges to qualify as row boundaries, eliminating decorative horizontal lines.
- **Panel-level isolation**: By grouping vertical lines into families based on Y-extents, the detector isolates separate tables sharing the same page, preventing cross-panel contamination.

## Running the Vector-Grid Detector

To extract tables using the full pipeline (including vector-grid detection):

```bash
pdf2md --json my_report.pdf > out.json

```

To debug the line-based detector specifically and view detailed logging:

```bash
RUST_LOG=pdf_inspector::tables=debug cargo run --bin pdf2md -- \
    --detect-lines-only my_report.pdf

```

The debug output includes messages from the functions described above, such as "detect_lines p1: accepted text-anchor rule table," allowing you to trace the detection process through each step.

## Key Source Files

- **[`src/tables/detect_lines.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/tables/detect_lines.rs)**: Implements the complete vector-grid pipeline, including `detect_dense_line_chart_regions`, `derive_columns_from_horizontal_segments`, and the `detect_tables_from_lines` entry point.
- **[`src/tables/grid.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/tables/grid.rs)**: Provides shared utilities for column/row clustering, numeric-column merging, and header-row recovery used by all three detection strategies.
- **[`src/tables/detect_heuristic.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/tables/detect_heuristic.rs)**: Implements the fallback heuristic detector that analyzes text positioning when explicit lines are absent.

## Summary

- Vector-grid detection analyzes PDF drawing operators to identify horizontal and vertical ruling lines.
- The algorithm requires at least **27 vertical edges** and **3 horizontal edges** to qualify a region as a dense table grid.
- **Snap clustering** with 3-6 pt tolerances groups lines affected by rendering artifacts while preserving true grid structure.
- **Panel validation** (minimum 100 pt width, 20 pt height) and **span-aware filtering** prevent false positives on decorative graphics.
- Detected grids assign text items to cells via geometric center-point testing before constructing the final `Table` struct.

## Frequently Asked Questions

### What is the minimum number of vertical lines required for vector-grid detection?

The algorithm requires at least **27 vertical edges** (`DENSE_CHART_MIN_VERTICAL_EDGES`) to consider a region a dense table grid. This threshold filters out charts and decorative graphics that typically contain far fewer vertical divisions.

### How does pdf-inspector distinguish between tables and charts using vector-grid detection?

The system relies on **density heuristics**. Real tables produce dense patterns of vertical strokes because column separators repeat across rows, while charts exhibit sparse line distributions. The early-exit logic at lines 51-53 of [`detect_lines.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/detect_lines.rs) rejects regions with fewer than 27 vertical or three horizontal lines.

### What tolerance values does the vector-grid algorithm use for clustering lines?

The implementation uses **6 pt** (`EXTENT_TOLERANCE`) for bucketing vertical line extents and **3 pt** for the `snap_edges` clustering routine. These tolerances accommodate minor anti-aliasing variations and PDF rendering artifacts without breaking grid continuity.

### Can vector-grid detection work on scanned PDFs?

Yes, provided the scanned document contains **explicit ruling lines**. The vector-grid detector serves as a high-confidence fallback for PDFs where the underlying text stream is unreliable, such as scanned forms with visible grid lines. However, it cannot detect tables in scanned images lacking visible borders, where the heuristic detector would take over.