FontPruner 字体精简工具

需求

FontPruner 是我们 16 年底开发的一个小工具,可以通过白名单机制来消除字体文件 (.ttf) 中大量的冗余符号,减小字体文件的尺寸,从而降低其包体占用和内存开销。

我们知道,中文字体普遍个头比较大,小的 3-5 MB,大一些的 10-20 MB,有的甚至还更大一些。而通过 FontForge 这样的工具可以看出,汉字仅占字体文件的一半不到(其他为日韩等语言和特殊符号),而其中常用 3000 字又仅占汉字总量的5%,所以理论上这个开销能缩减到原尺寸的 1/10 以内。

(下图是我机器上已安装的字体列表)

font-types.png


思路

要精简这些字体的尺寸,一个简单的做法是,找到中文,英文,标点符号它们各自的起止点,把在范围之外的其他语言字符去掉。这样做逻辑上很简单,但是有几个问题,一是游戏文本中可能用到特殊字符没有在我们框定的范围内,二是汉字中有 80% 是实际上使用频率极低的冷僻字,而偏偏是这些冷僻字笔画特别多,用于描述字形的 glyph data 的数据量,比常用的简化字要大得多。

那么有没有更好的方法呢?

一个改进的方案是,扫描所有游戏中可能出现的文本信息,生成一个活跃字表 (Active Character Table, ACT),然后把这个表之外的字符全部剔除。

使用这种白名单的方式,我们可以更精确地释放那些冷僻字占用的空间,但需要注意的事情有两点:

  1. 当游戏内容改变时,要及时更新我们的 ACT 表。
  2. 聊天框的用户输入可能出现任意字符,建议直接使用系统已有的默认字体

这个白名单方案有一个额外的好处,就是能顺便帮我我们找出所有游戏内的可显示文本,有助于统一规范化游戏内所有文本的引用,便于之后可能的本地化工作。


原理

基于上面说的白名单方案,我们制作了工具 FontPruner,它的主要工作原理如下:

p1.png

简单地解释一下,FontPruner 首先收集游戏内可能出现在屏幕上的各类文本,生成白名单(也就是曾经在游戏中出现过所有字符的集合),然后调用 sfntly 对字体文件做精简处理。


流程

具体的处理流程如下所示:

p2.png

我们可以定期在 Build 机器上执行此工具,这样游戏内容变更时,可以自动更新对应的字体文件。


效果

接下来是精简的具体效果:

p3.png

上图分别是 ttf 包含 1/4/100/200/500 个中文字体时,文件尺寸的变化情况。根据该测试数据可知,在包含 5000 常用字的情况下,对于一个 28MB 的字体文件,我们可以把字体的开销控制在 3-5MB 左右。


资源

关于此工具的更多信息,请访问下面的链接:

https://github.com/GameBuildingBlocks/FontPruner

如果基于此工具有好的想法,欢迎一起讨论~


Gu Lu

Comments
Write a Comment
  • Zs9024 reply

    你好,使用中碰到字体没有正确生成(大小只有9k)的问题,不知道是不是使用姿势不对?

    以下是命令行内容:

    D:\Project\Font\FontPruner-master>python FontPruner.py --inputPath=temp --inputF

    ont=MicrosoftYaHei-Bold.ttf --tempPath=temp

    {'--inputFont': ['MicrosoftYaHei-Bold.ttf'],

    '--inputPath': ['temp'],

    '--tempPath': 'temp'}

    path = temp

    temp\1.txt

    genFilePathList completed temp temp\input_filelist.txt

    提取完成

    extractFileString completed

    fontNameMicrosoftYaHei-Bold.ttf

    extracted file :tmp\intermediate\ChineseOutPut.txt

    extracted file :tmp\intermediate\unChineseOutPut.txt

    文本不存在或者无效tmp\intermediate\ChineseOutPut.txt

    文本不存在或者无效tmp\intermediate\unChineseOutPut.txt

    bulidNewFont completedMicrosoftYaHei-Bold.ttf

    字体文件和temp目录都在FontPruner.py同级,intermediate目录下的文件正常

    另:1).lua文件可以提取,但是.cs文件不行;2)可以支持excel的提取吗?实际的原始文本配置基本都在excel中。

    谢谢

知识共享许可协议
本作品由Gu Lu创作,采用知识共享Attribution-NonCommercial-NoDerivatives 4.0 国际许可协议进行许可。