0
0

sfdhanautohint:汉字的 gridfit 解决方案

Typeof 发表于 1970年01月01日 08:00 | Hits: 1053

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

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

  • 两个笔画在调整之后的相对位置不能交换。
  • 在低分辨率下,完整保留汉字(尤其是复杂文字)的所有笔画是不现实的,因此需要保留的是文字的整体轮廓;而像素数不足会造成笔画相碰,导致可读性下降,这是最需要避免的情况。
  • 为了避免笔画相碰,我们需要合并一些笔画;然而位于文字每个联通分支(在sfdhanautohint里叫做部首)边缘处的笔画不能和该部首内部的笔画合并,否则会导致字形特征丢失,同样造成可读性下降。
  • 小尺寸下汉字的字面大小的抖动是很影响可读性的,因此字面大小不能有太大变化。
  • 在以上三条保证的前提下,笔画之间的相对位置要尽量不变。

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

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

  • 碰撞-重合算子K hatK̂,定义为K hat | left y rangle = sum__{i, j; r_j < r_i} "{" C_{ij} ~ if bf (y_i - y_j = 1), A_{ij} ~ if bf (y_i = y_j), 0 right "}"K̂|y⟩ = ∑i, j; r j  r i{C ij if(y i − y j = 1), A ij if(y i = y j), 0}
  • 交换算子S hatŜ,定义为S hat | left y rangle = sum__{i, j; r_j < r_i} "{" k_S ~ if bf (y_j > y_i), 0 right "}"Ŝ|y⟩ = ∑i, j; r j  r i{k S if(y j > y i), 0}
  • 偏离算子alpha hatα̂,定义为alpha hat | left y rangle = sum __ i ~ mu_i | left { y_i - [min rm | left y rangle + (max rm | left y rangle - min rm | left y rangle){ r_j - min rm | left r rangle} over {max rm | left r rangle - min rm | left r rangle}] } right | + sum__i delta_i | left y_i - r_i right |α̂|y⟩ = ∑i μ i|y i − [min|y⟩ + (max|y⟩ − min|y⟩)(r j − min|r⟩/max|r⟩ − min|r⟩)]| + ∑iδ i|y i − r i|

C_ijC ij和A_ijA ij表示笔画ii和笔画jj碰撞/重合造成的可读性损失,这两个矩阵的值和 ppem 无关,故可以在提取笔画特征完成之后就计算出来。目前的评估策略是基于「重叠比」omega_{ij}ω ij,把它乘以一个比例系数就得到了C_ijC ij和A_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[]指令),来避免倾斜轮廓过度扭曲。

而效果,就是:

黑白分明当然是更好的。

原文链接: http://typeof.net/m/introducing-sfdhanautohint.html

0     0

评价列表(0)