fix(fonttools): keep natural glyph proportions in the ASCII atlas

build_ascii_atlas() used to scale every glyph to fill its cw x ch cell,
so uppercase and lowercase had the same height and narrow shapes such as
i/l/o became solid blobs.

Use one uniform scale ((ch - 2) / units_per_em) for the whole font, keep
the real cap/x-height/descender ratios, and only squeeze glyphs whose ink
is wider than cw - 1. Center by ink width and place the baseline at ch - 4.
This commit is contained in:
TermiNexus committed 2026-10-27 22:21:41 +08:00
1 parent 9bfdaecc6b
commit 5d9df61de0
1 file changed
+9 -5
+9 -5
View File
@@ -522,10 +522,14 @@ def build_ascii_atlas(font: Font*, cw: int, ch: int) -> uint8*:
bw: int = xmax - xmin
bh: int = ymax - ymin
if bw > 0 and bh > 0:
a: float = float(cw - 2) / float(bw)
d: float = float(ch - 4) / float(bh)
tx: float = 1.0 - float(xmin) * a
ty: float = -2.0 - float(ymax) * d
# Natural metrics: one uniform scale for the whole font, so
# cap/x-height and ascender/descender keep their real
# proportions. Only glyphs wider than the cell are squeezed.
scale: float = float(ch - 2) / float(font.units_per_em)
a: float = scale
if float(bw) * scale > float(cw - 1):
a = float(cw - 1) / float(bw)
tx: float = (float(cw) - float(bw) * a) / 2.0 - float(xmin) * a
string.memset(&_ascii_tmp, 0, uint64(cw * ch * 4))
global _edge_count, _min_x, _max_x, _min_y, _max_y
_edge_count = 0
@@ -533,7 +537,7 @@ def build_ascii_atlas(font: Font*, cw: int, ch: int) -> uint8*:
_max_x = -1.0e30
_min_y = 1.0e30
_max_y = -1.0e30
_add_glyph(font, gid, a, 0.0, 0.0, d, tx, ty, 0.0, 0.0, 1.0, 0)
_add_glyph(font, gid, a, 0.0, 0.0, scale, tx, 0.0, 0.0, float(ch - 4), 1.0, 0)
_fill_edges(&_ascii_tmp[0], cw, ch, uint32(0x00FFFFFF))
py: int = 0
while py < ch: