# How pdf-inspector Detects Multi-Column Layouts: Newspaper vs. Tabular Reading Order Explained

> Discover how pdf-inspector detects multi-column layouts by analyzing histograms, pre-masking lines, and classifying newspaper vs. tabular reading orders. Get accurate document parsing.

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

---

**pdf-inspector distinguishes between newspaper-style and tabular reading orders by analyzing horizontal projection histograms for column detection, pre-masking spanning lines, then classifying layouts based on vertical alignment patterns and line-grid presence.**

The `firecrawl/pdf-inspector` Rust library extracts structured text from PDFs with intelligent layout understanding. Multi-column documents pose a fundamental challenge: should text flow top-to-bottom within each column (newspaper-style), or should rows be read across columns before moving down (tabular-style)? This article examines exactly how pdf-inspector solves this detection problem.

## Understanding the Two Multi-Column Layout Types

pdf-inspector recognizes two distinct reading patterns that determine how extracted text is ordered:

| Layout type | Reading order | Visual characteristics |
|-------------|---------------|------------------------|
| **Newspaper** | Sequential columns (top-to-bottom, left-to-right) | Continuous text flow with irregular vertical alignment between columns |
| **Tabular** | Interleaved rows (across columns, then down) | Table-like structures with items sharing horizontal baselines or visible grid lines |

The detection pipeline runs during **layout extraction**, primarily in [`src/extractor/layout.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/extractor/layout.rs) and [`src/extractor/reading_order.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/extractor/reading_order.rs).

## Stage 1: Column Detection via Horizontal Projection Histograms

The first step identifies column boundaries mathematically. In [`src/extractor/layout.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/extractor/layout.rs), the `detect_columns` routine builds a **horizontal projection histogram** by counting text items at each x-coordinate.

Valleys in this histogram represent whitespace gaps between columns. The algorithm extracts x-bounds from these valleys to define column rectangles:

```rust
// Simplified from src/extractor/layout.rs
let histogram = build_horizontal_projection(&text_items);
let valleys   = find_valleys(&histogram);
let columns   = valleys.iter().map(|v| Column::from_valley(v)).collect();

```

Every `TextItem` is subsequently assigned to one of these detected columns based on its x-position.

## Stage 2: Spanning-Line Pre-Masking

Headlines, captions, and other spanning elements would corrupt column detection if left unhandled. pdf-inspector implements **pre-masking** in `pre_mask_spanning_lines` within [`src/extractor/layout.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/extractor/layout.rs):

```rust
if line.width > column_threshold {
    // Exclude from histogram to prevent false valleys
}

```

Lines exceeding a **column-aware threshold** (a fraction of page width) are temporarily removed from the histogram calculation. After column boundaries stabilize, these masked lines are re-inserted and assigned to appropriate columns.

## Stage 3: Newspaper vs. Tabular Classification

The final decision occurs in [`src/extractor/reading_order.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/extractor/reading_order.rs). The `classify_page_reading_order` function evaluates two primary signals:

**Tabular detection triggers when:**
- Text baselines show **strong vertical alignment** across columns (same y-coordinates within tolerance)
- **Horizontal or vertical line primitives** are detected (from [`src/tables/detect_lines.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/tables/detect_lines.rs))

**Newspaper fallback** applies when neither condition is satisfied:

```rust
// Core logic in src/extractor/reading_order.rs
if has_strong_vertical_grid(&page_items) || has_aligned_rows(&page_items) {
    ReadingOrder::Tabular
} else {
    ReadingOrder::Newspaper
}

```

The classification directly impacts output: tabular documents interleave rows across columns, while newspaper documents concatenate full columns left-to-right.

## Practical Implementation

Enable automatic reading order detection when processing PDFs:

```rust
use pdf_inspector::process_pdf_with_options;
use pdf_inspector::options::PdfOptions;

let options = PdfOptions::default()
    .with_reading_order(true);

let markdown = process_pdf_with_options("document.pdf", options)
    .expect("PDF processing failed");

// Output respects detected newspaper or tabular sequence
println!("{}", markdown);

```

The `reading_order` field in the returned structure exposes the detected classification for inspection or override.

## Key Source Files

| File | Responsibility |
|------|--------------|
| [`src/extractor/layout.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/extractor/layout.rs) | Histogram creation, valley detection, spanning-line masking |
| [`src/extractor/reading_order.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/extractor/reading_order.rs) | Classification logic between Newspaper and Tabular modes |
| [`src/tables/detect_lines.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/tables/detect_lines.rs) | Line primitive detection for grid-based tabular identification |
| [`src/markdown/convert.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/markdown/convert.rs) | Applies determined reading order during Markdown emission |

## Summary

- **Horizontal projection histograms** identify column boundaries by finding whitespace valleys in `detect_columns`
- **Spanning-line pre-masking** prevents headlines from corrupting column detection via `pre_mask_spanning_lines`
- **Tabular classification** depends on vertical alignment patterns and detected line grids in `has_strong_vertical_grid` and `has_aligned_rows`
- **Newspaper fallback** provides the default sequential column reading when tabular signals are absent
- The `ReadingOrder` enum propagates through [`src/markdown/convert.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/markdown/convert.rs) to ensure correct text sequencing

## Frequently Asked Questions

### How does pdf-inspector handle PDFs with mixed layout types on different pages?

pdf-inspector classifies **each page independently** through `classify_page_reading_order`. A document may contain newspaper-style content pages alongside tabular data pages, with each page receiving its appropriate reading order during the conversion pipeline.

### What causes false tabular detection in otherwise normal documents?

Dense multi-column layouts with **coincidental vertical alignment**—such as bulleted lists or code blocks—can trigger tabular classification. The `has_aligned_rows` function uses tolerance thresholds, but highly regular spacing may still misclassify. Force newspaper mode via `PdfOptions` when needed.

### Does pdf-inspector detect tables that lack visible grid lines?

Yes. The **vertical alignment heuristic** in `has_aligned_rows` detects tabular structure from baseline patterns alone, even without line primitives from [`src/tables/detect_lines.rs`](https://github.com/firecrawl/pdf-inspector/blob/main/src/tables/detect_lines.rs). This handles "invisible grid" tables common in academic papers.

### Can I extract text without any reading order detection?

The `with_reading_order(true)` flag enables classification; omitting it or using `with_reading_order(false)` produces raw text extraction without column-aware ordering. However, multi-column PDFs will likely yield scrambled output as text items default to arrival order in the PDF content stream.