feat(layout): detect sidebar annotations as newspaper columns

Narrow annotation columns beside wide body columns were being
Y-interleaved with body text, producing garbled reading order.
Add sidebar detection with width ratio, line balance, and sparse
density guards to correctly trigger sequential column reading.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Abimael Martell
2026-03-17 17:38:00 -07:00
co-authored by Claude Opus 4.6
parent 04aa6d4ae5
commit 76ea52680b
2 changed files with 167 additions and 7 deletions
+34 -4
View File
@@ -342,7 +342,7 @@ mod tests {
use super::*;
use crate::text_utils::{is_cjk_char, is_rtl_char, is_rtl_text, sort_line_items};
use crate::types::{ItemType, TextLine};
use layout::{detect_columns, is_newspaper_layout};
use layout::{detect_columns, is_newspaper_layout, ColumnRegion};
#[test]
fn test_group_into_lines() {
@@ -863,7 +863,17 @@ mod tests {
.map(|i| make_line(700.0 - i as f32 * 14.0, 350.0, 1))
.collect();
assert!(is_newspaper_layout(&[col1, col2]));
let cols = vec![
ColumnRegion {
x_min: 0.0,
x_max: 300.0,
},
ColumnRegion {
x_min: 300.0,
x_max: 600.0,
},
];
assert!(is_newspaper_layout(&[col1, col2], &cols));
}
#[test]
@@ -897,7 +907,17 @@ mod tests {
.map(|i| make_line(685.0 - i as f32 * 14.0, 350.0, 1))
.collect();
assert!(is_newspaper_layout(&[col1, col2]));
let cols = vec![
ColumnRegion {
x_min: 0.0,
x_max: 300.0,
},
ColumnRegion {
x_min: 300.0,
x_max: 600.0,
},
];
assert!(is_newspaper_layout(&[col1, col2], &cols));
}
#[test]
@@ -929,6 +949,16 @@ mod tests {
.map(|i| make_line(700.0 - i as f32 * 14.0, 350.0, 1))
.collect();
assert!(!is_newspaper_layout(&[col1, col2]));
let cols = vec![
ColumnRegion {
x_min: 0.0,
x_max: 300.0,
},
ColumnRegion {
x_min: 300.0,
x_max: 600.0,
},
];
assert!(!is_newspaper_layout(&[col1, col2], &cols));
}
}