fix(snapcompact): disambiguate digit zero from letter O in frame fonts

The default snapcompact frame fonts (X.org 8x13 for every provider, plus the selectable 6x12 and legacy 5x8) drew digit zero as a bare oval visually indistinguishable from letter O. Image-based compaction OCRs the frames back, so 0 and O were mixed up and compacted identifiers (e.g. Slack IDs) got corrupted.

Zero now carries a disambiguating interior mark the O lacks: an ascending slash in 8x13 and a center bar in 6x12/5x8. unscii-8 (8x8/6x6u shapes) already shipped a slashed zero and is unchanged.

Fixes #8713
This commit is contained in:
roboomp
2026-08-16 10:34:48 +00:00
parent 37eee71978
commit 70af5c300b
5 changed files with 35 additions and 5 deletions
+1 -1
View File
@@ -278,7 +278,7 @@ BITMAP
00
20
50
50
70
50
50
20
+1 -1
View File
@@ -364,7 +364,7 @@ BITMAP
30
48
48
48
78
48
48
30
+3 -3
View File
@@ -380,9 +380,9 @@ BITMAP
18
24
42
42
42
42
4A
52
62
42
24
18
+26
View File
@@ -1353,6 +1353,32 @@ mod tests {
assert!(FONT_SILVER.supported.contains(&'안'), "Silver must cover Hangul syllables");
}
#[test]
fn digit_zero_is_disambiguated_from_letter_o() {
// Regression for #8713: the default snapcompact bitmap fonts drew digit
// `0` and letter `O` as bare ovals that OCR back ambiguously, corrupting
// compacted identifiers. Each `0` now carries an interior slash/bar the
// `O` lacks, so it inks strictly more of the glyph's vertical middle even
// though it is the narrower oval (its wider top/bottom arcs sit outside
// the sampled band). unscii-8 already shipped a slashed zero.
for font in [&*FONT_5X8, &*FONT_6X12, &*FONT_8X13] {
let (cw, ch) = (font.cell_w, font.cell_h);
let width = cw * 2;
let grid = Grid { cols: 2, rows: 1, repeat: 1, cell_w: cw, cell_h: ch };
let px = render_bitmap("0O", width, ch, font, &grid, true);
let band = ch / 4..ch - ch / 4;
let mid_ink = |col0: usize| -> usize {
band
.clone()
.flat_map(|y| (col0..col0 + cw).map(move |x| (x, y)))
.filter(|&(x, y)| px[y * width + x] != 0)
.count()
};
let (zero, oh) = (mid_ink(0), mid_ink(cw));
assert!(zero > oh, "cell {cw}x{ch}: zero must ink its middle more than O (zero={zero}, O={oh})");
}
}
#[test]
fn bitmap_inks_sentences_and_caps_capacity() {
// 40px -> 8 cols x 5 rows = 40 cells (5x8 font).
+4
View File
@@ -2,6 +2,10 @@
## [Unreleased]
### Fixed
- Fixed image-based compaction confusing digit `0` with letter `O` and corrupting compacted identifiers (e.g. Slack IDs): the default frame fonts (X.org `8x13`, `6x12`, `5x8`) drew zero as a bare oval indistinguishable from `O`. Zero now carries a disambiguating interior slash (`8x13`) or bar (`6x12`/`5x8`); unscii-8 already shipped a slashed zero ([#8713](https://github.com/can1357/oh-my-pi/issues/8713)).
## [17.2.15] - 2026-08-12
### Fixed