Add row-stripe rect fallback for table detection

When PDF tables use full-width alternating row shading (row-stripe rects),
the normal rect grid detection fails because all rects share the same X/width,
collapsing to ~1 column. Add a fallback that uses rect Y-edges for rows and
text X-position clustering for columns, with a lower 15pt threshold to
separate narrow columns like row numbers and dates.

Also fix continuation-row merging in table formatting to not merge short
single-cell rows (≤5 chars) that are section sub-headers (e.g. month names).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Abimael Martell
2026-02-23 09:39:25 -08:00
co-authored by Claude Opus 4.6
parent 43c9a81388
commit dcbea3f652
2 changed files with 276 additions and 2 deletions
+12 -2
View File
@@ -85,9 +85,19 @@ fn clean_table_cells(cells: &[Vec<String>]) -> (Vec<Vec<String>>, Vec<String>) {
continue;
}
// Check if this is a continuation row (first column is empty but others have content)
// Check if this is a continuation row (first column is empty but others have content).
// A row with only 1 short non-empty cell (besides the first) is more likely a
// section sub-header (e.g. "JAN", "FEB") than overflow text — don't merge it.
let non_first_cells: Vec<&str> = row
.iter()
.skip(1)
.map(|c| c.trim())
.filter(|c| !c.is_empty())
.collect();
let is_short_subheader = non_first_cells.len() == 1 && non_first_cells[0].len() <= 5;
let is_continuation = first_cell.is_empty()
&& row.iter().skip(1).any(|c| !c.trim().is_empty())
&& !non_first_cells.is_empty()
&& !is_short_subheader
&& cleaned.len() > 1; // Don't merge into the first row (header)
if is_continuation {