|
fromhttp://fractal.csie.org/~eric/wiki/Fontconfig
Fontconfig
Table of contents [hide]
1 警告
2 版权声明
3 引言
4 Fontconfig
5 Xft
6 Freetype
7 fonts.conf
8 FAQ
警告
万一本文有更新的版本, 也许可以在 http://fractal.csie.org/~eric/fontconfig 找到,任何使用本文中提及的方法所造成之社会成本损失不会被负责。
版权声明
在保留此版权声明及原作者的情况下, 本文可以被任意转录。有关于更详细的条件请见: http://creativecommons.org/licenses/by-nc-sa/1.0/ -- EricCheng
See also:
Wprint 中文列印 Patch 与 freetype
引言
「为什么我把 xxx 升了之後字就变的难看了?」
「X 的字真是又丑又难设?」
「Fontconfig Xft Freetype 到底是什么关系啊!?!?」
荧幕上的字是用电脑的人整天会看到的,而用荧幕上有限的像素来有效显示文字,又要提高文字的可读性一直不容易。除了点阵字外,早在 80 年代就有的 anti-alias 也使得情况变得很复杂,即使已经过了 20 年,由於
各人的视觉喜好不同 - 没有一种样式可以使每一个人都满意
不同的操作环境与平台以及显示用的装置 (CRT || LCD)
多国语言文字的同时显示
所以能够随著自己的喜好而设定的字型是挺重要的。在各家 X desktop, toolkit 与浏览器的战国时代,前後出现了许多解决方案,而 Fontconfig 是到目前为止,算是广为被支援的一种新的不错的方式,姑且一试,也许它还不能完全令你完全满意,不过比起从前是来得有弹性的多了。
Fontconfig
晚近的 XFree86 除了有了 freetype 的内建,加强了对於 TrueType 等向量字型的支援外,最近 Keith Packard 的 Xft 与 Fontconfig 也是一个对於字型整合所做的尝试,在最新的 XFree86 4.3.x 与freetype/Xft2/Fontconfig 的支援下,X 下的程式对於一个统一的字型选择与绘制介面又进了一步。
虽然 XFree86 本身包含 Fontconfig, Fontconfig 事实上是一个可以独立出来的 介面,它是一个 library 不是一套 user app, 它所做的就是提供一套 font matching 的机制,让使用 Fontconfig 的程式可以不必自己制作一套字型的选取 方法。如此只要使用 Fontconfig 的程式愈多,单一的一套设定档就可以被用在愈 多的应用程式,应用程式本身可以利用 Fontconfig 所得到的字型名称去画字,也 可以架构在自己原先的字型选择架构之上 (如 Qt), 以达成对旧的设定的一定的向 後相容性。
Fontconfig 有许多好处,例如:
字型的安装。与其把要用的字型拿来放在一个目录, 然後用 ttfmkdir / defoma / ttfm 等东西生出 fonts.dir 再指给 xtt/freetype, 再重新启动 X font server 或 xset fp rehash, 现在在只要把字型丢或 symlink 到 ~/.fonts 或任何其他经过指定的目录, 就可以 _立即_ 开始使用了。当然在使用没有支援 Fontconfig 的程式种, 仍然要用传统的方法。Fontconfig 除了可以吃 TrueType, 也可以吃 Type1 或 pcf 等等传统的点阵字。
字型 matching 的设定。虽然 Fontconfig 已经附上了一套不错的设定档让在未被设定的情况下也都能够有一个可以使用的系统,但其实对於个别字型的设定更有弹性。这个是透过 Fontconfig 所使用的 xml 设定档达成的。稍後再说。
Fontconfig 会尽可能找出一套字,可以满足显示不同语言的需求。
Xft
Xft 也是一套 library, 它使用 Fontconfig match 到了所要的字型之後, 来决定该如何来画这些字。Xft 会看情况而决定要不要使用 core protocol 或 XRender 来画字。XRender 是 XFree86 4.x 新增的 extension, 我认为这是为了保留 X 的向 後相容性所新增的一个 hack, 不过因为它可以用来画 anti-aliased 的字,目前 的使用愈来愈广泛。不过 anti-aliased text 只有在使用向量字型的时候有用, 绘制点阵字的时候就要使用 core lib. Core library(以 x-truetype 或 freetype 作为 backend)自然也是可以画向量字,只不过画出来的就不能有 anti-aliased 的效果了。
有时当 XRender 不能使用时(如你是透过网路用一个旧的 X server 来执行 X apps), Xft 也可以使用 core lib 来画字。应用程式不必为这些问题操心,达到资迅隐藏、各谋其政的目的。
Freetype
Freetype 是一个很棒的画字函式库,XFree86 4.3 内含了 2.1.2. Freetype 提供 Xft 如何画字的资迅,包括处理 anti-aliasing 或 hinting. 因此 freetype 的改动会影响到 Xft 画出来的字,而 Fontconfig 的改动会影响到 Xft 如何去选字来画。
fonts.conf
这里所讲的就是最新的 Fontconfig 与 Xft2 的设定。对於旧的 Xft1.0 的 ~/.xftconfig 就不提了。
如果你装了 fontconfig, 那么它应该已经附上了一套预设的设定档。可以到 /etc/fonts/ (一些 Linux distributions) 或 /usr/X11R6/etc/fonts (一些 BSD flavors) 底下找找看 fonts.conf 这个档案。
fonts.conf 是简单的 xml 格式,在 etc/ 里面的 fonts.conf 是 system-wide 的设定,一般不建议直接更改它,可以更改 local.conf 或是自己家目录下面的 ~/.fonts.conf . 对於 fonts.conf 的各种语法,由於 manpage 里头已经写得很详尽了,所以这里只是提及比较重要的一些部份,有兴趣者可以 man fonts-conf. 所有的设定都放在 <fontconfig> 与 </fontconfig> 之间,而其中可以包含许多 tags, 详细的 tags 可以参照 fonts.dtd 或者是 manpage.
<dir> 里面是一个路径,fontconfig 会自己递归地去找这些路径里头的所有字型,如: <dir>/foo/bar/myfonts</dir>
<include> 可以把其他的设定档引进来,它们的格式是一样的。
其中最重要的 element 应该是 <match> 了。match 主要有两种用法, 一种是 pattern match, 另一种是 font match. 前者会把所有的字型 match 出来,所以 针对它的更改会套用到所有的字型的选择方式上。为什么要更改字型的属性? 因这样 可以针对个别的字型告诉 Fontconfig 该如何去处理这些字型,或是告诉 renderer 该如何去画这些字型。这里是一些常用到属性的列表,关於所有的属性 请洽 manpage:
family - String - 就是一般所看到的字型的名称了, 如 Arial
style - String - 字型的 style, 像是 Regular, Bold, Italic...
spacing - Int - 字型的宽度, Proportional 是有不同的宽度, monospace 是单一的宽度 (如 terminal 的字型)
antialias - Bool - 决定该字型是否要被 anti-alias 绘制; 只能用在向量字型上
hinting - Bool - 决定该字型是否要打开 hinting
autohint - Bool - 觉定是否要用 Freetype 自己的 hint 方法来 hint 字型, 还是用预设的方法来 hint
rgba - Bool - 决定定是否要用 subpixel 的方式来画字, 可以是 none (只用灰阶), rgb, bgr, vrgb, vbgr
Hinting 用来最佳化字型显示的方法。由於荧幕的像素有限,向量字型的缩放需要 有更多的考量, 例如当一条线位在两个像素格子中间时, 该取左边的格子还是右边 的格子? 如果这方面的控制没有做好,就常常会出现字型的襯線没有对齐,或是小 字歪七扭八的情况。Hinting 是額外的資訊, 它告訴 renderer 該如何處理這些細節的部份,使得向量字在小字的時候能夠好看。也因此 Hinting 是非常費時費人力的工作,TrueType 字型很多,但是有良好 Hinting 的字型不多。拙劣的 Hinting 就會讓字變得很難看。
為了稍微改善這個問題,freetype 有 autohint 的功能,可以自動為沒有 hint 的字型做 hinting 的工作。另外由於 TrueType 的 hinting 是有專利的,不能完全自由地使用, autohint 就不受這個限制。autohint 自然無法做得像人力的 hint 一樣好,不過至少比沒有 hint 要好些。話雖如此,對於許多筆劃複雜的文字 (如中文) 目前 freetype 的 autohint 還做得不甚完美,而因為建立完整的 hinting 的難度,即使是英文字,原本就很高,內建有 hinting 的中文字型就少之又少了。所以常常有人抱怨中文字在螢幕上很難看,就是沒有理想 hinting, 或者是使用了 autohinter 所造成的一些反效果。
Anti-alias 是將字型在幕後先以數倍的大小來繪製,然後再縮成想要的大小,未滿一格的格子用灰階補點。由於原本 X 所支援的 logic 運算不敷使用,所以才用 XRender 的 extension 來達成目的。除了一般的 Anti-alias 之外,Xft 還支援了為 LCD 所設計的 subpixel rendering.
什麼是 subpixel rendering? 如果你用放大鏡去看 LCD, 會發現一個正方形的像素是由三個長方形小像素構成的。這排列通常是紅綠藍,也就代表如果液晶螢幕的水平解析度是 1024 個像素,它其實有 1024x3 = 3072 個點,只不過這些點是 rgbrgbrgb... 依序排列的。以白底黑字為例,如果需要滿格的像素,rgb 三格就需是全關 (0,0,0), 如果只是右邊三分之二部份, 就關掉 g 和 b, 留下最左邊的 r 開著。這樣子理論上就會有原來三倍的水平像素可以使用,大幅增加了液晶螢幕的解析度。但由於只開著紅色或黃色或其他顏色,會有很明顯的光暈,所以一般會採用 filtering 的方式,把一個次像素的值往左右兩格分散(因為無論對哪一格次像素來說,它的左右兩格的顏色和本身都是不同的,所以往左右兩格分散可以均勻影響亮度),成為 1/3, 1/3, 1/3 分佈;但這樣的壞處是會顯得太模糊了一點,於是再多一層,把原先三格分成 5 格,但權重改為 1/9 2/9 3/9 2/9 1/9。3/9 那一格就是原本的次像素,而鄰近的格子就用這樣的方法分散後和原來該次像素格子的光度值相加,達到像素往中央集中,卻又不太模糊的效果。Windows XP 有個 ClearType 選項可以打開對液晶螢幕顯示最佳化,其基本原理就是 subpixel rendering. Xft 也有這樣的功能,不過 Xft 做得更多,除了 subpixel 外,還加上了 anti-aliasing。Fontconfig 的 rgba 選項就是設定液晶螢幕次像素的排列方式,一般都是 rgb, v 開頭的表示三種顏色是縱向排列。如果好奇的話可以拿放大鏡仔細瞧瞧,或用數位相機近拍下來放大觀察。
很多問題是出在 hinting, 因為許多時候, distribution 會把 freetype 的 bytecode hinting 打開,代表使用字型內部的 bytecode 來做 hinting 修正,如果像 freetype 預設沒有打開或是使用 freetype 裡頭的 autohinter, 有時效果不錯,有時卻不盡人意。另外 hinting 費時費力,大部分的字型設計師在做 hinting 的時候都只有針對點陣字的顯示做 hinting 的工作,這表示如果我們在顯示小字又用 anti-aliasing 的話,通常是不在字型設計師最佳化的範圍內的; 當 hinting 不當的時候,小字 anti-aliasing 就會顯得非常難看(如歪七扭八或擠成一團)。關於這方面 freetype 做了很多的努力, autohinter 也就是讓程式自己做 hinting 的演算法。由於 hinting 實在是個很棘手的問題,Mac OS X 對於 anti-aliasing 字型就都不使用 hinting. 好在 fontconfig 可以讓我們調整這些細部的設定,讓我們針對個別的字型做不同的處理。
話題回到 pattern match: 要使用 pattern match, 只需要加入如下的 pattern, 它就會對所有的字型作用:
<match target="pattern">
...
</match>
中間放的可以是一連串的 test, 然後是一連串的 edit. test 的用法是:
<test qual="any|all|first|not_first"
name="屬性"
compare="eq|not_eq|less|less_eq|more|more_eq|contains|not_contains">
值
</test>
any 指的是說, 只要字型的該屬性 list 之中有一項有符合要 test 的值, test 就會成立。all 的話要 list 之中所有的都符合,first 要第一個符合, not_first 要除了第一個以外有符合的。通常只會用到 any, 預設也是 any. name 裡面填的就是前面所提的屬性, 如 name="family". compare 是比較的條件, eq 是相等, less 是小於, 以此類推。 <test> 所包住的那個值就是要用來比較的值,包括: int, double, string, matrix, bool 等等。一旦 test 的條件都成立, 就會進行到 edit 的階段,代表編輯符合條件上述 test 條件的屬性:
<edit name="屬性"
mode="assign|assign_replace|prepend|append|prepend_first|append_last">
值
</edit>
注意在 fontconfig 中, 屬性 (property) 可以是一個 list, 亦即一個屬性可有許多的值。 assign 是說把 match 到的值取代掉, assign_replace 是說把該 list 的所有值取代成指定的值, prepend 則是插在 list 中被 match 到的那個值的前頭, 以此類推。
fonts.conf 裡面有一個範例:
<match target="pattern">
<test name="prefer_outline">
<bool>true</bool>
</test>
<test name="family">
<string>Times</string>
</test>
<edit name="family" mode="prepend" binding="same">
<string>Times New Roman</string>
</edit>
</match>
這個 pattern match 是說, 當 prefer_outline 的值是 true 的時候, 而且字型的 family 又叫做 Times, 那麼就把它的 family list 前面加入 Times New Roman。這樣做的原因是, Times 本身是點陣字, 如果希望在許多應用程式指定用 Times 顯示時, 不要用點陣字顯示, 而要用 Times New Roman 這個 TrueType 字型顯示, 這樣可以把 Times New Roman 的優先權提在 Times 的前面。 Family matching 是另一種 match 方法,它的用法和 pattern matching 差不多,只是它是針對個別字型的屬性作修改,用法是:
<match target="font">
...
</match>
舉個例子,如果我想讓所有字型預設能夠打開 anti-aliasing, hinting 並且使用 subpixel rendering, 我就寫:
<match target="font">
<edit name="antialias"><bool>true</bool></edit>
<edit name="rgba" mode="assign"><const>rgb</const></edit>
<edit name="hinting"><bool>true</bool></edit>
</match>
但是我可能覺得 Luxi Mono 這個字型在某些時候, subpixel 不太好看, 我就寫:
<match target="font">
<test name="family"><string>Luxi Mono</string></test>
<edit name="rgba"><const>none</const></edit>
</match>
FAQ
Q. 我手上有很多 ttf, 我要怎麼裝它們?
前面說過啦, 把它們全部丟到 ~/.fonts/ 裡頭去吧。做 symbolic link 也可以。丟完之後就跑一下 fc-list 列出所有已安裝的字型看看有沒有在裡面。
Q. 我裝好了字型, 可是我的程式 (rxvt, aterm, gtk1.x) 卻不能使用它們?
因為這些程式是使用 X 的 core fonts, 不是使用 fontconfig 也沒有支援 Xft, 就沒有辦法享受這樣的便利,不過還是可以透過傳統的方式來裝這些字型。新的 gtk2, Gnome2, mlterm, Mozilla (Firebird), Qt3.x 都支援了 fontconfig。
Q. 我想要使用新細明體,可以嗎?
可以, 把 mingliu.ttc 丟到 ~/.fonts 就行了。
Q. 我想要像 Windows 上小字那樣的新細明體,那是怎樣辦到的呢?為什麼在一些大小,新細明體的筆劃會破碎呢?
(新)細明體在 11, 12, 13, 15, 16, 20 點的大小有特別做內嵌的點陣字,換句話說,由於中文字的 hinting 不易,有時點陣字會比較有效。又因為新細明體使用了 bytecode 來組合筆劃, 沒有編進 bytecode interpreter 的 freetype 版本在 render 的時候,就會碎掉。請確定您系統上 freetype2 的 source 之中, include/freetype/config/ftoption.h 裡面的 #defineTT_CONFIG_OPTION_BYTECODE_INTERPRETER 是不是有打開。也不可以使用內建的 autohinter. 由於是上述幾個特定的大小是內建點陣字型,所以沒有被 bytecode interpreter 影響。
確定了 freetype 有編進 bytecode interpreter 之後, 設定讓新細明體在這些大小時顯示內建的點陣字而不要用 anti-aliased, 可以在 ~/.fonts.conf 加入:
<match target="font">
<test name="family"><string>PMingLiU</string></test>
<edit name="antialias"><bool>true</bool></edit>
<edit name="hinting"><bool>true</bool></edit>
<edit name="autohint"><bool>false</bool></edit>
</match>
<match target="font">
<test name="family"><string>PMingLiU</string></test>
<test name="size" compare="less_eq"><int>12</int></test>
<edit name="antialias" mode="assign"><bool>false</bool></edit>
<edit name="hinting" mode="assign"><bool>true</bool></edit>
</match>
Q. 我的細明體 (MingLiU) 的英文字和中文字會等寬?
因為 MingLiU 宣稱自己是 monospaced 字型,但實際上它有兩種寬度:中文的全形以及英文的半形。於是 freetype 就被騙了; 同樣的事情也發生在其他華康的一些字型上。Freetype 有個 globaladvance 的 flag:
<match target="font">
<test name="family"><string>MingLiU</string></test>
<edit name="globaladvance"><bool>false</bool></edit>
</match>
萬一因為不明的原因, 這樣做沒有用, 那麼還可以改 spacing:
<match target="font">
<test name="family"><string>MingLiU</string></test>
<edit name="spacing"><int>0</int></edit>
</match>
0 是 proportional 的 spacing, 100 是 mono, 110 是 charcell.
Q. 我想要把 Gnome2 選單的中英文字型分開設。
Gtk2 可以使用兩組特殊的 alias: Sans 和 Serif. Sans 是無襯線的意思,也就是如 Arial, Verdana 等等邊緣是方的字。Serif 則是有襯線的字,如 Times. 由於 fontconfig 有字型取代的機制, 可以修改 /etc/fonts/fonts.conf 裡面的這一段:
<alias>
<family>Bitstream Vera Sans</family>
<family>Helvetica</family>
<family>Arial</family>
<family>Verdana</family>
<family>Nimbus Sans L</family>
<family>Luxi Sans</family>
<family>Kochi Gothic</family>
<family>PMingLiU</family>
<family>AR PL KaitiM GB</family>
<family>AR PL KaitiM Big5</family>
<family>Baekmuk Dotum</family>
<family>SimSun</family>
<default><family>sans-serif</family></default>
</alias>
與這一段:
<alias>
<family>sans-serif</family>
<prefer>
<family>Bitstream Vera Sans</family>
<family>Verdana</family>
<family>Nimbus Sans L</family>
<family>Luxi Sans</family>
<family>Arial</family>
<family>Helvetica</family>
<family>Kochi Gothic</family>
<family>PMingLiU</family>
<family>AR PL KaitiM GB</family>
<family>AR PL KaitiM Big5</family>
<family>Baekmuk Dotum</family>
<family>SimSun</family>
</prefer>
</alias>
把想要加入替換 list 的字型加進去。排愈前面的字型, 在當他有符合要顯示的語言的文字的時候就會被用上,如我把 PMingLiU 設在文鼎字型前面,PMingLiU 就會在需要顯示中文的時候優先被選到。當然嚴格來說,PMingLiU 並不能算是 Sans-serif 而要算是 serif, 但因為我要跟 Bitstream Vera Sans 搭配,故放在一起。
Q. 我遇到了奇怪的問題,可是不知從何找起,怎麼辦?
XFT_DEBUG 這個環境變數可以顯示不同的偵錯資訊,打開一個 terminal, 把 XFT_DEBUG 設在要執行的程式之前,也許它可以幫助你找到問題。其中可以設的數值有:
XFT_DBG_OPEN 1
XFT_DBG_OPENV 2
XFT_DBG_RENDER 4
XFT_DBG_DRAW 8
XFT_DBG_REF 16
XFT_DBG_GLYPH 32
XFT_DBG_GLYPHV 64
XFT_DBG_CACHE 128
XFT_DBG_CACHEV 256
XFT_DBG_MEMORY 512
要同時開啟某幾個偵錯選項,就把它們的值相加就可以了。如 XFT_DEBUG=3 mozilla 就是以開啟第一和第二選項的模式來開啟 mozilla. 有趣的是,當 GLYPH 和 GLYPHV 同時開啟時, Xft 會在 console 用 ascii art 印出它所畫的字
Q. 我手上的字型都很難看。有什麼比較不錯的字型?
英文字型來說, Bitstream Vera Sans, Bitstream Vera Serif, Bitstream Vera Mono 都是高品質又是 free 的字型。Bitstream Cyberbit 可以免費取得(現在已經不是免費的了),又有頗完整的 Unicode coverage, 包含中日韓等等的字集。另外 Microsoft 和 Monotype 買的 Verdana, Times New Roman 等等也都具有漂亮的 hinting; Kochi Gothic 和 Kochi Mincho 是高品質的 free 日文字型。Arial Unicode MS 的 Unicode coverage 也很大,只是這套字型為了這麼大的 coverage, 相對地在許多地方,如筆劃與外觀,就必須做出一些犧牲。如果要拿來看中文的小字的話,目前最好把 hinting 關掉(中文字型大部分把 hinting 關掉會有比較令人高興的外觀,除了新細明體是一定要打開以外)
Q. 這份 FAQ 實在太沒有幫助了。我要找的問題都找不到。很多地方都寫錯了。
如果有寫錯的地方,為免再造成誤導,也請不吝指正。這裡是 wiki, 也可以直接點上面的 Edit this page 來加入自己的修改。
Q. 我照著這些方法設卻不能動。一切都太麻煩了!
要讓一切合自己的意要付出一定的代價。或許你可以找到一個會設的人,請他吃一頓飯或什麼的,然後找他來幫你照你的意思設。
Screenshot:
//============================ |
|