嵌入式点阵字库方案详解 —— 优缺点分析与 LVGL 官方字库对比
数据格式规格、设备端引擎设计与 LVGL 官方字库的逐维度对比(SVG 图解)
*.py / tests/* 等源码文件为工具内部实现的落点记录,源码暂未公开;不影响阅读方案本身。本文面向使用/评估 Py_FontMaker 的嵌入式开发者,回答三个问题:
- 当前点阵字库方案是什么(数据格式、生成管线、设备端引擎);
- 它的优点和缺点分别是什么(逐条给依据,含代码位置);
- 它和 LVGL 官方点阵字库(lv_font_conv 产物)的差异在哪里(逐维度对比 + 选型建议)。
文中所有结论均以本仓库代码为准(
ttf_conver_FontCvtST_xbf.py、xbf_to_fontlib_bin.py、font_engine_code.py等);LVGL 侧以 v8.3 的lv_font_fmt_txt与 lv_font_conv 官方文档为参照,v9 的接口差异在 §7.4 单独说明。
1. 方案总览
一句话概括:PC 端把 TTF 逐字栅格化成灰度点阵,打包成一个
Font_Lib.bin 烧进外挂 SPI Flash;设备端用自动生成的 C
引擎按需逐字形读取、解压、渲染,向上以
lv_font_t(LVGL)或裸机回调两种接口暴露。
整条链路分两段:
PC 端工具链(Python,跨平台,另有 Web 在线生成与本地 GUI):
| 阶段 | 脚本 | 输入 → 输出 |
|---|---|---|
| ① 栅格化 | ttf_freetype_to_xbf.py(默认,FreeType
直连;--renderer pygame 退回
ttf_conver_FontCvtST_xbf.py) |
TTF → .xbf + .kern.json(每字号/每 bpp
一组) |
| ② 打包 | xbf_to_fontlib_bin.py |
多个 .xbf + 码点配置 → Font_Lib.bin + 全套
C 代码 |
| 配套 | ttf_to_fake_font_c.py / ttf_icon_to_c.py /
emoji_to_c.py / ttf_to_inner_font_c.py /
excel_multi_language_to_c.py |
fake 兜底字库 / 图标字库 / emoji 图片字库 / 内部字库 / 多语言表 |
变形字体(Variable Font)先用 fontTools instancer
按轴(如 wght 字重)固化成静态实例再进管线,一个 VF
文件可产出任意字重的点阵字库。
设备端(自动生成的 C 代码,见
font_engine_code.py 模板):
Font_Lib.h:所有编译期开关(LVGL / hash / RLE / 缓存)与结构体定义;ext_font_engine.c/h:字库引擎(cmap 查表、Flash 读取、RLE 解压、缓存、版本校验、fake 兜底);ext_font_app.c/h:应用层封装,用户只需实现一个读函数并app_font_init(my_flash_read)注册(原型uint32_t (*)(offset, buf, size)),生成代码零修改,与具体 Flash 驱动解耦;cmap_<字库名>.c:稀疏 cmap 的 XIP 常量表(排序数组 + hash 表两套,宏切换);fake_font_*.c:编译进固件的兜底字库。
2. 数据格式详解
2.1 XBF 中间格式
XBF 是①阶段的产物,格式兼容 FontCvtST(ST 提供的 emWin 字体转换工具),因此也可以脱离本方案单独给 emWin/裸机工程使用。本工具直接生成 XBF,不依赖任何第三方 exe。
要点(对应 ttf_conver_FontCvtST_xbf.py:34-157):
- 18 字节头:名称(4B) +
YSize/YDist/BaseLine(各 u16) +bpp(u8) +px(u8) + 保留(u16) +FirstCode/LastCode(各 u16),小端; - 密集 cmap:
[FirstCode, LastCode]区间内每个码点一条{u32 offset, u16 size}(6 B),缺字条目全 0。按码点直接下标寻址,O(1); - 字形记录 = 12
字节属性(
adv_w/box_w/box_h/ofs_x/ofs_y/bytes_per_line,各 u16/s16)+ 行对齐灰度位图; - 码点为 u16,只覆盖 BMP(≤ 0xFFFF);增补平面的 emoji 走图片字库产线;
- 栅格化默认由 freetype-py 直连
FreeType:精确像素字号、原生覆盖度灰度量化到目标
bpp(
gray >> (8 - bpp),MSB 在前),1bpp 默认 mono 渲染;头部 0x0C 保留字段标记坐标约定(0=legacy,1=freetype+top,2=freetype+bottom),并输出.kern.jsonkerning sidecar。
2.2 Font_Lib.bin 外挂字库格式
②阶段把若干 XBF
按各自的码点配置文件(font_type/*.txt,"范围段 +
文本段取并集")裁剪后打进一个 bin。
要点(对应
xbf_to_fontlib_bin.py:85-111, 732-741, 1164-1361):
| 区域 | 起始地址 | 内容 |
|---|---|---|
| 字库头 | 0x0000 |
魔数 "John_LIB"(8B) + 随机版本
magic(u32) + 字体数(u32) + 首字体偏移 u16(=0x1000) |
| 字体信息表 | 0x0100 |
每字体 64 B:44 B 名称 + bpp/cmap_continued/y_size/y_dist/baseline/l_hight/c_hight/first_code/last_code/cmap_offset |
| 字体数据区 | 0x1000 |
依次为每个字体的 cmap 区 + 字形记录区 |
cmap 有两种形态,打包时自动判定(码点集合连续 →
连续表,否则稀疏表,xbf_to_fontlib_bin.py:722-727):
- 连续表:6 B/字
{u32 offset, u16 size},设备端按(code - first_code)直算偏移后读 Flash; - 稀疏表:bin 内 8 B/字
{u16 code, u32 offset, u16 size};同时生成 XIP 的 C 常量表(cmap_*.c),运行时实际查的是 C 表(排序数组走二分,或 hash 表走开放寻址线性探测,CMAP_HASH_ENABLE切换),bin 内的稀疏表当前为预留。
字形记录 = 6
字节属性头(u8 adv_w/box_w/box_h、s8 ofs_x/ofs_y、u8 bytes_per_line,比
XBF 的 12 B 减半)+ 位图(可 RLE)。
版本闭环是这个格式的特色:每次打包生成随机 magic,同时写进 bin 头与
Font_Lib.h 的 FONT_LIB_MAGIC
宏;设备启动时引擎校验二者一致,不一致(固件与字库脱节)则全部退回 fake
字库并可由 app_font_version_ok() 触发字库
OTA,保证字库可以独立于固件发布/升级而不会花屏。
2.3 位图打包方式
2026-09 更新:
--bitstream(默认开)已支持字形内连续位流存储——打包进 bin 时去掉行尾补位,box_w上报真实宽度,与 LVGL 原生打包方式一致;--bitstream False退回下图左侧的行字节对齐布局。下图描述的是两种可选布局的差异。
XBF
中间格式每行按字节对齐(bytes_per_line = ceil(box_w × bpp / 8),保持
FontCvtST/emWin 兼容);打包为 Font_Lib.bin
时默认重打包为连续位流,LVGL 官方也是连续位流:
历史行为说明:旧版(--bitstream False)设备端上报的
box_w 按 bytes_per_line × 8 / bpp
反推,即对齐后的宽度——真实 13 列、2 bpp 会上报 16
列,右侧 3 列为补 0
空白列。位流模式下该问题不复存在(Font_Lib.h 的
BITMAP_BIT_CONTINUOUS_ENABLE 宏由工具随 bin
写死,两者必须一致)。
2.4 RLE 压缩
--rle True(默认开)时对每个字形的位图单独做字节级
RLE(run_length_encoding.py),cmap 中的 size
记录压缩后长度,解码器约 30 行
C(RLE_glyph_bitmap_decode):
- 连续 ≥3 个相同字节 →
[0x80|count][value];不重复串 →[count][字面量…];count ≤ 0x7F; - 逐字形独立压缩意味着随机访问不受影响(无需从头解压整个字库);
- 收益与 bpp 负相关:1 bpp(大片空白/整行重复)收益最大,4/8 bpp 抗锯齿灰度丰富时收益递减,最坏情况反而多出控制字节;
- 代价:静态缓冲模式需要双份位图缓冲(压缩流 +
解压结果,
glyph_bitmap_buf[2][MAX_STATIC_BITMAP_BUF_SIZE]),或改用 malloc 模式(--rlemalloc); - RLE 开关必须与生成 bin
时一致(
Font_Lib.h中BITMAP_RLE_ENCODE_ENABLE由工具写死,不可手改)。
2.5 基线与坐标系
2026-09 更新:基线坐标系已做成可选(
--baseline top|bottom)。top 为 FontCvtST 顶部基准(默认,兼容 emWin 生态);bottom 直接按 LVGL 底部基准存储(ofs_y = yMin、baseline从行框底起算),LVGL 路径零换算。约定标记写在 XBF 头 0x0C 保留字段,打包器自动检测并生成BASELINE_TOP_REFERENCED宏,引擎按宏对齐换算;同一个 bin 内混用两种约定会在打包时报错。
top
模式下,存储侧的垂直量以行框顶部为原点向下计(baseline = ascent、ofs_y = ascent − yMax + 1);而
LVGL 以基线为原点向上计,引擎在
get_glyph_dsc 里做一次整数换算:
3. 设备端引擎
取一个字形的完整路径如下(font_engine_code.py 生成的
ext_font_engine.c):
几个关键设计:
两级缓存
- 字形描述缓存:全局
font_cache[100](EXT_FONT_DSC_CACHE_CNT,可改),按 (unicode, font_type) 线性扫描命中则 0 次 Flash 读——界面上反复出现的字符(数字、标点、固定文案)基本全命中; - 单条 cmap 缓存:每个字体记住上一次查过的
{code, offset, size},get_glyph_dsc和紧随其后的get_glyph_bitmap查同一个字时第二次 cmap 查找免掉。 - 位图本体没有缓存:每次绘制都要从 Flash 读一次位图(详见 §5)。
- 字形描述缓存:全局
三种 cmap 查找
- 连续(全字库/连续区间):直算偏移 + 读 Flash 6 B;
- 稀疏 + hash(默认):XIP C 表开放寻址,平均接近 O(1);
- 稀疏 + 二分:XIP 排序数组,O(log n)。
fake 字库兜底:码点越界、cmap 查不到、
size == 0(生成时就缺字)、bin 版本 magic 不匹配——统统落到编译进固件的 fake 字库显示占位字形,任何情况下不花屏。与存储解耦:引擎只通过
pfunc_get_data(offset/buf/size)拉数据,SPI NOR、QSPI、eMMC、甚至文件系统都能接。LVGL / 裸机双接口:
LVGL_FONT_ENABLE=1时public_font_t就是lv_font_t,ext_font_create()填好get_glyph_dsc/get_glyph_bitmap/line_height/base_line后可直接赋给 style;=0时是等价的自定义结构体,裸机直接调两个回调。LVGL v8 / v9 双版本支持(2026-09 新增):生成代码通过
LVGL_VERSION_MAJOR自动识别大版本。v8 下get_glyph_bitmap直接返回位流位图(v8 渲染器原生按width_bit = box_w × bpp位寻址);v9(按 v9.3 官方发布版契约)下走包装回调——从g_dsc->gid.index取码点、读 Flash 解码后,由共享的ext_font_bitmap_to_a8_draw_buf()展开为 A8(每像素 1 字节,按draw_buf->header.stride对齐)写入 LVGL 分配的draw_buf并返回,与官方lv_font_fmt_txt同一行为;glyph_dsc按版本填bpp(v8)或format + gid(v9)。fake/内部/图标/emoji 四类 C 字库同样双版本适配。
4. 方案优点
按重要性排序:
内部 Flash / RAM 占用极小,CJK 全量字库可用。字库数据全部在外挂 SPI Flash;固件里只有引擎(~2 KB 代码)、稀疏 cmap C 表(仅裁剪字库需要)和 fake 字库。RAM 只需 1~2 个字形位图缓冲(
MAX_STATIC_BITMAP_BUF_SIZE= 最大字号的y_dist²·bpp/8,如 24px/2bpp 约 256 B;56px/2bpp 约 900 B)+ 100 条 dsc 缓存。这是 LVGL 官方两条路径(C 数组占内部 Flash、binfont 占 RAM)都做不到的。字库独立升级的版本闭环。bin 与 C 头文件用随机 magic 配对,版本错落 fake 字库 +
app_font_version_ok()上报,OTA 时字库和固件可以分开发布、分开烧写,工程上非常实用。多字体多字号一包。一个
Font_Lib.bin打包 N 个字体×M 个字号(含图标字库、emoji 字库),信息表统一管理,应用层用枚举取字体;固件与字库的对应关系只有一处。全套 C 代码自动生成,拿来即用。用户唯一要写的是一个 Flash 读函数;LVGL/裸机、hash/二分、RLE 开关、缓存条数都是
Font_Lib.h里的宏。缺字兜底。fake 字库保证任何异常路径都有占位显示,不会出现乱码/花屏——对量产设备是刚需。
按需裁剪,体积可控。码点配置支持"范围 + 界面文案文本"取并集,"只打包界面用到的几百个字"能把字库从几 MB 降到几十 KB,生成时间也降一个量级。
查表结构为外挂场景优化。连续区间直算 O(1);稀疏区间 hash 平均 O(1) 且表在 XIP 不占 RAM;dsc 缓存吸收热点字符的重复查询。
RLE 逐字形压缩,随机访问不受影响,1 bpp 字库收益显著;解码器极简(无状态、无查找表)。
工具链友好:纯 Python 跨平台(服务器无头环境可跑)、Web 在线生成(上传 TTF 选参数下载 zip)、变形字体一个文件出全字重、XBF 兼容 emWin 生态、附带 iconfont/emoji/多语言 Excel 一条龙。
emoji 图片字库:把 Noto Emoji PNG 转成同一 bin 里的一个"字体",用同一引擎渲染——LVGL 官方点阵字库路线没有对应能力(需另接
lv_imgfont)。
5. 方案缺点与限制
同样按影响面排序,均给出代码依据:
渲染吞吐受 SPI 总线限制,位图无缓存。每个字形每次绘制都要 1~2 次 Flash 读(dsc 未命中缓存时 6 B 属性 + 位图本体);滚动长文本、跑马灯时同一个字反复读取。dsc 缓存只缓存 6 B 描述,不缓存位图(
__user_font_get_bitmap每次都走 Flash)。对比 LVGL C 数组的零 IO,这是外挂方案的本质代价,但位图 LRU 缓存是明确的补强空间(见 §9)。无 kerning(字距调整)(2026-09 已解决)。freetype 渲染器自动从 TTF 的 kern/GPOS 表提取字偶对(含 PairPos format1/2 与 Extension),按目标字号缩放为 1/16 px 定点写入 XIP kern 表;引擎在get_glyph_dsc按(left<<16)|right二分查找修正adv_w(与 lv_font_fmt_txt 同款舍入),dsc 缓存存基础值不受污染。advance 存储为整数像素(bin 中 u8,2026-09 部分改进)。freetype 渲染器按 26.6 定点四舍五入,逐字形精确;kern 修正按 1/16 px 定点计算后舍入——这已达到 LVGL 自定义字体回调接口(
dsc->adv_w为整数)能表达的精度上限。与官方剩余差距仅在无 kern 长串的亚像素累积(官方 fmt_txt 同样逐字形舍入输出,实际无差);u8 存储仍限制单字形 advance ≤255 px(72 px 字号内安全)。码点仅支持 BMP。XBF 头与 cmap 都是 u16(
ttf_conver_FontCvtST_xbf.py:43-44),增补平面(含大多数 emoji)必须走图片字库产线;bin 的稀疏 cmap 条目也是 u16 码点(emoji 字体单独用 u32 变体)。部分字体度量硬编码。
xbf_to_fontlib_bin.py:1300-1331里 16/20/22/24/40/48/56/72 号字的y_size/y_dist/baseline是一张为 HarmonyOS Sans 调好的经验值表;不在表内的字号会沿用上一个字体的值(潜在 bug),换其他字体最好核对/修改这张表。强依赖文件命名约定。bpp 从文件名
..._2Bpp解析、字号取name[-7:-5]两位数字(xbf_to_fontlib_bin.py:1112-1113, 1295);文件名不合规会产出错误的元数据,且字号只支持两位数。hash 表装载因子为 1.0。生成时 hash 表大小 = 字符数(
xbf_to_fontlib_bin.py:1436),满载的开放寻址线性探测在聚簇处会退化,未命中查找最坏遍历整表(先被 first/last 区间过滤挡掉大部分)。README 所说 O(1) 是平均意义上的。位图行对齐带来的宽度虚报(2026-09 已解决)。--bitstream(默认开)改为字形内连续位流存储,box_w上报真实宽度;仅--bitstream False的兼容模式仍是旧行为。实测 ASCII 测试字库(16px/2bpp + 24px/1bpp)位流化单独可省约 25% 位图体积(1bpp 收益最大;RLE 开启时行尾 0 本就可压缩,叠加后净收益缩小)。静态缓冲非线程安全。
glyph_bitmap_buf是全局静态,get_glyph_bitmap返回其指针,多线程同时取字会互相踩;LVGL 单线程模型下没问题,裸机双核/RTOS 多任务需自行加锁。RLE 静态模式还要双倍缓冲。生成侧渲染质量依赖 pygame(2026-09 已解决)。XBF 默认由ttf_freetype_to_xbf.py直连 FreeType:FT_Set_Pixel_Sizes精确像素字号(不再 pt 扫描)、原生覆盖度灰度(不再亮度反推)、hinting 五档可选(1bpp 默认 mono 渲染更锐利)、生成速度快一个量级。fake/内部/图标字库生成器仍走 pygame(占位/图标字形对渲染精度不敏感),--renderer pygame可整体退回旧链路。生成的 LVGL 接口是 v8 签名(2026-09 已解决)。生成代码按LVGL_VERSION_MAJOR自动适配 v8 与 v9(v9.3 官方发布版契约),见 §7.4。工程细节类:字体信息区 0x100~0x1000 上限约 60 个字体;
cmap_*.c稀疏表同时以二分数组 + hash 表两份形态生成(XIP 体积 ×2,好在仅裁剪字库有此表);bin 内稀疏 cmap 为预留未被引擎使用。
6. LVGL 官方点阵字库简介
LVGL 官方的静态点阵字库由 lv_font_conv(Node.js
CLI,亦有官方在线转换器)生成,运行时格式是
lv_font_fmt_txt:
lv_font_t
└─ lv_font_fmt_txt_dsc_t
├─ glyph_bitmap[] 位流紧凑打包的位图池
├─ glyph_dsc[] 每字形 {bitmap_index:20, adv_w:12(8.4 定点), box_w/h, ofs_x/y}
├─ cmaps[] 多段 cmap(FORMAT0_FULL/TINY、SPARSE_FULL/TINY 四种)
├─ kern_dsc kerning:pair(字偶对)或 class(字距类矩阵),1/16 px 精度
├─ bpp: 1/2/3/4 抗锯齿位深(--lcd/--lcd-v 另有 ×3 子像素)
└─ bitmap_format RAW 或 COMPRESSED(XOR 行预滤波 + 位级 RLE)
两条使用路径:
- C
数组(
--format lvgl):.c文件编译进固件,内部 Flash XIP,渲染直接取址,零 IO 零额外 RAM;内置 Montserrat 等字体即此形态; - binfont(
--format bin):运行时lv_binfont_create()(v8 为lv_font_load())经文件系统整体载入 RAM。
另有运行时矢量方案(Tiny TTF、FreeType 接口),不属于点阵字库,此处不展开。
7. 与 LVGL 官方字库逐维度对比
7.1 存储与资源占用
| 维度 | Py_FontMaker 外挂字库 | LVGL 官方 lv_font_conv |
|---|---|---|
| 字库数据位置 | 外挂 SPI Flash(Font_Lib.bin) |
内部 Flash C 数组(XIP)或 binfont 载入 RAM |
| 内部 Flash 占用 | 引擎 + 稀疏 cmap 表 + fake 字库(KB 级) | 整个字库(CJK 24px/2bpp 全量 ≈ 3 MB+) |
| RAM 占用 | 位图缓冲(几百 B~1 KB)+ dsc 缓存(100×~12 B) | C 数组 0;binfont ≈ 字库体积 |
| 渲染时 IO | 每字形 1~2 次 SPI 读(dsc 缓存命中 0 次) | 0 |
| 字库独立升级 | ✅ bin 单独烧写/OTA,magic 版本闭环 | C 数组随固件;binfont 可换文件但无版本机制 |
| 多字体打包 | ✅ 一个 bin 装 N 字体 M 字号 + icon + emoji | 每字体独立 .c/.bin |
7.2 格式能力
| 维度 | Py_FontMaker | lv_font_conv |
|---|---|---|
| 码点范围 | BMP(u16);增补平面走 emoji 图片字库 | 全 Unicode(u32),支持多 range 与码点重映射 |
| cmap | 单区间;连续直算 / 稀疏 hash(平均 O(1))或二分 | 多段 cmap,段内二分;无 hash |
| bpp | 1/2/4/8 | 1/2/3/4(另有 --lcd/--lcd-v 子像素 ×3) |
| advance 精度 | 整数像素(bin 内 u8) | 12 bit 8.4 定点(1/16 px) |
| kerning | ✅ kern/GPOS 提取,XIP 表二分查找,1/16 px | ✅ pair / class 两种,1/16 px |
| 位图打包 | 默认字形内连续位流(--bitstream False
可退回行字节对齐) |
默认位流紧凑(可 --byte-align 切回) |
| 压缩 | 逐字形字节级 RLE(随机访问友好) | XOR 行预滤波 + 位级 RLE(--no-compress 可关) |
| 缺字处理 | fake 字库兜底 + 版本校验,永不花屏 | lv_font_t.fallback 字体链(需自行配置) |
| 彩色 emoji | ✅ PNG → 图片字库,同一引擎渲染 | ❌ 点阵路线不支持(需 lv_imgfont 另做) |
7.3 工具链与生态
| 维度 | Py_FontMaker | lv_font_conv |
|---|---|---|
| 实现语言 | Python(pygame + fontTools) | Node.js |
| 使用形态 | CLI / 本地 GUI / Web 在线生成(自部署) | CLI / LVGL 官网在线转换器 |
| 变形字体 | ✅ 轴固化(Web 端拖滑条) | 需自行先固化 |
| 中间格式互通 | XBF 兼容 FontCvtST / emWin 生态 | 无 |
| 字符集配置 | 范围段 + 界面文案文本取并集 | -r 范围 / --symbols 字符列表 |
| 附加产线 | iconfont、emoji、多语言 Excel、内部字库、fake 字库 | 仅字体转换(icon 可把 FontAwesome 当字体转) |
| 渲染引擎 | FreeType 直连(hinting 五档可选;--renderer pygame
退回旧链路) |
FreeType 系(--autohint-off/--autohint-strong) |
7.4 LVGL 版本兼容性
2026-09 更新:生成代码已同时支持 LVGL v8 与 v9 官方发布版,编译期通过
LVGL_VERSION_MAJOR自动切换,无需手工适配。
两个大版本的回调契约不同:
/* v8:get_glyph_bitmap 返回位流位图指针, 渲染器按 width_bit = box_w*bpp 位寻址 */
const uint8_t * (*get_glyph_bitmap)(const lv_font_t *, uint32_t);
/* v9(按 v9.3 契约):由字体把字形展开为 A8(每像素 1 字节)写入 LVGL 分配的
* draw_buf(行按 header.stride 对齐), 返回 draw_buf; 码点从 g_dsc->gid.index 取 */
const void * (*get_glyph_bitmap)(lv_font_glyph_dsc_t *, lv_draw_buf_t *);引擎的实现方式:内部保留 v8
风格的裸回调(ext_font_get_bitmap_raw /
fake_font_get_bitmap_raw,跨字库兜底委托统一走裸回调,任何版本下都可直接调用);v9
下再套一层包装回调,用共享的
ext_font_bitmap_to_a8_draw_buf() 完成 A8 展开——与官方
lv_font_fmt_txt 的行为一致。glyph_dsc 填充由
FONT_GLYPH_DSC_SET_FORMAT 宏按版本落到
bpp(v8/裸机)或
format + gid.index(v9)。fake/内部/图标/emoji
字库同样适配。v9 的 release_glyph 置 NULL(引擎从不设置
g_dsc->entry,LVGL 不会调用它)。
参考工程当前基于 RT-Thread + LVGL v8 验证(https://gitee.com/woowill/ZJ_RT_Thread_LVGL_Font_Nordic.git);v9
路径已在宿主机用 v9.3
结构桩做过运行时逐位验证(tests/test_host_c.py),上板验证欢迎反馈。
7.5 一图流总结
| 字符集小(拉丁/数百字) | 字符集大(CJK 全量/多字号) | |
|---|---|---|
| 内部 Flash 充足 | LVGL C 数组(官方,最优) | LVGL C 数组(能塞下也可) |
| 内部 Flash 紧张 / 字库需独立升级 | 两者皆可,看是否要 OTA | Py_FontMaker 外挂字库(主场) |
8. 选型建议
选 LVGL 官方 lv_font_conv,当:
- 字符集小(拉丁/西里尔/固定文案),C 数组塞得进内部 Flash;
- 对西文排版质量敏感(需要 kerning 与 1/16 px advance);
- 不想引入外挂 Flash 读路径,追求零 IO 的极致渲染性能;
- 使用 3 bpp、LCD 子像素等 lv_font_conv 独有特性。
选本方案(Py_FontMaker 外挂字库),当:
- 需要 CJK 大字符集、多字号,内部 Flash 放不下(最典型场景:手表/手环/仪表);
- 字库需要独立于固件 OTA(版本闭环是现成的);
- 平台是裸机或非 LVGL GUI(双接口 + XBF/emWin 兼容);
- 需要 emoji 图片字库、iconfont、多语言表一条龙;
- 希望用 Web 服务给团队/客户提供在线字库生成。
两者混用也常见:界面骨架用 LVGL 内置 Montserrat(C
数组),中文正文/大字号用本方案外挂字库——lv_font_t
层面完全等价,可在同一个 label 样式体系里共存。
9. 可优化方向
结合 §5 的缺点,按投入产出排序:
- 字形位图 LRU 缓存:在 dsc 缓存旁加 N 条位图缓存(内存允许时按字号分池),滚动场景可把 SPI 读次数降一个数量级——收益最大的单点优化。
- hash 表预留空槽:生成时把表大小设为字符数 × 1.25~1.5,消除满载线性探测的退化,代价是 XIP 体积略增。
- 度量表去硬编码:
y_size/y_dist/baseline直接取 XBF 头的实测值(头里本来就有),删掉按字号查的经验值表,同时消除"字号不在表内沿用旧值"的隐患。 LVGL v9 适配层:✅ 已完成(2026-09),见 §7.4。kerning 支持:✅ 已完成(2026-09),kern 表生成在 XIP C 文件(自动按打包字符集过滤),引擎二分查找修正。- adv_w 升级为 8.4 定点 u16:属性头从 6 B 变 7~8 B,换取西文排版精度。
- 码点扩展到 u32:打通增补平面文字(非 emoji 的生僻字/少数民族文字场景)。
:✅ 已完成(2026-09),随box_w如实上报--bitstream位流存储一并实现,见 §2.3。
本文档由工具代码分析生成,与当前实现保持一致;若代码更新导致描述失配,以代码为准。