Typeof.net

sfdhanautohint:汉字的 gridfit 解决方案

长久以来,由于汉字的复杂性和庞大数量,汉字字体的屏幕优化一直是极度消耗劳动力的工作,其在低分辨率下的可读性一直很差。sfdhanautohint 将提供自动化的处理手段,以最终解决这个问题。优化的方法是调整笔画(Stem,文字中横向或者竖向的矩形区域,sfdhanautohint 目前只处理横向)的位置和宽度,来优化显示效果。从轮廓中找出笔画的方法已经比较成熟了,sfdhanautohint 是先找出所有的水平线段,然后判断哪些线段对可以笔画。

sfdhanautohint 优化笔画位置的策略是基于以下考量:

背离这四个目标中的每一个都会导致可读性下降,我们用一个扭曲算符 E hat 表示这可读性受损的程度。换言之,一个抽象的「可读性」问题现在成了一个组合优化的问题:优化笔画的位置数组 | left y rangle|y(每一项都是整数,因为笔画的上边缘永远都放在像素上)来最小化 E hat | left y rangle|y

E hat 由以下三个部分组成:

C_ijC ijA_ijA ij 表示笔画 ii 和笔画 jj 碰撞/重合造成的可读性损失,这两个矩阵的值和 ppem 无关,故可以在提取笔画特征完成之后就计算出来。目前的评估策略是基于「重叠比」omega_{ij}ω ij,把它乘以一个比例系数就得到了 C_ijC ijA_ijA ij 的值。另外,对于潜在的位置对称且无重叠的笔画,会有负值的 A_ijA ij 让我们维护「对称性」。系数 k_Sk S 是一个很大的值,表明交换是高成本的,必须竭力避免。数组 | left r rangle|r 为笔画在轮廓中的原始位置,我们同时利用笔画间的相对位置和笔画的绝对位置来计算偏离算子的值,因为对于文字顶底部的笔画来说,偏离算子的第一项总是 0,所以需要同时考虑绝对位置。

优化 | left y rangle|y 的过程可以用遗传算法来实现。不过,单纯地使用遗传算法效率太低,因此在 sfdhanautohint 中使用的实际上是一个混合算法:先是采用确定性的策略来生成一个「种子」| left y_0 rangle|y 0,然后再用遗传算法优化 E hat 值。

在得到一组合适的 | left y rangle|y 之后,我们会根据各个笔画之间的间距分配宽度。sfdhanautohint 会尽量把所有的笔画都显示出来——尽管有些笔画因为空间不足只会分配 1px 的宽度。

不同 ppem 下的 | left y rangle|y 并不相同,当处理完我们关心的 ppem 之后,就可以利用这些 | left y rangle|y 来生成 TT 指令了。目前 sfdhanautohint 并不会对生成的指令做压缩,这是今后的任务之一。生成指令所用到的数据除了 | left y rangle|y,也会用到传统的 Blue Zone,并且会对一些极值点作插值(利用 IP[] 指令),来避免倾斜轮廓过度扭曲。

而效果,就是:

黑白分明当然是更好的。