跳转到主要内容

位图字体压缩

TouchGFX从4.25版本开始支持位图字体压缩。

位图字体压缩功能支持对4 BPP位图字体进行 压缩。 其目标是在保持渲染性能的同时, 减小字体数据的大小。

It is very simple to enable font compression in TouchGFX Designer. 只需在Designer中为字体排印选择“4 - compressed”作为“Bpp”即可。

选择压缩4 BPP

两类应用程序可从中获益。 包含数千字符的应用程序(例如中文字符), 或使用超大字号的应用程序。 这类应用程序获益显著。 而仅使用20号 英文字母的应用程序获益有限,因其字体数据本身较小。

压缩率取决于字母大小与字体 大小。 小字体的压缩效果比大字体差。 预期压缩后的大小为原始大小的 30%至70%。

字母在绘制前会被解压到缓存缓冲区。 如果字母不在缓存中,那么在渲染之前就必须先进行解压缩操作。 所用压缩算法(游程编码类型)的解压过程非常简便,通常不会造成问题。 如果字母已在缓存中,渲染性能将略优于常规情况,因为从SRAM渲染比 从外部Flash更快。 缓存大小可在Designer中配置。 请参见下文。

如果多次绘制同一个字母,无论是因为该字母在文本中重复出现,还是因为在动画或滚动效果中重绘文本,在很多情况下,缓存都能省去解压缩的这一步。

Note
缓存大小必须足够存储待绘制文本中最大的字母。

若缓存不够大,应用程序将停止工作。

请参见说明此处

如果平台支持硬件加速绘制,该功能同样适用于压缩字体。

矢量字体可作为压缩字体的替代方案。 当使用多种大小时,矢量字体通常 比压缩字体更节省空间,但会对性能造成更大的影响。

有关矢量字体的相关信息,请单击此处

性能

本部分我们将分析一个使用大量 汉字的应用程序,以及一个包含大量数字的应用程序。

第一个示例将使用 NotoSansCJKsc-Black.otf创建28号字体。 我们包含的字符范围为 0x4E00至0x5E00(另加文本中使用的若干额外字符), 总计 4165个字符。 当然,实际的汉字应用程序可能包含更多字符。

该应用程序显示包含24个汉字的文本:

28号汉字

第二个应用程序使用40号和140号Verdana字体:

40号和140号Verdana字体文本

我们将检查字体数据的大小以及绘制这些字符的性能。

字体数据大小

下表显示了字体数据大小(单位:字节):

字体大小字符未压缩大小压缩后大小节省压缩率
NotoSansCJKsc-Black.otf284,1161,568,599917,170651,4291.7
Verdana.ttf409527,36912,78914,5802.1
Verdana.ttf1401140,4088,21132,1974.9

可见汉字压缩节省了超过 0.5兆字节的数据。 该节省量足以减小外部Flash的容量需求,从而降低BOM成本。

尽管压缩率更高,但Verdana字体的压缩并未节省相近数量的 字节数。 主要原因是字符数量少了很多。
两种Verdana字体的数据总和低于22Kb。 这意味着字体数据能够存储在非常小的器件的内部Flash中。

如果我们将Noto字体生成为矢量字体,则字体数据的大小为1,509,236 字节。 这略小于未压缩字体的大小,但比压缩后的位图字体要大。 在使用多种字号时, 矢量字体在大小方面的优势就会显现出来,因为所有大小的字体都共享数据。

渲染

现在我们将检查渲染压缩字母的性能。 如我们将看到的,缓存大小至关重要。 如果应用程序重复绘制相同字母且有足够的缓存来存储,则性能接近未压缩字体,有时甚至更优。

我们将从使用汉字应用程序开始,缓存大小为10,000 字节。 这足以存储所有使用的字母。

我们测量重绘整个屏幕(包括背景图像)的渲染时间。

测试缓存大小渲染时间/ms
背景图像-5.28 ms
未压缩的Noto-7.57 ms
压缩的Noto100007.55 ms
压缩的Noto50009.41 ms
压缩的Noto20009.42 ms

存储显示的所有字母所需的缓存约为8000字节。 如果缓存大于该值,并且字符在第一帧中已经解压缩,那么在后续所有帧中进行渲染时就无需再次解压缩。 当缓存较小 (5000或2000字节)时,由于 缓存大小不足以存储所有字符,必须反复进行解压缩。 虽然性能会降低,但仍然可用。

现在我们来看第二个应用程序。 这次在每帧中仅重绘那个大数字。 每个数字的大小约为4000字节, 因此10,000字节的缓存足以存储两个数字。 例如,一个5000字节的缓存只能存储一个字母, 因此我们必须反复解压缩。

测试缓存大小渲染时间/ms
背景图像-
未压缩的Verdana-2.46 ms
压缩的Verdana10000
压缩的Verdana50003.57 ms

我们再次看到,如果缓存足够大,性能不会改变,否则性能就会受到影响。

作为最后一个示例,我们将使用一个更具模拟性质的应用程序, 仅显示大量“A”字符:

40字号的Verdana字体文本

测试缓存大小渲染时间/ms
背景图像-
未压缩的Verdana-16.51 ms
压缩的Verdana1000016.45 ms
压缩的Verdana100016.46 ms

所有配置的性能都相同。 由于我们仅 绘制单个字符“A”,因此只需非常小的缓存即可。

缓存必须足够大,以存储帧中绘制的所有独特字符。 在此情况下仅需存储“A”。

结论

总之,如果缓存能够存储 帧中绘制的字母,则压缩字体的性能与未压缩字体完全相同。 这意味着只要缓存足够大,压缩字体可应用于 动画和滚动文本场景。

如果缓存不够大,解压缩字符对性能的影响也不大。 这意味着压缩字体可以 搭配较小的缓存用于静态文本,而不会出现大的性能问题。

配置

As mentioned in the introduction font compression is enabled by selecting it on the individual Typographies in TouchGFX Designer. 应用程序会自动包含必要的解压缩代码。

缓存大小

The cache size can be configured in TouchGFX Designer. 在“Config”选项卡中选择“Text Configuration”:

123

配置缓存大小。

If the cache is smaller than required by the largest compressed letter TouchGFX Designer will report an error in the log:

缓存不足时的错误输出。

将字体缓存更改为大于报告数值。

字体文件显示绘制该字体所有字符所需的最小缓存大小。 可以在TouchGFX/generated/fonts/src/Table_xxx.cpp文件中找到此信息:

140号Verdana字体的压缩大小和最小缓存大小

从上面我们可以发现,140号Verdana字体需要至少4025字节的缓存来绘制所有字母。

缓存失败

如果缓存不够大,无法存储所绘制的字符,应用程序将会停止。 应用程序将调用函数 CompressedFontCache::unableToCache(const GlyphNode* glyphNode, int byteSize)(该函数无返回值)。

只有当手动修改生成的文件时,才会发生这种情况。

限制

无法同时在压缩的4 Bpp和未压缩的4 Bpp中使用相同的字体。