INFINALITY 补丁的“终极”进化:在 Linux 中启用字体微调和次像素渲染的正确姿势(二)


Thu May 5 18:52:15 UTC 2016 - stecue@gmail.com

  • 在 1 楼添加了调整 INFINALITY 选项的一些说明和经验。

在本系列的上一篇帖子里( [INFINALITY 补丁的“终极”进化:在 Linux 中启用字体微调和次像素渲染的正确姿势(一)) ),我介绍了 INFINALITY-ULTIMATE 补丁的安装方法,并且提到了它可以让我们在运行时(runtime)修改 FreeType 的渲染参数而不需要重新编译。本来,使用一个软件的最好方式就是去读它的 Manual,不过官方网站上的文档 (bohoomil.com/doc/) 只有“Concept overview”是可以打开的,大部分有用的文档都在分散在 GitHub 代码仓库中的 README.md 文件甚至脚本文件的注释中。所以我在这里简述一下 freetype 补丁的最基本的使用方式,希望可以引导新手快速入门并找到查阅官方文档的方式。

首先,一键安装或者添加软件源再通过 zypper 安装带补丁的 freetype 之后,会安装一个 /etc/X11/xinit/xinitrc.d/infinality-settings.sh 文件。这个文件既是简要说明又是配置文件,请务必查看。在目前(FreeType 2.6.2)的版本中,按照这个文件的说明,INFINALITY-ULTIMATE 已经预先 hard-coded 了 ultimate3 级别的参数集了。当然你也可以按照自己的喜好采用其他的预设参数集(比如更锐利的 ultimate1 或者 ultimate2)。要注意的是,尽管这个文件的原话是“create custom ones if necessary. Once modified, “infinality-settings.sh” needs to be copied to “/etc/X11/xinit/xinitrc.d/”.”,但是你要理解这是针对 ArchLinux 用户的说明,作为 OpenSUSE 用户我们要理解原理而不是机械照搬。首先,nick31 打包的时候这个文件已经在 /etc/X11/xinit/xinitrc.d/ 中了。其次,很显然,放到 /etc/X11/xinit/xinitrc.d/ 的意思是令这里面设定的变量成为环境变量。那么你要用预设参数集的话,其实只要设定 INFINALITY_FT 为环境变量就可以了。如果不想动需要用到 root 权限的 /etc/X11/xinit/xinitrc.d/ (或者对 KDE5 是否执行这个目录下的脚本有怀疑的话),按照 openSUSE 的 KDE5 的文档( en.opensuse.org/SDB:KDE_Plasma_5#Environment_variables ),只要把脚本放到 ~/.config/plasma-workspace/env/ 就可以了(GNOME 桌面的环境变量脚本路径请自行查阅)。甚至 ~/.bashrc 中加一行“export INFINALITY_FT=XXX”也行,亲测有效(尽管不推荐)。

如果你对几个预设的参数集的效果都不满意的话,就需要逐个参数进行修改了。说明文件中提到参看 infinality-settings-generic,不过实际上它指的这个文件既不叫“infinality-settings-generic”,也不包含在 nick31 的软件包中(从而也不在我提供的软件包中)。这个 generic 设定文件实际上在 Github(传送门: github.com/bohoomil/fontconfig-ultimate/blob/master/freetype/generic_settings/infinality-settings.sh ),里面详解了各种参数的使用方法。你可以直接把这个 generic 的 infinality-settings.sh 拷贝到 ~/.config/plasma-workspace/env/ 并加以修改,或者在 ~/.bashrc 里添一句 “source /path/to/your/infinality-settings.sh”,亲测也有效(不推荐)。

到这里大家就应该知道如何调整 FreeType 参数了。但是你可能发现,即使把你的 Windows 系统中最新的雅黑字体拷到 ~/.fonts 目录,也无论如何都没法通过仅仅调整 Infinality 的参数来达到我在第一个帖子里演示的效果。那很可能是因为我们还有 fontconfig 配置文件没有调整。这又是一个大坑,我将专开一贴,下次再见!

1赞

INFINALITY 选项繁多,贸然修改可能导致越改越乱,因此需要明确每个选项的效果并且有目的的进行修改(全局优化是个永恒的难题)。而修改的目的无非是“消除锯齿和彩边”,以及“尽量锐利”。选定一个 lcdfilter 之后,锯齿和彩边基本上不需要特殊调整,那么只需要调整锐度就好了。而做到锐利的最根本方法,就是让笔画 (stems) 尽量贴合、吸附 (snap) 到整数像素上(对于包含次像素的 LCD 来说,至少也要调整到次像素上)。以字母“T”为例,如果横和竖的宽度都只有一个像素,但是它们的渲染出来的最终位置却不在整像素而是在半个像素上,那就无论如何都很难锐利起来。本来,TrueType 字体的内置 hinting (调整)信息就是用来解决这个问题的。然而如前所述,很多——甚至绝大多数——字体在开发的时候并未考虑到“对齐到次像素”的问题;此外,自动吸附也可能强烈影响字母的间距(比如对于 min,multi,infinality 之类的“单词”,字母 i 如果左移了大半个像素而右边的字母又右移了大半个像素,很可能字母 i 的左边就太挤而右边就太空,很难看)。所以 INFINALITY 补丁又提供了几个参数来调整“自动吸附到整像素”的强度。按照这样的分析,以下几个选项对字形的影响(不管好坏)就最重要:

INFINALITY_FT_STEM_ALIGNMENT_STRENGTH # 对于 10 ppem (ppem 是字符大小的一个单位)和更大的字符起作用。笔画左右移动的最大允许幅度。100 最大,单位似乎时 1/200 个像素。


INFINALITY_FT_STEM_FITTING_STRENGTH # 对于 10 ppem 和更大的字符起作用。字符上下缩放的最大允许幅度。100 最大,单位似乎是 1/100 个像素。


INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE # 指定一个数值后,对于 ppem 比该数值更大字符将使用 INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=100 和 INFINALITY_FT_STEM_FITTING_STRENGTH=100;对于 ppem = 10 的字符其笔画平移的允许幅度由上面两个选项规定;对于 ppem 在 10 和指定的数值之间的字符,其笔画平移的允许幅度随着 ppem 的增加而线性增加,直到 ppem 增加到此处规定的数值时为止。此时允许幅度也增加到 100。


INFINALITY_FT_GLOBAL_EMBOLDEN_X_VALUE # 在 X 方向加粗。加粗后原来不够整个像素的笔画也许就正好可以填满至少整个像素(或者次像素),这个笔画也就不需要平移太多而破坏字符间距。 

其他的锐化方法,比如 INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTHINFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH , 都不是根本性的方案。根据我的经验,它们对于半个像素或者横跨两个像素的笔画都几乎没法处理,只能略微改善总体锐度,大概算是“二线”办法。尤其是,这两个选项会导致比较粗的笔画被渲染上很多锯齿和其他的 artifact,强烈不建议开启。

根据以上的分析,由于每个字体的笔画粗细不一样,内置的 hinting 强度也不一样,最好是对每个字体设定单独的选项。但是目前好像没有办法针对个别字体单独设定(只找到一个 INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS 但是灵活性太小),那只好尽量小的设定对齐强度——因为对齐强度选项实在是大杀器,一不小心就把字符间距完全搞乱了。总之,我目前的设定是:

export INFINALITY_FT_FILTER_PARAMS="04 22 38 22 04" #copied from ultimate1
export INFINALITY_FT_GRAYSCALE_FILTER_STRENGTH=0
export INFINALITY_FT_FRINGE_FILTER_STRENGTH=0
export INFINALITY_FT_AUTOHINT_HORIZONTAL_STEM_DARKEN_STRENGTH=10 # was 0. Should have no effects for hinted fonts
export INFINALITY_FT_AUTOHINT_VERTICAL_STEM_DARKEN_STRENGTH=25 # was 0. Should have no effects for hinted fonts.
export INFINALITY_FT_AUTOHINT_INCREASE_GLYPH_HEIGHTS=true
export INFINALITY_FT_AUTOHINT_SNAP_STEM_HEIGHT=100
export INFINALITY_FT_CHROMEOS_STYLE_SHARPENING_STRENGTH=0 # Use a little or just turn off to solve the blur I in "T" problem, especially in Arial.
export INFINALITY_FT_WINDOWS_STYLE_SHARPENING_STRENGTH=0
export INFINALITY_FT_STEM_ALIGNMENT_STRENGTH=35 #keep this minimum to less disturb kerning/spacing
export INFINALITY_FT_STEM_FITTING_STRENGTH=0
export INFINALITY_FT_STEM_SNAPPING_SLIDING_SCALE=0 # be carefull! 0 mean apply the above two options to all characters.
export INFINALITY_FT_GAMMA_CORRECTION="1000 110" #
export INFINALITY_FT_BRIGHTNESS="-20" #to make stems darker
export INFINALITY_FT_CONTRAST=30 # This makes the font sharper without distorting the kerning/spacing (?)
export INFINALITY_FT_USE_VARIOUS_TWEAKS=true
export INFINALITY_FT_USE_KNOWN_SETTINGS_ON_SELECTED_FONTS=false
export INFINALITY_FT_GLOBAL_EMBOLDEN_X_VALUE=5

这个设定的思路就是,首先调节 INFINALITY_FT_STEM_ALIGNMENT_STRENGTHINFINALITY_FT_GLOBAL_EMBOLDEN_X_VALUE 将笔画对齐到像素(我是用 Arial 和 Open Sans 的字母"T" 来标定的)。然后调节亮度和对比度 ( INFINALITY_FT_BRIGHTNESSINFINALITY_FT_CONTRAST 尽量减少笔画边缘阴影,进一步锐化。对大部分开启了内置 hiting 的字体的效果看起来还不错。(截图待补)诸位探索到了更好的选项组合,请不吝赐教!

建议楼主出个一键全部搞定的脚本什么的,这些内容看着太复杂了。

好主意,就是得等到有空……
另外现在 INFINALITY 补丁直接控制 FreeType 的行为。这就破坏了 Linux 的软件分层 / 封装,既要配置 fontconfig 又要配置 FreeType ,可能也是感觉复杂的原因。也许 fork 一个项目看能不能把 fontconfig 扩展一下直接包含 INFINALITY 的选项 (或者现在的 fontconfig 就可以直接把自己不认识的选项原样传递给 freetype 处理吗?)……