在 Linux 环境下使用中文的朋友恐怕都会遇到过这个问题。如何让 Linux 显示字体时更好 看呢?
可能会有这样的经验,即使 Ubuntu 使用英文版也不能很好的显示汉字。但是将 Ubuntu
Desktop 的 /etc/fonts/conf.avail/65-language-selector-zh-cn.conf
启用,或者复
制到自己机器上,就好了。
这几天由于读了 wiki.installgentoo.com 上一些有关上网安全的文章后,又重新回到 Firefox 的怀抱,想比较而言 Chromium 的插件可就少很多,并且多半没 Firefox 的好用 呢。但是有一个非常困扰的情况,在 Linux 中, Chromium 即使遇到了网页指定字体不存在 情况,仍旧能很好的展示(不会使用 X11 默认的难看衬线字体)。而 Firefox 则会出现 字体显示大小不一,字体不一的情况。虽然可以使用 userstyles 插件解决,不过写全局或 单个域名总不是个解决办法。所以这次简单研究一下 fontconfig 吧。
freetype 与 fontconfig
虽然原理上可能相同(某没考察过),不过 Windows 的 GDI 也许和 fontconfig 一样,在 找不到字体的情况下会回到默认的字体上(还记得简体中文那万恶的宋体拉丁字体吗?)。
Linux (或其他 unix-like )系统下将字体文件渲染成点阵位图的主要是 freetype ,而对如何访问这些字体的配置则是通过名为 fontconfig 的配置系统来管理的。它的特点 是通过 XML 配置文件(以及指定的 DTD )来对字体的访问顺序、渲染效果进行控制。
我们来看看控制访问。操作系统中使用字体除了直接指定具体的字体名字外(例如: Microsoft YaHei )。一般都提供了这个几个别名,分别是:
- serif ,衬线字
- sans serif 或 sans-serif ,无衬线字
- monospace ,等宽字
对什么是衬线字不清楚的,简单来说就是除了必要的笔画外还有一些修饰痕迹。详细了解可 看这里。
他们都没有具体实际的字体,但都提供了选择。那么如果使用这些字体时,到底实际上使用 了哪个字体,以及如何修改呢?
对于 fontconfig 来说,提供了 fc-match
命令用来查询,例如在某的机器上。
$ fc-match monospace
Menlo.ttc: "Menlo" "Regular"
那么,到底是什么决定了 monospace 使用 Menlo 这个字体呢?
fontconfig 是如何工作的(简要版)
由于某没有读过源代码,所以只能通过使用的经验来解释一下。
自然, fontconfig 是需要通过配置文件来读取的,这些文件都是 XML ,并且语法含义由 DTD 定义(有兴趣的可以去翻一下 DTD 的内容 XD)。
主配置文件在 /etc/fonts/fonts.conf
下,一般会定义字体从哪些目录读取(包括允许
读取个人字体目录 ~/.fonts
等)。 然后会包含 /etc/fonts/conf.d/
下的文件。而
一般来说,Linux 发行版默认会将其他配置文件放在 /etc/fonts/conf.avail
下会做软
链接,来达到方便地调整。
哦~原来配置文件都是这么来的呀~
再来,包括( include
)是按照文件名顺序读取的,开头两位数字从小到大字体读取,
在后面的配置会覆盖前面的文件。所以我们会到看到以 10 、 20 开头的会定义一些通用的
抗狗牙、字体大小等配置。
针对前面提到的 serif 、 sans-serif 以及 monospace 字体别名而言。一般会写在
60-latin.conf
以及 65-nonlatin.conf
中。我们知道一般拉丁字母的字体比较小,
其中不包括那些非拉丁字符对应的字;字体系统也很聪明,如果按顺序读取字体没有该字符
,则会继续寻找配置里的下一个字体文件中的字。
所以,我们在配置字体时,需要优先把拉丁字符字体放在支持非拉丁字符的字体前面。
某在查看了 Gentoo 默认的 65-nonlatin.conf
后发现,中文字体前写的尽是一些日语、
韩语的字体。难怪啦!日语字体里包含一部分汉字,但是又不够多,如果遇见日语字体里不
包含的字,那么就按顺序继续去中文字体里寻找了,所以才会出现同一个页面里,字体不
一致,大小不一的情况。
自定义 fontconfig
既然知道了原因,就可以动手开始改了。
但是,好像直接动那个系统配置不太合适吧?没错, fontconfig 为我们提供了两种方
法;一是修改系统级别的自定义文件,/etc/fonts/local.conf
。另外也可以在用户级别
的 ~/.fonts.conf
,具体就根据喜好啦。
我们拿 monospace 这个别名来举例子。原来在 GitLab 等不太关注汉语字体会出现 textarea 与 pre 等元素中等宽字体出现问题。
我们来进行改造,语法内容大致如下,另外两个也可仿照。
<fontconfig>
<!-- ... -->
<alias> <!-- 注意都是一个别名 -->
<family>monospace</family> <!-- 起个名字 -->
<prefer> <!-- 这里定义字体访问的偏好顺序,靠前在上 -->
<family>Menlo</family>
<family>WenQuanYi Micro Hei Mono</family>
</prefer>
<default><family>DejaVu Sans Mono</family></default> <!-- 这里定义如果全都没找到的情况下默认字体 -->
</alias>
<!-- ... -->
</fontconfig>
CJK 混合用户的痛楚
一般来说一个用户在拉丁字符以外,一般只会使用一类 CJK 语言(或字体)。但是遇到像 某这样同时需要兼顾日语以及汉语的就比较麻烦啦。
Linux GUI 程序访问字体本身似乎是没有针对语种进行区分的,导致访问字体只能按照固 定顺序。比如某把文泉驿微米黑放前面的话,由于支持的字符集非常大,日语假名和特有 汉字也会优先使用文泉驿字体,然而有时这个字体不够好看。但是又不能将日语字体放在 汉语前面,因为日语字体里是包含一些汉语字的 orz 。
折中的解决方案是选用一种两种语言均有字符且较为好看的。目前某使用的是 Google 前阵 子刚刚推出的 Noto Sans S Chinese 字体。显示日语汉字与假名效果还能接受,中文 字也 算好看。
不过,总是会有搞不定的时候啦。 XD
Bonus Time
值得一提的是,网页中 html
元素的 lang
做了定义,表示该元素的内容语言。
并且 Firefox 会根据实际情况选用字体。 不过目前发现字体只是对 html
元素生效
,对页面内的其他元素似乎没用?有待进一步验证。
freetype 补丁
当然,除了使用已经提供的配置来修改渲染效果外,还有直接对 freetype 进行修改的项目 ;自然,这需要比较新版本的 freetype 以及补丁。在 ArchLinux 下可以通过 AUR 中 的 freetype2-infinality 或 freetype2-ubuntu 包来解决;前一个为打过 infinality 补丁集的版本,旨在提供更好的渲染方式以及模拟其他操作系统的显示 效果(例如 MacOSX 与 Windows );后一个则是 Ubuntu 项目中打的补丁版本。在 Gentoo 下,对 media-libs/freetype 打开 infinality USE 即可。
然后针对 /etc/fonts/infinality
里的配置进行调整。 Gentoo 下可以方便的使用
$ eselect lcdfilter
以及
$ eselect infinality
进行修改。
效果与后话
可以在某的配置文件仓库里看到现在正在使用的配置。
这里贴几张目前的效果,还算满意。
汉语
来自维基百科条目
日语
来自维基百科条目
英语
来自维基百科条目
本篇只是浅显地介绍了一下某对 fontconfig 的工作原理的理解,没有读过源代码,不敢说 一定准确。其他有关抗狗牙等渲染上的配置也还没来得及研究。欢迎各位巨巨指教。
以后再补充其他细节吧 XD
__END__