FontPruner 字体精简工具
需求
FontPruner 是我们 16 年底开发的一个小工具,可以通过白名单机制来消除字体文件 (.ttf) 中大量的冗余符号,减小字体文件的尺寸,从而降低其包体占用和内存开销。
我们知道,中文字体普遍个头比较大,小的 3-5 MB,大一些的 10-20 MB,有的甚至还更大一些。而通过 FontForge 这样的工具可以看出,汉字仅占字体文件的一半不到(其他为日韩等语言和特殊符号),而其中常用 3000 字又仅占汉字总量的5%,所以理论上这个开销能缩减到原尺寸的 1/10 以内。
(下图是我机器上已安装的字体列表)
思路
要精简这些字体的尺寸,一个简单的做法是,找到中文,英文,标点符号它们各自的起止点,把在范围之外的其他语言字符去掉。这样做逻辑上很简单,但是有几个问题,一是游戏文本中可能用到特殊字符没有在我们框定的范围内,二是汉字中有 80% 是实际上使用频率极低的冷僻字,而偏偏是这些冷僻字笔画特别多,用于描述字形的 glyph data 的数据量,比常用的简化字要大得多。
那么有没有更好的方法呢?
一个改进的方案是,扫描所有游戏中可能出现的文本信息,生成一个活跃字表 (Active Character Table, ACT),然后把这个表之外的字符全部剔除。
使用这种白名单的方式,我们可以更精确地释放那些冷僻字占用的空间,但需要注意的事情有两点:
- 当游戏内容改变时,要及时更新我们的 ACT 表。
- 聊天框的用户输入可能出现任意字符,建议直接使用系统已有的默认字体
这个白名单方案有一个额外的好处,就是能顺便帮我我们找出所有游戏内的可显示文本,有助于统一规范化游戏内所有文本的引用,便于之后可能的本地化工作。
原理
基于上面说的白名单方案,我们制作了工具 FontPruner,它的主要工作原理如下:
简单地解释一下,FontPruner 首先收集游戏内可能出现在屏幕上的各类文本,生成白名单(也就是曾经在游戏中出现过所有字符的集合),然后调用 sfntly 对字体文件做精简处理。
流程
具体的处理流程如下所示:
我们可以定期在 Build 机器上执行此工具,这样游戏内容变更时,可以自动更新对应的字体文件。
效果
接下来是精简的具体效果:
上图分别是 ttf 包含 1/4/100/200/500 个中文字体时,文件尺寸的变化情况。根据该测试数据可知,在包含 5000 常用字的情况下,对于一个 28MB 的字体文件,我们可以把字体的开销控制在 3-5MB 左右。
资源
关于此工具的更多信息,请访问下面的链接:
https://github.com/GameBuildingBlocks/FontPruner
如果基于此工具有好的想法,欢迎一起讨论~
- Written on [2017-09-08] in 2h; Posted on [2017-09-15]
- 本文首发于 西山居技术
- 本文同时发于 知乎专栏 - 游戏人间
(全文完)