fix(columns): Skip table detection on wide multi-column text pages
Multi-column text layouts (e.g., creditor matrices with 3 address columns) were incorrectly claimed by body-font table detection. Now runs column detection before table detection and skips tables on pages where all detected columns are wider than 150pt, letting group_into_lines handle the column-by-column reading order correctly. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
73ade64fac
commit
d8f341bafc
+4
-4
@@ -2109,9 +2109,9 @@ fn effective_width(item: &TextItem) -> f32 {
|
|||||||
|
|
||||||
/// Represents a column region on a page
|
/// Represents a column region on a page
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct ColumnRegion {
|
pub(crate) struct ColumnRegion {
|
||||||
x_min: f32,
|
pub(crate) x_min: f32,
|
||||||
x_max: f32,
|
pub(crate) x_max: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Detect column boundaries on a page using a horizontal projection profile.
|
/// Detect column boundaries on a page using a horizontal projection profile.
|
||||||
@@ -2119,7 +2119,7 @@ struct ColumnRegion {
|
|||||||
/// Builds an occupancy histogram across the page width and finds empty valleys
|
/// Builds an occupancy histogram across the page width and finds empty valleys
|
||||||
/// (gutters) where no text exists. Validates valleys with vertical consistency
|
/// (gutters) where no text exists. Validates valleys with vertical consistency
|
||||||
/// checks to avoid false positives.
|
/// checks to avoid false positives.
|
||||||
fn detect_columns(items: &[TextItem], page: u32) -> Vec<ColumnRegion> {
|
pub(crate) fn detect_columns(items: &[TextItem], page: u32) -> Vec<ColumnRegion> {
|
||||||
const BIN_WIDTH: f32 = 2.0;
|
const BIN_WIDTH: f32 = 2.0;
|
||||||
const MIN_GUTTER_WIDTH: f32 = 8.0;
|
const MIN_GUTTER_WIDTH: f32 = 8.0;
|
||||||
const MIN_VERTICAL_SPAN_RATIO: f32 = 0.30;
|
const MIN_VERTICAL_SPAN_RATIO: f32 = 0.30;
|
||||||
|
|||||||
@@ -190,6 +190,22 @@ pub fn to_markdown_from_items(items: Vec<TextItem>, options: MarkdownOptions) ->
|
|||||||
let group = page_groups.get(&page).unwrap();
|
let group = page_groups.get(&page).unwrap();
|
||||||
let page_items: Vec<TextItem> = group.iter().map(|(_, item)| (*item).clone()).collect();
|
let page_items: Vec<TextItem> = group.iter().map(|(_, item)| (*item).clone()).collect();
|
||||||
|
|
||||||
|
// Skip table detection on pages with clear multi-column text layout.
|
||||||
|
// Column detection in group_into_lines handles these correctly, and
|
||||||
|
// table detection would incorrectly claim columnar text as table rows.
|
||||||
|
// Only skip when all detected columns are wide (>150pt ~ 2 inches),
|
||||||
|
// indicating true text columns rather than narrow table columns.
|
||||||
|
let columns = crate::extractor::detect_columns(&page_items, page);
|
||||||
|
if columns.len() >= 2 {
|
||||||
|
let min_col_width = columns
|
||||||
|
.iter()
|
||||||
|
.map(|c| c.x_max - c.x_min)
|
||||||
|
.fold(f32::INFINITY, f32::min);
|
||||||
|
if min_col_width > 150.0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let tables = detect_tables(&page_items, base_size);
|
let tables = detect_tables(&page_items, base_size);
|
||||||
|
|
||||||
for table in tables {
|
for table in tables {
|
||||||
|
|||||||
Reference in New Issue
Block a user