From d3e0aeb62ba6d09322bf94f8f4a6d368eaef8969 Mon Sep 17 00:00:00 2001 From: Stefan Blixten Karlsson Date: Sun, 10 May 2026 04:52:13 +0200 Subject: [PATCH] feat: allow unnamed intervals (#1903) ## Summary * Previous `fontconvert_sdcard.py` requires that the intervals are named (i.e. listed in `INTERVAL_PRESETS`, ex. "latin1"), this change will also allow them to be unnamed (ex. "(0x2100-0x214F)") for a more flexible usage. --- ### 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? _**NO**_ --- lib/EpdFont/scripts/fontconvert_sdcard.py | 29 ++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/lib/EpdFont/scripts/fontconvert_sdcard.py b/lib/EpdFont/scripts/fontconvert_sdcard.py index 888f9532..1e410a97 100755 --- a/lib/EpdFont/scripts/fontconvert_sdcard.py +++ b/lib/EpdFont/scripts/fontconvert_sdcard.py @@ -26,6 +26,7 @@ import freetype import struct import sys import os +import re import math import argparse from collections import namedtuple @@ -75,17 +76,39 @@ INTERVAL_PRESETS = { (0xFB00, 0xFB06)], } +# Regex for parsing unnamed hex range intervals: (0xSTART-0xEND) +_HEX_RANGE_PATTERN = re.compile(r'^\(0x([0-9a-fA-F]+)-0x([0-9a-fA-F]+)\)$') + +def parse_hex_range(s: str) -> tuple[int, int] | None: + match = _HEX_RANGE_PATTERN.fullmatch(s) + if not match: + return None + + start_hex, end_hex = match.groups() + start, end = int(start_hex, 16), int(end_hex, 16) + + # Validating Unicode range bounds. + if start > end or end > 0x10FFFF: + return None + return start, end + def resolve_intervals(preset_str): """Resolve comma-separated preset names into a merged, sorted, deduplicated interval list.""" all_intervals = [] for name in preset_str.split(","): name = name.strip().lower() - if name not in INTERVAL_PRESETS: + unnamed_interval = parse_hex_range(name) + if name not in INTERVAL_PRESETS and unnamed_interval is None: print(f"Error: unknown interval preset '{name}'", file=sys.stderr) print(f"Available presets: {', '.join(sorted(INTERVAL_PRESETS.keys()))}", file=sys.stderr) + print("You can also specify unnamed hex ranges like (0x2100-0x214F)", file=sys.stderr) sys.exit(1) - all_intervals.extend(INTERVAL_PRESETS[name]) + + if unnamed_interval is not None: + all_intervals.append(unnamed_interval) + else: + all_intervals.extend(INTERVAL_PRESETS[name]) # Always add replacement character all_intervals.append((0xFFFD, 0xFFFD)) @@ -895,4 +918,4 @@ def main(): if __name__ == "__main__": - main() \ No newline at end of file + main()