构建初始UI界面

This commit is contained in:
2026-08-30 13:30:59 +08:00
parent e2f199c6bf
commit 67370888a1
11 changed files with 1634 additions and 171 deletions
+95
View File
@@ -0,0 +1,95 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""提取工程 UI 源码中字符串字面量里的非 ASCII 字符(实际显示的汉字),
输出 <仓库根>/ui_cn_chars.txt,供 make_font.py 生成中文字体子集。
用法(在仓库根目录执行,或任意目录均可,脚本自动定位仓库根):
python tools/font_gen/extract_cn.py
"""
import os
import glob
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
UI_DIR = os.path.join(ROOT, 'Drivers', 'BSP', 'UI')
TASK_DIR = os.path.join(ROOT, 'App', 'task')
SCAN = (glob.glob(os.path.join(UI_DIR, '*.c')) +
glob.glob(os.path.join(UI_DIR, '*.h')) +
[os.path.join(TASK_DIR, 'ui_task.c'), os.path.join(TASK_DIR, 'ui_task.h')])
def collect(text):
"""跳过 /* */ 与 // 注释、字符常量,只收集双引号字符串内的非 ASCII 字符。"""
out, i, n = set(), 0, len(text)
blk = line = sstr = cchr = False
while i < n:
c = text[i]
nx = text[i + 1] if i + 1 < n else ''
if blk:
if c == '*' and nx == '/':
blk = False
i += 2
continue
i += 1
continue
if line:
if c == '\n':
line = False
i += 1
continue
if sstr:
if c == '\\':
i += 2
continue
if c == '"':
sstr = False
i += 1
continue
if ord(c) > 0x7F:
out.add(c)
i += 1
continue
if cchr:
if c == '\\':
i += 2
continue
if c == "'":
cchr = False
i += 1
continue
if c == '/' and nx == '*':
blk = True
i += 2
continue
if c == '/' and nx == '/':
line = True
i += 2
continue
if c == '"':
sstr = True
i += 1
continue
if c == "'":
cchr = True
i += 1
continue
i += 1
return out
def main():
chars = set()
for f in SCAN:
if not os.path.exists(f):
print(' skip (not found):', os.path.relpath(f, ROOT))
continue
chars |= collect(open(f, encoding='utf-8-sig', errors='ignore').read())
s = ''.join(sorted(chars))
out_path = os.path.join(ROOT, 'ui_cn_chars.txt')
with open(out_path, 'w', encoding='utf-8') as fp:
fp.write(s)
print('scanned %d files; unique non-ASCII chars: %d' % (len(SCAN), len(s)))
print('->', out_path)
if __name__ == '__main__':
main()
+93
View File
@@ -0,0 +1,93 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""生成中文子集位图字体 ui_font_cn_12.c(LVGL 格式,输出到 Drivers/BSP/UI/)。
前置依赖:
npm i -g lv_font_conv # 离线 TTF/OTF -> LVGL 字体 转换器
pip install fonttools # 仅当字体源是 .ttc 集合时需要(用于抽取单字重)
用法:
python tools/font_gen/make_font.py # 默认:宋体, 12px, 1bpp
python tools/font_gen/make_font.py --bpp 2 # 宋体细笔画发虚时改用 2bpp
python tools/font_gen/make_font.py --font C:/path/to/font.ttf
"""
import os
import sys
import argparse
import tempfile
import subprocess
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
OUT = os.path.join(ROOT, 'Drivers', 'BSP', 'UI', 'ui_font_cn_12.c')
CHARS_FILE = os.path.join(ROOT, 'ui_cn_chars.txt')
FONT_NAME = 'ui_font_cn_12'
def resolve_lv_font_conv():
# 1) 全局 node 模块路径(npm i -g)
try:
groot = subprocess.check_output(['npm', 'root', '-g'], text=True).strip()
p = os.path.join(groot, 'lv_font_conv', 'lv_font_conv.js')
if os.path.exists(p):
return ['node', p]
except Exception:
pass
# 2) PATH 上的可执行
for cmd in ('lv_font_conv.cmd', 'lv_font_conv'):
if subprocess.run(['where', cmd], capture_output=True, shell=True).returncode == 0:
return [cmd]
sys.exit('ERROR: 找不到 lv_font_conv。请先执行: npm i -g lv_font_conv')
def resolve_font(path):
if path:
if not os.path.exists(path):
sys.exit('ERROR: --font 指定的文件不存在: ' + path)
return path
# 默认字体:Windows 宋体集合 simsun.ttc(lv_font_conv 不支持 .ttc,需先抽取 face0)
ttc = r'C:\Windows\Fonts\simsun.ttc'
if os.path.exists(ttc):
try:
from fontTools.ttLib import TTCollection
coll = TTCollection(ttc)
tmp = os.path.join(tempfile.gettempdir(), 'simsun_regular.ttf')
coll.fonts[0].save(tmp)
print('extracted SimSun regular (face0) ->', tmp)
return tmp
except Exception as e:
sys.exit('ERROR: 抽取 simsun.ttc 失败,请 pip install fonttools,或用 --font 指定 ttf: ' + str(e))
sys.exit('ERROR: 未找到 C:\\Windows\\Fonts\\simsun.ttc,请用 --font 指定字体 ttf/otf 路径')
def main():
ap = argparse.ArgumentParser()
ap.add_argument('--bpp', type=int, default=1, help='字体位深 1/2/3(默认 1)')
ap.add_argument('--size', type=int, default=12, help='字号(默认 12)')
ap.add_argument('--font', default=None, help='自定义字体 ttf/otf 路径(默认宋体)')
args = ap.parse_args()
if not os.path.exists(CHARS_FILE):
sys.exit('ERROR: 请先运行 extract_cn.py 生成 ui_cn_chars.txt')
chars = open(CHARS_FILE, encoding='utf-8').read().strip()
cmd = resolve_lv_font_conv()
font = resolve_font(args.font)
cmd += ['--font', font,
'--size', str(args.size),
'--bpp', str(args.bpp),
'-r', '0x20-0x7E', # 含 ASCII,使字体自包含
'--symbols', chars, # 本工程实际显示的汉字子集
'--no-compress', # 关闭 RLE 压缩,保证兼容
'--format', 'lvgl',
'--lv-font-name', FONT_NAME,
'-o', OUT]
print('RUN:', ' '.join(cmd))
r = subprocess.run(cmd)
if r.returncode != 0:
sys.exit('FAILED rc=%d' % r.returncode)
print('OK %d bytes -> %s' % (os.path.getsize(OUT), OUT))
if __name__ == '__main__':
main()