4、LVGL字体转换工具:在线字体转换器、离线字体转换工具、转换参数配置
好,咱们接着聊字体这块。上一节我把字体格式和渲染原理讲清楚了,这一节咱们直接上手——聊聊怎么把字体文件变成LVGL能吃的格式。
说白了,LVGL不认识你电脑上的.ttf或者.otf文件。它要的是经过转换的、结构化的字体数据。这个转换过程,就是我今天要讲的核心。
4.1 在线字体转换器:快速原型验证
我个人习惯,在项目初期或者做原型验证的时候,优先用在线转换器。为什么?快,不用装环境,浏览器打开就能用。
目前最常用的在线工具是LVGL官方提供的 LVGL Font Converter(网址我就不贴了,你搜一下就有)。它的界面很直观,你上传一个.ttf文件,选好参数,点一下按钮,就能下载一个.c源文件。
我记得有一次,客户临时要改一个开机画面的字体,要求用「思源黑体」显示。我手头没有现成的转换环境,直接打开在线工具,5分钟搞定。嗯,这种场景下在线工具确实香。
在线转换的核心流程:
- 上传字体文件(支持.ttf、.otf、.woff)
- 选择字符范围(全选?还是只选ASCII?)
- 设置字体大小(单位是像素,不是点)
- 选择输出格式(LVGL 8.x 用 .c,LVGL 9.x 用 .bin)
- 点击转换,下载文件
不过我要提醒你,在线工具有个坑——字符集太大时容易超时。我曾经试过转换一个包含2万多个汉字的字体包,浏览器直接卡死了。所以在线工具适合小规模验证,生产环境还是得用离线工具。
4.2 离线字体转换工具:生产环境首选
离线工具,说白了就是能在你电脑上本地运行的程序。最主流的有两个:LVGL官方提供的 lv_font_conv 和 Node.js 版本的 lv_font_conv_cli。
我个人更推荐用Node.js版本,因为它跨平台,Windows、macOS、Linux都能跑。安装也简单:
npm install -g lv_font_conv_cli
装完之后,一行命令就能完成转换。我给你看个我项目里实际用过的例子:
lv_font_conv --font NotoSansSC-Regular.ttf \
--size 16 \
--range 0x20-0x7F \
--range 0x4E00-0x9FFF \
--format lvgl \
--output my_font.c
这条命令干了什么?它把「思源黑体」的.ttf文件,提取了ASCII字符(0x20-0x7F)和常用汉字(0x4E00-0x9FFF),生成了一个16像素大小的LVGL字体文件。
我的经验:离线工具最大的好处是可以写脚本批量转换。我做过一个项目,需要支持中、英、日、韩四种语言,每种语言一个字体文件。写个shell脚本,循环调用lv_font_conv,几分钟全部搞定。
4.3 转换参数配置:细节决定成败
参数配置这块,我踩过不少坑。咱们一个一个说。
4.3.1 字体大小(--size)
这个参数单位是像素,不是点。你想想看,在嵌入式屏幕上,一个像素就是一个物理点。如果你设成16,那每个字符的高度就是16像素。
我建议你根据屏幕DPI来算。比如你的屏幕是2.8寸,分辨率320x240,那16像素的字体大概能显示15行文字。如果屏幕更大,可以适当调大。
4.3.2 字符范围(--range)
这是最容易被忽视的参数。很多人图省事,直接全选所有字符。结果生成的.c文件动辄几兆,MCU根本放不下。
正确的做法是:只包含你需要的字符。比如你的界面只用到了数字、英文字母和100个常用汉字,那就只转换这些。
我教你一个技巧:先写一个测试程序,把所有界面上的字符串打印出来,然后去重,得到一个字符集合。再把这个集合传给转换工具。这样生成的字体文件最小。
注意:如果你用了LVGL的label控件,并且设置了长文本自动换行,那最好把标点符号也包含进去。我曾经因为漏了逗号和句号,导致文本换行时显示异常,排查了半天才发现是字体里没有这些字符。
4.3.3 压缩选项(--compress)
LVGL 8.x 开始支持字体数据压缩。开启后,生成的.c文件会小30%-50%。代价是运行时需要解压,会多消耗一点CPU。
我个人建议:如果你的MCU Flash比较紧张(比如只有2MB),那就开启压缩。如果Flash够用(比如8MB以上),可以不压缩,省点CPU。
4.3.4 抗锯齿(--no-aa)
默认情况下,转换工具会生成抗锯齿的字体,也就是每个字符边缘有半透明像素。这样显示效果更平滑,但占用的Flash也更大。
如果你的屏幕分辨率很低(比如128x64),或者你追求极致的性能,可以关闭抗锯齿。命令加个 --no-aa 就行。
4.4 实战:一个完整的转换案例
好,咱们来走一遍完整的流程。假设我要做一个智能家居控制面板,需要显示中文和英文。
第一步:准备字体文件
我选的是「阿里巴巴普惠体」,免费商用,而且字形清晰。下载.ttf文件放到项目目录。
第二步:确定字符范围
我把界面上所有可能出现的文字列出来:
- 英文:A-Z, a-z, 0-9, 标点符号
- 中文:温度、湿度、开关、设置、返回、确认、取消、灯光、空调、窗帘
去重后,大概有50个汉字和80个英文字符。
第三步:执行转换命令
lv_font_conv --font AlibabaPuHuiTi-Regular.ttf \
--size 18 \
--range 0x20-0x7F \
--range 0x4E00-0x4E2D \
--range 0x6E29-0x6E29 \
--range 0x5EA6-0x5EA6 \
--range 0x5F00-0x5F00 \
--range 0x5173-0x5173 \
--range 0x8BBE-0x8BBE \
--range 0x7F6E-0x7F6E \
--range 0x8FD4-0x8FD4 \
--range 0x56DE-0x56DE \
--range 0x786E-0x786E \
--range 0x8BA4-0x8BA4 \
--range 0x706F-0x706F \
--range 0x5149-0x5149 \
--range 0x7A7A-0x7A7A \
--range 0x8C03-0x8C03 \
--range 0x7A97-0x7A97 \
--range 0x5E18-0x5E18 \
--format lvgl \
--compress \
--output my_font.c
你看,每个汉字我都用Unicode编码指定了范围。虽然命令长了点,但生成的.c文件只有不到20KB,非常精简。
第四步:在LVGL中使用
/* 在代码中声明外部字体 */
LV_FONT_DECLARE(my_font);
/* 创建label时指定字体 */
lv_obj_t *label = lv_label_create(lv_scr_act());
lv_obj_set_style_text_font(label, &my_font, 0);
lv_label_set_text(label, "当前温度:25°C");
嗯,到这里,字体就成功用上了。
4.5 常见问题与避坑
最后,我分享几个我实际踩过的坑,你遇到了可以少走弯路。
坑一:字体文件路径不要有中文
我曾经把字体文件放在「D:\项目\字体\」目录下,结果转换工具死活报错。后来发现是路径里的中文导致解析失败。改成英文路径就好了。
坑二:字符范围不要重叠
如果你指定了 --range 0x4E00-0x9FFF 又指定了 --range 0x4E2D-0x4E2D,工具会报错。因为0x4E2D已经在第一个范围里了。范围之间不能有交集。
坑三:字体大小和屏幕DPI要匹配
同样的16像素字体,在2.8寸屏幕上看着刚好,换到4.3寸屏幕上就显小了。我建议你根据屏幕的物理尺寸来调整字体大小,而不是盲目套用。
好了,字体转换这块就讲这么多。下一节咱们聊聊怎么在LVGL中动态切换字体,实现真正的多语言支持。到时候我会分享一个我实际用过的「字体管理器」方案,挺实用的。