1. 字体渲染基础:像素与矢量字体的区别、点阵字体原理、TrueType/OpenType 字体结构简介

做嵌入式 UI 这么多年,我踩过最大的坑就是「字体」。你想想看,一个好好的界面,布局、颜色、交互都调完了,一上屏,文字糊成一团,或者缺笔画,或者干脆显示不出来。嗯,这种问题十有八九出在字体渲染上。

说白了,字体渲染就是把字库里的字形数据,变成屏幕上一个个像素点的过程。听起来简单,但嵌入式环境里资源有限,CPU 主频低、内存小、屏幕分辨率还五花八门,稍不注意就翻车。

这一章我们先打好基础。把像素字体、矢量字体、点阵原理、TrueType/OpenType 结构这些概念理清楚。后面再讲优化,你才能知道优化到底在优化什么。

核心认知: 嵌入式字体渲染的本质,是在「显示质量」和「资源消耗」之间找平衡。没有银弹,只有取舍。

1.1 像素字体 vs 矢量字体

先问个问题:你手机上的「宋体」和 LED 广告牌上的「16×16 点阵字」,本质区别在哪?

答案是——描述方式不同。

对比维度 像素字体(点阵) 矢量字体(轮廓)
存储方式 每个字对应一张位图 存储数学曲线和指令
缩放效果 放大后锯齿严重 理论上无限缩放不失真
渲染速度 极快,直接拷贝像素 慢,需要实时计算轮廓并填充
内存占用 固定大小,字库体积大 字库小,但渲染时需要临时分配内存
典型场景 低端 MCU、小屏、固定字号 高端 SoC、大屏、多字号

我在一个温控器项目里用过矢量字体。那款芯片主频只有 72MHz,RAM 64KB。每次切换界面,FreeType 库光渲染一个「温」字就要 30 多毫秒,界面卡得不行。后来换成预先生成的点阵字库,渲染时间降到 1 毫秒以内。你看,选对类型比什么都重要。

1.2 点阵字体原理

点阵字体,说白了就是「画好格子,填颜色」。每个字对应一个固定尺寸的位图,比如 16×16 像素,那就是 256 个格子。每个格子要么是 0(不显示),要么是 1(显示)。

存储结构很简单:

// 16x16 点阵字模,每个字 32 字节
// 每行 2 字节,共 16 行
const uint8_t font_16x16_zhong[] = {
    0x00, 0x00,  // 第 1 行
    0x7F, 0xFC,  // 第 2 行
    0x40, 0x04,  // 第 3 行
    // ... 共 16 行
};

渲染时,直接把这 32 个字节按位映射到显存对应位置。没有计算,没有插值,就是纯粹的「内存拷贝 + 位操作」。所以点阵字体在低端 MCU 上特别吃香。

我的习惯: 做点阵字库时,我会把常用字(ASCII、数字、标点)放在前面,生僻字放后面。这样查找时命中率高,缓存友好。

但点阵字体有个硬伤——不能缩放。你做一个 16×16 的字库,就只能用在 16 像素的场景。想用 24 像素?重新生成一套。所以点阵字库的体积会随着字号和字符集数量线性增长。一个 GB2312 全集的 16×16 点阵字库,大概 256KB 左右。对于 64KB Flash 的芯片来说,这就是灾难。

1.3 TrueType/OpenType 字体结构简介

矢量字体就不一样了。它存的不是像素,而是「怎么画这个字」的指令。TrueType 和 OpenType 是目前最主流的两种矢量字体格式。

我刚开始接触 TrueType 时,被它的结构绕晕过。其实核心就三部分:

  • 字形轮廓(glyph outlines):用二次贝塞尔曲线描述每个字的形状
  • 度量信息(metrics):每个字的宽度、高度、基线偏移等
  • 指令表(hinting instructions):告诉渲染器在小字号时怎么「对齐像素」

OpenType 在 TrueType 基础上扩展了 CFF(Compact Font Format)轮廓,支持 PostScript 曲线,还加入了排版特性(连字、变体、上下标等)。但底层逻辑是一样的。

一个典型的 TrueType 字形渲染流程:

  1. 从字库中读取字形索引对应的轮廓数据
  2. 将轮廓坐标从设计空间缩放到目标像素尺寸
  3. 执行 hinting 指令,微调轮廓位置
  4. 扫描线填充,生成像素位图
  5. 将位图输出到显存

你看,步骤 2 和 3 是最耗时的。尤其是 hinting,它本质上是一个微型虚拟机在执行字节码。我在一个项目里试过,关闭 hinting 后渲染速度提升了 40%,但小字号文字边缘变得模糊。这就是典型的「质量 vs 速度」取舍。

我曾经踩过的坑: 在 STM32F4 上直接移植 FreeType 默认配置,没关抗锯齿和 hinting。结果渲染一个「啊」字用了 80 毫秒,界面帧率直接掉到 12fps。后来把 FT_LOAD_TARGET_MONO 和 FT_RENDER_MODE_MONO 打开,速度才上来。

1.4 知识体系总览

下面这张图,把这一章的核心逻辑串起来了。你可以把它当作后续章节的「地图」。

嵌入式字体渲染基础 · 知识体系 像素字体(点阵) 矢量字体(轮廓) 存储:位图矩阵(0/1) 渲染:直接内存拷贝 + 位操作 局限:不可缩放,字库体积大 TrueType:二次贝塞尔 + hinting OpenType:CFF 轮廓 + 排版扩展 渲染:缩放 → hinting → 填充 核心矛盾:显示质量 vs 资源消耗 预渲染 + 缓存 Hinting 裁剪 子像素渲染 后续章节将逐一展开这些优化技术

从这张图你可以看到,无论是点阵还是矢量,最终都要落到「质量 vs 资源」这个天平上。后面 29 章,我们就是在教你怎么在这个天平上找到最优解。

一个小建议: 刚开始学字体渲染,别急着上优化。先把点阵字模的结构读透,再拿一个 TrueType 字体文件用十六进制编辑器打开看看。我当年就是这么干的,看完之后对「字体到底是什么」的理解完全不一样了。