fix(spacing): Refine single-char threshold to distinguish fragments from per-glyph text
The symmetric single-char check (prev==1 OR curr==1) was too aggressive
for PDFs using per-glyph positioning (each letter as a separate item),
causing word spaces to disappear ("EffectiveDate" instead of
"Effective Date").
Now distinguishes three cases:
- Asymmetric (one single-char, other multi-char): generous 0.25 threshold
for fragment rejoining ("b"+"illion", "C"+"ultural")
- Both single-char numeric: generous 0.25 threshold for number continuity
("1"+"0"+"0" within per-glyph numbers)
- Both single-char alphabetic: normal 0.15 threshold to preserve word
spaces in per-glyph Latin text
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
2c825b034d
commit
b2510ffe3e
+18
-4
@@ -754,13 +754,27 @@ fn should_join_items(prev_item: &TextItem, curr_item: &TextItem) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
// Single-character fragments from per-glyph positioning are almost never
|
||||
// standalone words. Use a more generous threshold to rejoin split words
|
||||
// like "b" + "illion", "C" + "ultural", "togeth" + "er".
|
||||
if prev_chars == 1 || curr_chars == 1 {
|
||||
// Single-character fragment joined to a multi-character item: use a
|
||||
// more generous threshold to rejoin split words like "b" + "illion"
|
||||
// or "C" + "ultural".
|
||||
if (prev_chars == 1) != (curr_chars == 1) {
|
||||
return gap < font_size * 0.25;
|
||||
}
|
||||
|
||||
// Both single-char: per-glyph positioning. For numeric characters
|
||||
// (digits within "100,000"), use generous threshold. For alphabetic
|
||||
// per-glyph text ("E"+"f"+"f"...), use normal threshold to preserve
|
||||
// word spaces between letters like "e" (end of word) + "D" (start).
|
||||
if prev_chars == 1 && curr_chars == 1 {
|
||||
if let (Some(p), Some(c)) = (prev_last, curr_first) {
|
||||
let p_numeric = p.is_ascii_digit() || matches!(p, ',' | '.' | '%' | '+' | '-');
|
||||
let c_numeric = c.is_ascii_digit() || matches!(c, ',' | '.' | '%');
|
||||
if p_numeric && c_numeric {
|
||||
return gap < font_size * 0.25;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// With accurate widths, a gap < 15% of font size means glyphs are
|
||||
// adjacent (same word). Anything larger is a deliberate space.
|
||||
return gap < font_size * 0.15;
|
||||
|
||||
Reference in New Issue
Block a user