增加网络配置界面

This commit is contained in:
2026-09-10 11:36:33 +08:00
parent 020278d4e3
commit 8e1fd3b2b8
44 changed files with 2488 additions and 332 deletions
+128
View File
@@ -127,6 +127,132 @@ def fix_trailing_newline(path):
fp.write(fixed)
# ---------------------------------------------------------------------------
# 低码位符号补回(与箭头字形合并同一模式)
# lv_font_conv 的稀疏 cmap 从符号集中最小码位起算,低于该起点的符号被静默丢弃
# (实测:U+3001 全角逗号 < 0x4E2D 范围起点,未进字体 → 页脚","长期渲染为空白)。
# 处理:对每个此类符号单独生成迷你字体(真实宋体位图),再并入主字体
# (位图 + glyph_dsc + 单码位 cmap,幂等)。
# ---------------------------------------------------------------------------
EXTRA_SYMBOLS = [','] # U+3001 全角逗号(页脚"第 X 页,共 Y 页")
def merge_extra_symbols(font_path, size, bpp):
"""把 lv_font_conv 丢失的低码位符号从迷你字体并入主字体(逐符号、幂等)。"""
import re
for ch in EXTRA_SYMBOLS:
cp = ord(ch)
raw = open(font_path, 'rb').read()
has_bom = raw.startswith(b'\xef\xbb\xbf')
src = raw.decode('utf-8-sig')
if re.search(r'\.range_start\s*=\s*%d\s*,' % cp, src):
print('U+%04X %r 已存在,跳过合并' % (cp, ch))
continue
# 1) 单独生成仅含该符号的迷你字体(真实宋体位图/度量)
tmp = os.path.join(tempfile.gettempdir(), 'font_extra_%04x.c' % cp)
cmd = resolve_lv_font_conv() + ['--font', resolve_font(None),
'--size', str(size), '--bpp', str(bpp),
'--symbols', ch, '--no-compress',
'--format', 'lvgl', '--lv-font-name', 'tmp_extra',
'-o', tmp]
r = subprocess.run(cmd)
if r.returncode != 0:
sys.exit('ERROR: 生成 U+%04X 迷你字体失败' % cp)
mini = open(tmp, encoding='utf-8-sig').read()
# 2) 从迷你字体提取位图字节 / glyph_dsc 字段 / 码位
bm = re.search(r'glyph_bitmap\[\]\s*=\s*\{', mini)
end_bm = mini.find('\n};', bm.end())
body_bm = re.sub(r'/\*.*?\*/', '', mini[bm.end():end_bm], flags=re.S)
bytes_ = re.findall(r'0x[0-9a-fA-F]+', body_bm)
gd = re.search(r'glyph_dsc\[\]\s*=\s*\{', mini)
end_gd = mini.find('\n};', gd.end())
entries = re.findall(r'\{\.bitmap_index = (\d+), \.adv_w = (\d+), \.box_w = (\d+), '
r'\.box_h = (\d+), \.ofs_x = (-?\d+), \.ofs_y = (-?\d+)\}',
mini[gd.end():end_gd])
if len(entries) < 2:
sys.exit('ERROR: 无法解析 U+%04X 迷你字体 glyph_dsc' % cp)
# 取第 1 项(下标 0 是保留空字形)
bmp_ofs, adv, bw, bh, ox, oy = (int(v) for v in entries[1])
cm = re.search(r'cmaps\[\]\s*=\s*\{', mini)
m = re.search(r'\.range_start\s*=\s*(\d+)\s*,\s*\.range_length\s*=\s*(\d+)',
mini[cm.end():])
if not m or int(m.group(2)) != 1:
sys.exit('ERROR: U+%04X 迷你字体 cmap 非单码位,无法并入' % cp)
sym_cp, sym_len = int(m.group(1)), 1
# 3) 并入主字体:位图追加(偏移平移)+ glyph_dsc 追加 + 单码位 cmap 追加
body = re.search(r'glyph_bitmap\[\]\s*=\s*\{', src)
end_main_bm = src.find('\n};', body.end())
main_bytes = len(re.findall(r'0x[0-9a-fA-F]+',
re.sub(r'/\*.*?\*/', '', src[body.end():end_main_bm], flags=re.S)))
glyph_count = len(re.findall(r'\.bitmap_index\s*=\s*\d+', src))
bmp = ',\n\n /* U+%04X %r(来源:宋体迷你字体并入;lv_font_conv 丢低码位符号) */\n ' % (cp, ch) \
+ ', '.join(bytes_)
src = src[:end_main_bm] + bmp + src[end_main_bm:]
gd = re.search(r'glyph_dsc\[\]\s*=\s*\{', src)
end_main_gd = src.find('\n};', gd.end())
entry = ',\n {.bitmap_index = %d, .adv_w = %d, .box_w = %d, .box_h = %d, ' \
'.ofs_x = %d, .ofs_y = %d} /* U+%04X */' % (
main_bytes + bmp_ofs, adv, bw, bh, ox, oy, cp)
src = src[:end_main_gd] + entry + src[end_main_gd:]
cm = re.search(r'cmaps\[\]\s*=\s*\{', src)
end_main_cm = src.find('\n};', cm.end())
cmap = ',\n {\n .range_start = %d, .range_length = %d, ' \
'.glyph_id_start = %d,\n' \
' .unicode_list = NULL, .glyph_id_ofs_list = NULL, .list_length = 0, ' \
'.type = LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY\n }' % (sym_cp, sym_len, glyph_count)
src = src[:end_main_cm] + cmap + src[end_main_cm:]
src = re.sub(r'\.cmap_num = (\d+),',
lambda m: '.cmap_num = %d,' % (int(m.group(1)) + 1), src, count=1)
out = b'\xef\xbb\xbf' if has_bom else b''
open(font_path, 'wb').write(out + src.encode('utf-8'))
print('已合并 U+%04X %r:%d 字节位图,glyph_id=%d' % (cp, ch, len(bytes_), glyph_count))
def verify_coverage(font_path):
"""生成后校验:ui_cn_chars.txt 的全部码位必须进字体 cmap(防静默丢字)。
lv_font_conv 对某些码位会静默丢弃(低于稀疏范围起点、或源字体缺字形),
静默缺字在 UI 上表现为空白,极难发现。此校验把"缺字"变成生成期硬错误。
须在 merge_arrow_glyph / merge_extra_symbols 之后调用(合并的符号也要计入)。
"""
import re
src = open(font_path, encoding='utf-8-sig').read()
# 稀疏 cmap 的 unicode_list_N:十六进制偏移(相对 range_start)
ulists = {}
for m in re.finditer(r'static const uint16_t (unicode_list_\d+)\[\] = \{(.*?)\};', src, re.S):
ulists[m.group(1)] = [int(x, 16) for x in re.findall(r'0x[0-9a-fA-F]+', m.group(2))]
cmaps = [] # (range_start, range_length, sparse_offsets_or_None)
for m in re.finditer(r'\.range_start = (\d+), \.range_length = (\d+), \.glyph_id_start = (\d+),\s*'
r'\.unicode_list = ([^,]+), \.glyph_id_ofs_list = ([^,]+), \.list_length = (\d+), '
r'\.type = (\w+)', src):
ul = m.group(4).strip()
cmaps.append((int(m.group(1)), int(m.group(2)), ulists.get(ul)))
def covered(cp):
for rs, rl, offs in cmaps:
if offs is None:
if rs <= cp < rs + rl:
return True
elif (cp - rs) in offs:
return True
return False
chars = sorted(set(open(CHARS_FILE, encoding='utf-8').read().strip()))
missing = [c for c in chars if not covered(ord(c))]
if missing:
sys.exit('ERROR: 字体缺字 %d 个(UI 将显示空白): %s'
% (len(missing), ' '.join('U+%04X' % ord(c) for c in missing)))
print('coverage OK: %d 个字符全部进字体' % len(chars))
def main():
# Windows GBK 控制台无法打印 ▶ 等符号:降级为替换字符,避免 UnicodeEncodeError 崩溃
try:
@@ -161,6 +287,8 @@ def main():
if r.returncode != 0:
sys.exit('FAILED rc=%d' % r.returncode)
merge_arrow_glyph(OUT) # 补回宋体缺失的 ▶ 字形(幂等)
merge_extra_symbols(OUT, args.size, args.bpp) # 补回 lv_font_conv 丢弃的低码位符号(幂等)
verify_coverage(OUT) # 生成后校验:字符集全部码位必须进字体(防静默丢字)
fix_trailing_newline(OUT) # 规范化末尾换行(pre-commit end-of-file-fixer)
print('OK %d bytes -> %s' % (os.path.getsize(OUT), OUT))