Files
STM32F4-Base/docs/UI 设计/UI_中文字体生成与配置.md
T
2026-09-02 14:22:33 +08:00

153 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# UI 中文字体生成与配置
> **适用范围**:STM32F4-Base 远程单色屏(160×160,1bpp,`LV_COLOR_FORMAT_I1`)的 LVGL 中文显示。
> **目标**:把工程实际用到的汉字生成**子集化 1bpp 位图字体**,挂到 `LV_FONT_DEFAULT`,使菜单/标签正常显示中文并推流到客户端。
---
## 1. 背景
- LVGL 内置字体(Montserrat 等)**不含中文**;`LV_FONT_SIMSUN_16_CJK` 等全字库体积过大,不适合 160×160 小屏。
- 本工程显示是 **1bpp 单色**:像素 1=亮(白)/0=暗(黑),与客户端 `mono_to_png` 的 `1→白` 语义一致。
- 方案:用 `lv_font_conv` 把系统中文字体(**宋体 SimSun**)按"实际用到的汉字 + ASCII"子集,生成 1bpp 的 LVGL 字体 `.c`。
生成产物:`Drivers/BSP/UI/ui_font_cn_12.c`(变量名 `ui_font_cn_12`)。
---
## 2. 工具准备
### 2.1 工具与环境确认
| 工具 | 用途 | 安装 |
|------|------|------|
| Node.js (≥ v14) | 运行 `lv_font_conv` | 已具备 |
| `lv_font_conv` | TTF/OTF → LVGL 字体 `.c`(官方离线转换器) | `npm i -g lv_font_conv` |
| Python `fontTools` | `make_font.py` 读取 `.ttc` 集合时抽取单字重(仅在字库为 `.ttc` 时需要) | `pip install fonttools` |
安装完成后验证可用:`lv_font_conv -h` 能打印用法即成功。
---
## 3. 提取字符集(只取会显示的汉字)
已落库脚本 `tools/font_gen/extract_cn.py`:扫描 `Drivers/BSP/UI/*.c/.h` 与 `App/task/ui_task.c/.h` 中**字符串字面量**里的非 ASCII 字符,跳过 `/* */`、`//` 注释与字符常量(避免把注释里的汉字也打进字体、徒增体积),输出 `<仓库根>/ui_cn_chars.txt`。脚本自动定位仓库根,可在任意目录运行。
**执行命令(在仓库根目录):**
```bash
python tools/font_gen/extract_cn.py
```
输出示例:
```
scanned 9 files; unique non-ASCII chars: 83
-> D:\Code\DTU Code\STM32F4-Base\ui_cn_chars.txt
```
产物 `ui_cn_chars.txt` 为本工程实际显示的汉字清单(当前 83 字),可留作字符集记录。
---
## 4. 生成字体
已落库脚本 `tools/font_gen/make_font.py`:自动定位 `lv_font_conv`(全局安装或 PATH)、自动处理宋体 `.ttc` 的 face0 抽取,直接生成 `Drivers/BSP/UI/ui_font_cn_12.c`。
**前置依赖(仅需一次):**
```bash
npm i -g lv_font_conv # TTF/OTF -> LVGL 字体 离线转换器
pip install fonttools # 仅当使用 .ttc 集合字体(如宋体)时需要
```
> 若 `npm i -g lv_font_conv` 报代理错误,先清代理:`npm config delete proxy` / `npm config delete https-proxy`。
**执行命令(在仓库根目录):**
```bash
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 # 换其他字体
```
输出示例:
```
extracted SimSun regular (face0) -> C:\Users\...\Temp\simsun_regular.ttf
RUN: lv_font_conv.cmd --font ... --size 12 --bpp 1 -r 0x20-0x7E --symbols ... --no-compress --format lvgl --lv-font-name ui_font_cn_12 -o ...\ui_font_cn_12.c
OK 36393 bytes -> ...\Drivers\BSP\UI\ui_font_cn_12.c
```
参数说明:
- `--bpp 1`:单色无抗锯齿;体积最小。**注意** lv_font_conv 在 1bpp 下斜线/细笔画偶发"丢像素",宋体尤甚。
- `--bpp 2/3`:字形带灰度,渲染到 1bpp 屏时按 `LV_DRAW_SW_I1_LUM_THRESHOLD` 阈值化,笔画更连贯;子集仅几十~上百字,体积仍很小。
- `--no-compress`:关闭内置压缩,规避 `LV_FONT_COMPRESSED` 未启用导致的兼容问题。
- `--lv-font-name ui_font_cn_12`:生成的 `lv_font_t` 变量名,须与下面 `LV_FONT_DECLARE` 一致。
---
## 5. 配置接入
### 5.1 声明与设为默认字体(`Lib/lv_conf.h`)
该文件当前为 **UTF-8(带 BOM)**。历史上它曾为 GBK,且工作区版本因某次整文件文本重写导致中文注释被 `U+FFFD` 不可逆损坏(`HEAD` 中的 GBK 版本仍干净)。
> **损坏恢复**:若二次损坏,不要用整文件文本重写。正确做法:
> `git show HEAD:Lib/lv_conf.h` 以 `gbk` 解码得到干净中文 → 叠加第 5.1 节的字体配置改动 → 重新写为 `utf-8-sig`(UTF-8 带 BOM)。这样中文可完整恢复,不会引入 `U+FFFD`。
```c
/* 自定义中文 1bpp 字体:由 lv_font_conv 生成(ASCII + 本工程所需汉字子集) */
#define LV_FONT_CUSTOM_DECLARE LV_FONT_DECLARE(ui_font_cn_12)
/* 默认字体:中文 1bpp 子集字体(已含 ASCII),菜单/标签均使用它 */
#define LV_FONT_DEFAULT &ui_font_cn_12
```
> 字体 `.c` 自身通过 `#ifndef UI_FONT_CN_12` 自包含,编译进工程即生效;无需额外 `#include`。
### 5.2 加入 Keil 工程
`MDK-ARM/STM32F407-Demo.uvprojx` 的 `Drivers/BSP/UI` 组追加(纯 ASCII 插入):
```xml
<File>
<FileName>ui_font_cn_12.c</FileName>
<FileType>1</FileType>
<FilePath>..\Drivers\BSP\UI\ui_font_cn_12.c</FilePath>
</File>
```
---
## 6. 编译验证
```bash
@build # 即 MDK-ARM\build.bat,调用 UV4 全量重建
```
要求:`0 Error(s), 0 Warning(s)`。重新生成/修改字体或 `lv_conf.h` 后务必重建验证。当前已验证通过,`ui_font_cn_12.c` 正常编入。
---
## 7. 注意事项
1. **1bpp 细笔画发虚**:宋体在 1bpp 下可能丢像素。若上板/客户端中文偏淡,把第 4 节 `--bpp` 改为 `2` 重生成即可(子集小,体积可接受)。
2. **字符集变更**:以后新增中文菜单项,须重跑第 3、4 节(重新提取 `ui_cn_chars.txt` 并生成),否则新字显示为方框。
3. **编码**:UI 源文件须为 **UTF-8(带 BOM)**,LVGL 按 UTF-8 解码中文串;字体 `.c` 为纯 ASCII,无编码风险。当前 Keil 已加 Misc Controls 抑制项,无需额外 `--locale=english`。
4. **字体体积**:12px + 1bpp + ~83 字 ≈ 36KB(RO-data);改 bpp 2 约翻倍,仍在 F407 Flash 余量内。
5. **换字体**:黑体用 `simhei.ttf`(单文件免抽取);其余字体同理替换 `--font` 路径后重生成。
---
## 8. 文件清单
| 文件 | 说明 |
|------|------|
| `Drivers/BSP/UI/ui_font_cn_12.c` | 生成的中文 1bpp 字体(变量 `ui_font_cn_12`) |
| `Lib/lv_conf.h` | 字体声明与默认字体配置 |
| `MDK-ARM/STM32F407-Demo.uvprojx` | UI 组包含该字体 `.c` |
| `ui_cn_chars.txt`(工程根) | 实际显示汉字清单记录(可删) |
| `tools/font_gen/extract_cn.py` | 提取字符集脚本(见第 3 节) |
| `tools/font_gen/make_font.py` | 生成字体脚本,自动定位 lv_font_conv 并处理 `.ttc`(见第 4 节) |