fix: Restore performance in fontconvert_sdcard.py (#1924)

## Summary

#1910 caused a massive performance degradation in the way rasterized
glyph buffers were handled during pixel iteration. This change restores
the original performance characteristics so the font generation job
finishes in a reasonable amount of time.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**YES**_
This commit is contained in:
Zach Nelson
2026-05-10 12:01:02 -05:00
committed by GitHub
parent 74b8cac928
commit 2ff63884d6
+11 -4
View File
@@ -535,14 +535,16 @@ def rasterize_font_style(fontfile, size, intervals, style_id=0, force_autohint=F
return face return face
return None return None
# Validate intervals: remove codepoints not present in the font # Validate intervals: remove codepoints not present in the font.
# Only check glyph existence via get_char_index — do NOT call
# load_glyph here, as that triggers FT_LOAD_RENDER at the target
# DPI and doubles total rasterization time for no benefit.
print(f" [{style_label}] Validating intervals against font...", file=sys.stderr) print(f" [{style_label}] Validating intervals against font...", file=sys.stderr)
validated_intervals = [] validated_intervals = []
for i_start, i_end in intervals: for i_start, i_end in intervals:
start = i_start start = i_start
for code_point in range(i_start, i_end + 1): for code_point in range(i_start, i_end + 1):
f = load_glyph(code_point) if face.get_char_index(code_point) == 0:
if f is None:
if start < code_point: if start < code_point:
validated_intervals.append((start, code_point - 1)) validated_intervals.append((start, code_point - 1))
start = code_point + 1 start = code_point + 1
@@ -575,13 +577,18 @@ def rasterize_font_style(fontfile, size, intervals, style_id=0, force_autohint=F
# pitch == width and a top-down layout — that holds in the common # pitch == width and a top-down layout — that holds in the common
# case but breaks on padded or flipped bitmaps and corrupts the # case but breaks on padded or flipped bitmaps and corrupts the
# output. Walk by (row, col) using the real pitch instead. # output. Walk by (row, col) using the real pitch instead.
#
# Cache bitmap.buffer in a local — ctypes struct field access
# creates a new Python wrapper object each time, so re-evaluating
# it per pixel is catastrophically slow.
pixels4g = [] pixels4g = []
px = 0 px = 0
buf = bitmap.buffer
abs_pitch = abs(bitmap.pitch) abs_pitch = abs(bitmap.pitch)
for y in range(bitmap.rows): for y in range(bitmap.rows):
row_offset = y * abs_pitch if bitmap.pitch >= 0 else (bitmap.rows - 1 - y) * abs_pitch row_offset = y * abs_pitch if bitmap.pitch >= 0 else (bitmap.rows - 1 - y) * abs_pitch
for x in range(bitmap.width): for x in range(bitmap.width):
v = bitmap.buffer[row_offset + x] v = buf[row_offset + x]
if x % 2 == 0: if x % 2 == 0:
px = (v >> 4) px = (v >> 4)
else: else: