Linux 桌面系統字體配置要略


字體顯示效果測試

這一段是為了測試宋體字的顯示效果,包括宋體里面自帶的英文字體,“This is english,how does it look like?”。這一行是小字。后面幾個字是加粗的宋體。標點符號“,。:;!”
  這一段是為了測試黑體字的顯示效果,包括黑體里面自帶的英文字體,“This is english,how does it look like?”。這一行是小字。標點符號“,。:;!”。微軟雅黑是什么樣子的呢“,。:!”?
  This paragraph shows how does serif english fonts look like,包括英文里面夾雜中文的顯示效果。Is serif same as Times New roman?
  This paragraph shows how does sans-serif english fonts look like,包括英文里面夾雜中文的顯示效果。Is sans-serif same as Arial?
  This paragraph shows how does ui fonts look like,還有專門的界面字體,比如Windows中的Tahoma字體:File->New->New Project。
    #include <stdio.h>
    int main(){
      return 0;//很顯然這是為了測試等寬字體
    }

    #include <stdio.h>  //觀察下面的代碼了解monospace是否等於Courier New
    int main(){
      return 0;
    }

 

字體的分類及其用途

在文章最開始的一個部分(也就是這部分之前的內容),我特意寫了一些文字用來測試各種字體的顯示效果。這些測試文本我在 HTML 源代碼模式下經過仔細修改。第 1 段的字體都是設置為宋體,包括其中的英文、小字及加粗的字。第 2 段除了最后一句外,其余的字體都設置為黑體,包括英文及小字;最后一句字體設置為微軟雅黑,是為了對比微軟雅黑和普通黑體的效果。第 3 段除了最后一句外,其余的字體都設置為 Serif,包括其中的中文;最后一句字體設置為 Times New Roman。第 4 段除了最后一句外,其余的是 Sans-Serif,最后一句是 Arial。第 5 段的字體都是設置為 Tahoma。最后的兩塊代碼,第 1 塊代碼的字體設置為 monospace,第 2 塊代碼的字體設置為 Courier New。為什么這樣設置,我后面會配合圖片逐一講解。下面,需要先了解字體的分類及其用途。

1、英文字體分為三類,分別是有襯線字體(serif)、無襯線字體(sans-serif)和等寬字體(monospace)。Serif 是有襯線字體,意思是在字的筆畫開始、結束的地方有額外的裝飾,而且筆畫的粗細會有所不同。Sans-serif 就沒有這些額外的裝飾,而且筆畫的粗細差不多。在傳統的正文印刷中,普遍認為襯線體能帶來更佳的可讀性(相比無襯線體),尤其是在大段落的文章中,襯線增加了閱讀時對字母的視覺參照。而無襯線體往往被用在標題、較短的文字段落或者一些通俗讀物中。相比嚴肅正經的襯線體,無襯線體給人一種休閑輕松的感覺。同時,由於無襯線字體筆畫比較飽滿,所以比較適合電腦屏幕顯示,在印刷和打印中,可以用無襯線字體做標題、加粗字體等表示強調。等寬字體就不用多說啦,主要用於終端字體或編程。

2、中文字體可以參照英文字體進行分類,由於中文都是等寬的,所以就只需要區分有襯線(serif)和無襯線(sans-serif)。中文的宋體、仿宋就相當於英文的 serif,所以用於傳統印刷和打印效果比較好。而中文的黑體、楷體、圓體等字體相當於英文的 sans-serif,用於電腦屏幕的顯示效果比較好,也可以用在印刷和打印中做標題和粗體字。

3、Serif 字體的經典代表有 Georgia 和 Times New Roman,sans-serif 字體的經典代表有 Arial 和Verdana,monospace 字體的經典代表有 Courier New 和 DejaVu Sans Mono。

電腦中的字體顯示技術

電腦中的字體既是一門藝術,也是一門技術。要將屏幕上的字體顯示得好看難度可不小。字體可以表示為點陣(bitmap),也可以表示為輪廓(outline)。點陣字體不能縮放,輪廓字體可以隨意縮放。

1、要獲得銳利清晰的效果,小字必須顯示為點陣(bitmap),大字可以顯示為輪廓;

2、顯示輪廓字體時,為了讓字體邊緣顯得比較光滑,需要對字體邊緣進行抗鋸齒(anti-alias);

3、為了獲得更好的效果,字體設計廠家在設計字體的時候,會對字體進行微調(hinting)。字體微調是一項耗時耗力的工作,所以就產生了自動微調技術(autohint);

4、為了讓字體在液晶顯示器上獲得更好的效果(主要也是為了字體邊緣光滑),產生了次像素平滑技術(subpixle),微軟的 ClearType 技術也屬於次像素平滑技術的一種。所謂次像素,是指每個像素中的單獨的 R、G、B 分量,所以次像素平滑用好了,字體邊緣看起來會更平滑,如果用不好,字體邊緣就會顯得花花綠綠。也正是因為 CRT 顯示器和液晶顯示器每個像素的組成方式不一樣,所以在 CRT 顯示器中不能開次像素平滑。

5、增加屏幕的 dpi,可以增加畫字的像素,從而獲得更平滑的顯示效果。比如在傳統的 96dpi 的電腦顯示器上,一個 9pt 的字符用 12 個像素繪制,一個 12pt 的字符用 16 個像素繪制,使用輪廓字體確實很難做到平滑。但是在目前的安卓手機、蘋果 iPad 等設備上,高分辨率的潤眼屏都在 300dpi 以上,畫一個 12pt 的字符可以用 50 多個像素,字體平滑自然不是問題,根本不需要使用點陣、微調、抗鋸齒、次像素等技術。我認為,隨着顯示器硬件技術的發展,以上技術都將成為浮雲。

以上圖片是字體測試段落在 Win7 系統中的顯示效果。除了標題和小字外,其它的字體都是 12pt。可以看到,12pt 的宋體字和 serif 的英文字體顯示為點陣,所以獲得了清晰銳利的效果。而黑體、微軟雅黑和 sans-serif 字體都沒有點陣,但是由於 sans-serif 本身筆畫飽滿,所以也獲得了不錯的顯示效果。據說微軟雅黑每個字造價 100 美元,專為 ClearType 技術而設計,但是從效果上看,並不比普通黑體強多少。

前面講過,serif 和 sans-serif 是字體的分類名,而不是具體的字體名。Times New Roman 是 Windows 下最經典的 serif 字體,但是從上圖可以看出它並不是 serif 字體的首選字體,設置為 serif 的字體和設置為 Times New Roman 的字體顯示不一樣,但是都是很漂亮的有襯線字體,serif 的中文選擇了一種和宋體不同的點陣字體。Arial 字體是最經典的無襯線字體,從圖中可以看出設置為 sans-serif 和設置為 Arial 的字體顯示效果相同。只是sans-serif 的中文被宋體的點陣代替了。Tahoma 字體的顯示效果和 sans-serif 只是寬度上略有不同,但是依然很飽滿。

使用 Ctrl+鼠標滑輪 可以縮放網頁。將網頁放大后顯示,可以查看輪廓字體的顯示效果,如下圖:

(注意:我文中的圖片都不是原始大小,可以通過 Ctrl+鼠標滑輪 放大后觀看,也可以在新窗口中打開圖片觀看。)

Linux 中的字體

下面,通過大量的圖片直觀地感受不同的字體以及不同的字體顯示技術會帶來什么樣的效果。

上圖是 CentOS 5 中的顯示效果,是不是覺得字體很虛?系統菜單中的字體倒是很銳利。其實在 Fedora 9 之前,Red Hat 系列的 Linux 發行版中文字體顯示都很模糊。也正是因為這個原因,我曾經有一段時間偏向於使用中科紅旗的 Linux。CentOS 中的字體顯示發虛的原因就是因為它的小字沒有使用點陣。

小字使用輪廓字體就會發虛,大字使用輪廓字體效果就要好得多。使用 Ctrl+鼠標滑輪 將網頁放大,可以看到大字顯示很清晰飽滿。如下圖:

CentOS 5 中的字體顯示還有一個奇怪的現象,那就是它認為 serif 的中文應該是楷體,而且它的 sans-serif 也顯示的是有襯線字體,很顯然這是不對的。而且由於歷史的原因,它沒有黑體。如下圖:

CentOS 系統中對中文的支持主要依賴於 2001 年文鼎向開源界貢獻的兩套字體:文鼎PL中楷和文鼎PL細上海宋,如下圖:

下面來看看 Ubuntu 中的顯示效果。從下圖中可以看到,Ubuntu 側重於 sans-serif 和黑體,除了明確指定serif 和 Times New Roman 的字體外,其余全部顯示為 sans-serif 和黑體。而且沒有點陣。這進一步印證了我前面說的黑體適合屏幕顯示、宋體適合打印和印刷。在系統中全部顯示黑體雖然不會丟失文字的信息,但是肯定會影響美觀。Ubuntu 沒有正確地為 monospace 選擇等寬字體,但是對 Courier New 倒是選擇了一個很漂亮的等寬字體進行替代。

使用 Ctrl+鼠標滾輪 將網頁放大,看到清晰飽滿的字體,如下圖:

對於界面字體,Windows 下有 Tahoma,Ubuntu 下也有專用的界面字體,該字體就叫 Ubuntu,是開源的。自 Ubuntu 14.04 開始,已經沒有采用文泉驛的黑體了,而是改用 Droid Sans Fallback,沒錯,就是 Google 花錢為 Android 系統設計的字體。反正該字體也沒點陣,我覺得顯示效果也就那樣。

下面再來看看 Fedora 20,該系統也是以黑體為主。從下面的圖片中可以看到,除了 Times New Roman,其它的字體顯示都是一個樣。

小字是點陣,放大后,顯示為黑體,如下圖:

查看 Fedora 20 系統,可以看到它還是安裝了 AR PL UMing,也就是宋體,但是它沒有使用,而且它沒有安裝楷體,雖然它的軟件源中有 cjkuni-ukai。它使用的黑體是文泉驛系列。

之前發表的幾篇隨筆都是在 Ubuntu 14.04 下完成的,這次我決定換到 Fedora 20 系統下。曬一下我的桌面,如下圖:

從 AR PL 這幾個字符可以看出,AR PL UMing 和文鼎貢獻的那兩套字體是一脈相承的。確實如此,只不過是經過合並、修改、增加了日語韓語及香港常用字型后,更名為 CJKUniFonts,據說含有點陣。從名字可以看出,有了這套字體,中日韓都可以搞定。CentOS 6 的主打字體就是它。如下圖,小字有點陣,清晰銳利:

放大后,顯示輪廓字體,不過好像缺了黑體,如下圖:

這套字體唯一的缺點就是它的標點符號,逗號和句號經常跑到一行的中間,而不是一行的底部。這都不是什么大事兒,其實,微軟雅黑的引號也不漂亮,不是嗎?

CentOS 6 中已經有了文泉驛,如下圖,之所以沒有顯示黑體不是因為沒有黑體,而是因為沒有正確配置:

通過上面一系列的截圖,可以看到各個操作系統都使用了哪些中文字體,也展現出了各個操作系統在字體配置方面的缺陷。從另一個方面,也反映出了挑選字體的趨勢。可以總結如下:

1、Linux 系統中的宋體最早只有文鼎貢獻的細上海宋,而且還沒有點陣。后來發展到 CJKUniFonts,宋體才有了點陣,它的字體名叫 AR PL UMing,在 Linux 系統上想要使用宋體,就全靠它了。但是 CJKUniFonts 的點陣似乎不太符合我們的習慣,好在文泉驛有非常漂亮的點陣字體,雖然只覆蓋了 9pt 到 12pt 的范圍。

2、Linux 系統中最開始黑體缺乏,現在大家都認識到了黑體在屏幕顯示中具有較好的效果,於是就黑體泛濫了。微軟花大價錢請人設計的微軟雅黑是黑體,開源字體文泉驛做的也是黑體,Google 花錢請人做的 Droid Sans Fallback 還是黑體。Ubuntu 用黑體,Fedora 也用黑體。可以說,文泉驛選擇黑體作為切入點真的是選對了,也確實是我們廣大 Linux 使用者的福音。

3、即使是最新的 Linux 發行版,如 Ubuntu 14 和 Fedora 20,其字體設置也不合理,對 serif、sans-serif、宋體、黑體的理解都不正確。所以,對於字體,我們還是得自己配置。

字體配置實戰

下面,將以 Fedora 20 為例,自己動手將它配置為正確的顯示效果。目前,在 Linux 系統上配置字體的工具是 Fontconfig。

為什么是 Fontconfig

感謝這個時代,曾經混亂不堪的字體配置方法終於被 Fontconfig 一統江湖。在 Linux 中,字體配置曾經各自為政、混亂不堪,XServer、Xft、GTK、GTK2、QT 等等各自采用不同的配置手段,字體引擎也有 Type1、FreeType等。目前,可以認為在 Linux 系統中只需要配置 FontConfig 即可。

XOrg 的官方網站上的文檔說明:XOrg 中有兩種字體系統,一種字體系統是 XServer 自帶的字體系統,另一種就是 Xft,而且 XOrg 官方建議所有的界面庫的開發者首選 Xft 字體系統;對於字體引擎,現在只剩下 FreeType 了,Type1 的功能已經合並到了 FreeType 中。FreeDesktop.org 的官方網站上有 Xft、Freetype 以及 Fontconfig 的文檔,雖然很簡略,但是也提到:Xft1.0 及以前的版本,需要通過 XftConfig 文件來配置字體,從Xft1.1 以后,都采用 Fontconfig 來配置字體;Fontconfig 的文檔也說它只負責字體的配置,不負責字體的顯示。

So,配置 Linux 中的字體,我們只用理會 Fontconfig,還有疑問嗎?

學習 Fontconfig

學習 Fontconfig 的最佳方式是閱讀 man fonts.conf 手冊頁,其次,就是閱讀 /etc/fonts/conf.d 目錄下的配置文件,從實例中學習。

Fontconfig 的功能就是幫助應用程序選擇字體並指導字體的顯示效果(只能說指導,因為具體的顯示由 Xft、Freetype 等說了算),用什么策略選擇字體及用什么選項顯示字體,通過配置文件來指定。Fontconfig 對配置文件進行兩遍掃描,第一遍對應用程序傳遞給 Fontconfig 的字體列表(稱為 pattern)進行操作,通過添加、刪除、替換pattern中的字體名,讓應用程序得到相應的字體;第二遍對已經選擇的字體進行操作,這時一般不改字體名了,而是對抗鋸齒(antialias)、微調(hinting)、自動微調(autohint)、微調級別(hintstyle)以及次像素平滑(rgba)等屬性進行控制。

Fontconfig 配置文件的語法,這個不用我在這里嘮叨,看 man fonts.conf 手冊頁即可,一點也不難,它的很多元素,如 match、target、test、edit、string、bool、double、const 等,本身就是自解釋的,看到這個單詞就知道它是什么意思。它的原則就是對每一個 <match...>...</match>,通過 <test...>...</test> 來選擇要編輯的元素,然后使用 <edit...>...</edit> 來對該元素進行編輯。

配置 Fedora 20

Fontconfig 首先讀取的配置文件是 /etc/fonts/fonts.conf,然后,根據 /etc/fonts/fonts.conf 里面的 <include>...</include> 信息來加載其它的配置文件。Fedora 20 默認是加載 /etc/fonts/conf.d 目錄下的所有文件。當然,/etc/fonts/conf.d 目錄下的文件太多了,引入了很多其實沒有必要的復雜性。對於我這種追求簡潔的人,我直接就把它改了,讓 /etc/fonts/conf.d 下的文件去見鬼,從我自己的主目錄的 fonts.conf.d 目錄下加載配置文件吧。如下圖,我注釋掉了第71行,增加了第72行:

下面正式開始寫配置文件。

第一步:將不標准的字體分類命名更改為標准的字體分類命名

英文的字體分類有 serif、sans-serif 和 monospace,中文的分類有“宋體”和“黑體”,但我們不能保證別人在請求字體的時候拼寫都是准確的,比如有可能拼寫成“sans serif”或“sans”、“mono”等,中文也可能寫成繁體“宋體”、“黑體”或者拼音“SongTi”、“HeiTi”等,為了后面配置文件的簡潔,這些不標准的分類名要先替換成標准的分類名。

英文的分類名的標准化 /etc/fonts/fonts.conf 這個主配置文件(就是我上面截圖的那個文件)已經做了,其完整代碼如下:

  1 <?xml version="1.0"?>
  2 <!DOCTYPE fontconfig SYSTEM "fonts.dtd">
  3 <!-- /etc/fonts/fonts.conf file to configure system font access -->
  4 <fontconfig>
  5 
  6 <!--
  7     DO NOT EDIT THIS FILE.
  8     IT WILL BE REPLACED WHEN FONTCONFIG IS UPDATED.
  9     LOCAL CHANGES BELONG IN 'local.conf'.
 10 
 11     The intent of this standard configuration file is to be adequate for
 12     most environments.  If you have a reasonably normal environment and
 13     have found problems with this configuration, they are probably
 14     things that others will also want fixed.  Please submit any
 15     problems to the fontconfig bugzilla system located at fontconfig.org
 16 
 17     Note that the normal 'make install' procedure for fontconfig is to
 18     replace any existing fonts.conf file with the new version.  Place
 19     any local customizations in local.conf which this file references.
 20 
 21     Keith Packard
 22 -->
 23 
 24 <!-- Font directory list -->
 25 
 26     <dir>/usr/share/fonts</dir>
 27     <dir>/usr/share/X11/fonts/Type1</dir> <dir>/usr/share/X11/fonts/TTF</dir> <dir>/usr/local/share/fonts</dir>
 28     <dir prefix="xdg">fonts</dir>
 29     <!-- the following element will be removed in the future -->
 30     <dir>~/.fonts</dir>
 31 
 32 <!--
 33   Accept deprecated 'mono' alias, replacing it with 'monospace'
 34 -->
 35     <match target="pattern">
 36         <test qual="any" name="family">
 37             <string>mono</string>
 38         </test>
 39         <edit name="family" mode="assign" binding="same">
 40             <string>monospace</string>
 41         </edit>
 42     </match>
 43 
 44 <!--
 45   Accept alternate 'sans serif' spelling, replacing it with 'sans-serif'
 46 -->
 47     <match target="pattern">
 48         <test qual="any" name="family">
 49             <string>sans serif</string>
 50         </test>
 51         <edit name="family" mode="assign" binding="same">
 52             <string>sans-serif</string>
 53         </edit>
 54     </match>
 55 
 56 <!--
 57   Accept deprecated 'sans' alias, replacing it with 'sans-serif'
 58 -->
 59     <match target="pattern">
 60         <test qual="any" name="family">
 61             <string>sans</string>
 62         </test>
 63         <edit name="family" mode="assign" binding="same">
 64             <string>sans-serif</string>
 65         </edit>
 66     </match>
 67 
 68 <!--
 69   Load local system customization file
 70 -->
 71 <!-- <include ignore_missing="yes">fonts.conf.d</incllude> -->
 72     <include ignore_missing="yes">~/fonts.conf.d</include>
 73 
 74 <!-- Font cache directory list -->
 75 
 76     <cachedir>/var/cache/fontconfig</cachedir>
 77     <cachedir prefix="xdg">fontconfig</cachedir>
 78     <!-- the following element will be removed in the future -->
 79     <cachedir>~/.fontconfig</cachedir>
 80 
 81     <config>
 82 <!--
 83   These are the default Unicode chars that are expected to be blank
 84   in fonts.  All other blank chars are assumed to be broken and
 85   won't appear in the resulting charsets
 86  -->
 87         <blank>
 88             <int>0x0020</int>    <!-- SPACE -->
 89             <int>0x00A0</int>    <!-- NO-BREAK SPACE -->
 90             <int>0x00AD</int>    <!-- SOFT HYPHEN -->
 91             <int>0x034F</int>    <!-- COMBINING GRAPHEME JOINER -->
 92             <int>0x0600</int>    <!-- ARABIC NUMBER SIGN -->
 93             <int>0x0601</int>    <!-- ARABIC SIGN SANAH -->
 94             <int>0x0602</int>    <!-- ARABIC FOOTNOTE MARKER -->
 95             <int>0x0603</int>    <!-- ARABIC SIGN SAFHA -->
 96             <int>0x06DD</int>    <!-- ARABIC END OF AYAH -->
 97             <int>0x070F</int>    <!-- SYRIAC ABBREVIATION MARK -->
 98             <int>0x115F</int>    <!-- HANGUL CHOSEONG FILLER -->
 99             <int>0x1160</int>    <!-- HANGUL JUNGSEONG FILLER -->
100             <int>0x1680</int>    <!-- OGHAM SPACE MARK -->
101             <int>0x17B4</int>    <!-- KHMER VOWEL INHERENT AQ -->
102             <int>0x17B5</int>    <!-- KHMER VOWEL INHERENT AA -->
103             <int>0x180E</int>    <!-- MONGOLIAN VOWEL SEPARATOR -->
104             <int>0x2000</int>    <!-- EN QUAD -->
105             <int>0x2001</int>    <!-- EM QUAD -->
106             <int>0x2002</int>    <!-- EN SPACE -->
107             <int>0x2003</int>    <!-- EM SPACE -->
108             <int>0x2004</int>    <!-- THREE-PER-EM SPACE -->
109             <int>0x2005</int>    <!-- FOUR-PER-EM SPACE -->
110             <int>0x2006</int>    <!-- SIX-PER-EM SPACE -->
111             <int>0x2007</int>    <!-- FIGURE SPACE -->
112             <int>0x2008</int>    <!-- PUNCTUATION SPACE -->
113             <int>0x2009</int>    <!-- THIN SPACE -->
114             <int>0x200A</int>    <!-- HAIR SPACE -->
115             <int>0x200B</int>    <!-- ZERO WIDTH SPACE -->
116             <int>0x200C</int>    <!-- ZERO WIDTH NON-JOINER -->
117             <int>0x200D</int>    <!-- ZERO WIDTH JOINER -->
118             <int>0x200E</int>    <!-- LEFT-TO-RIGHT MARK -->
119             <int>0x200F</int>    <!-- RIGHT-TO-LEFT MARK -->
120             <int>0x2028</int>    <!-- LINE SEPARATOR -->
121             <int>0x2029</int>    <!-- PARAGRAPH SEPARATOR -->
122             <int>0x202A</int>    <!-- LEFT-TO-RIGHT EMBEDDING -->
123             <int>0x202B</int>    <!-- RIGHT-TO-LEFT EMBEDDING -->
124             <int>0x202C</int>    <!-- POP DIRECTIONAL FORMATTING -->
125             <int>0x202D</int>    <!-- LEFT-TO-RIGHT OVERRIDE -->
126             <int>0x202E</int>    <!-- RIGHT-TO-LEFT OVERRIDE -->
127             <int>0x202F</int>    <!-- NARROW NO-BREAK SPACE -->
128             <int>0x205F</int>    <!-- MEDIUM MATHEMATICAL SPACE -->
129             <int>0x2060</int>    <!-- WORD JOINER -->
130             <int>0x2061</int>    <!-- FUNCTION APPLICATION -->
131             <int>0x2062</int>    <!-- INVISIBLE TIMES -->
132             <int>0x2063</int>    <!-- INVISIBLE SEPARATOR -->
133             <int>0x206A</int>    <!-- INHIBIT SYMMETRIC SWAPPING -->
134             <int>0x206B</int>    <!-- ACTIVATE SYMMETRIC SWAPPING -->
135             <int>0x206C</int>    <!-- INHIBIT ARABIC FORM SHAPING -->
136             <int>0x206D</int>    <!-- ACTIVATE ARABIC FORM SHAPING -->
137             <int>0x206E</int>    <!-- NATIONAL DIGIT SHAPES -->
138             <int>0x206F</int>    <!-- NOMINAL DIGIT SHAPES -->
139             <int>0x2800</int>    <!-- BRAILLE PATTERN BLANK -->
140             <int>0x3000</int>    <!-- IDEOGRAPHIC SPACE -->
141             <int>0x3164</int>    <!-- HANGUL FILLER -->
142             <int>0xFEFF</int>    <!-- ZERO WIDTH NO-BREAK SPACE -->
143             <int>0xFFA0</int>    <!-- HALFWIDTH HANGUL FILLER -->
144             <int>0xFFF9</int>    <!-- INTERLINEAR ANNOTATION ANCHOR -->
145             <int>0xFFFA</int>    <!-- INTERLINEAR ANNOTATION SEPARATOR -->
146             <int>0xFFFB</int>    <!-- INTERLINEAR ANNOTATION TERMINATOR -->
147         </blank>
148 <!--
149   Rescan configuration every 30 seconds when FcFontSetList is called
150  -->
151         <rescan>
152             <int>30</int>
153         </rescan>
154     </config>
155 
156 </fontconfig>
/etc/fonts/fonts.conf

中文的分類名標准化:

 1 <?xml version="1.0"?>
 2 <!DOCTYPE fontconfig SYSTEM "fonts.dtd">
 3 <fontconfig>
 4     <match target="pattern">
 5         <test qual="any" name="family">
 6             <string>宋體</string>
 7         </test>
 8         <edit name="family" mode="assign" binding="same">
 9             <string>宋體</string>
10         </edit>
11     </match>
12     <match target="pattern">
13         <test qual="any" name="family">
14             <string>SongTi</string>
15         </test>
16         <edit name="family" mode="assign" binding="same">
17             <string>宋體</string>
18         </edit>
19     </match>
20     <match target="pattern">
21         <test qual="any" name="family">
22             <string>黑體</string>
23         </test>
24         <edit name="family" mode="assign" binding="same">
25             <string>黑體</string>
26         </edit>
27     </match>
28     <match target="pattern">
29         <test qual="any" name="family">
30             <string>HeiTi</string>
31         </test>
32         <edit name="family" mode="assign" binding="same">
33             <string>黑體</string>
34         </edit>
35     </match>
36 </fontconfig>
~/fonts.conf.d/01-standardize-chinese-font-class.conf

第二步:對英文字體進行分類

請注意,我只對英文字體進行分類。對英文字體進行分類的目的是為了給相應的英文字體搭配正確的中文,比如字體為 Arial 的英文句子中,如果出現中文就應該用黑體,而字體為 Times New Roman 的英文句子中,如果出現中文當然應該用宋體。等寬的英文字體嘛,whatever,反正中文字都一樣寬,哪個順眼就用哪個吧。對於中文其實也可以分類,然后搭配不同的英文字體。但是我認為,中文的字體中一般都包含有英文字符,用原裝的即可,沒有必要替換。所以,不對中文進行分類。其代碼如下:

  1 <?xml version="1.0"?>
  2 <!DOCTYPE fontconfig SYSTEM "fonts.dtd">
  3 <fontconfig>
  4 <!--
  5   Serif faces
  6  -->
  7     <alias>
  8         <family>Bitstream Vera Serif</family>
  9         <accept><family>serif</family></accept>
 10     </alias>
 11     <alias>
 12         <family>DejaVu Serif</family>
 13         <accept><family>serif</family></accept>
 14     </alias>
 15     <alias>
 16         <family>Liberation Serif</family>
 17         <accept><family>serif</family></accept>
 18     </alias>
 19     <alias>
 20         <family>Times New Roman</family>
 21         <accept><family>serif</family></accept>
 22     </alias>
 23     <alias>
 24         <family>Times</family>
 25         <accept><family>serif</family></accept>
 26     </alias>
 27     <alias>
 28         <family>Nimbus Roman No9 L</family>
 29         <accept><family>serif</family></accept>
 30     </alias>
 31     <alias>
 32         <family>Luxi Serif</family>
 33         <accept><family>serif</family></accept>
 34     </alias>
 35     <alias>
 36         <family>Thorndale AMT</family>
 37         <accept><family>serif</family></accept>
 38     </alias>
 39     <alias>
 40         <family>Thorndale</family>
 41         <accept><family>serif</family></accept>
 42     </alias>
 43     <alias>
 44         <family>Georgia</family>
 45         <accept><family>serif</family></accept>
 46     </alias>
 47     <alias>
 48         <family>Garamond</family>
 49         <accept><family>serif</family></accept>
 50     </alias>
 51     <alias>
 52         <family>Palatino Linotype</family>
 53         <accept><family>serif</family></accept>
 54     </alias>
 55     <alias>
 56         <family>Trebuchet MS</family>
 57         <accept><family>serif</family></accept>
 58     </alias>
 59 <!--
 60   Sans-serif faces
 61  -->
 62     <alias>
 63         <family>Bitstream Vera Sans</family>
 64         <accept><family>sans-serif</family></accept>
 65     </alias>
 66     <alias>
 67         <family>DejaVu Sans</family>
 68         <accept><family>sans-serif</family></accept>
 69     </alias>
 70     <alias>
 71         <family>Liberation Sans</family>
 72         <accept><family>sans-serif</family></accept>
 73     </alias>
 74     <alias>
 75         <family>Arial</family>
 76         <accept><family>sans-serif</family></accept>
 77     </alias>
 78     <alias>
 79         <family>Helvetica</family>
 80         <accept><family>sans-serif</family></accept>
 81     </alias>
 82     <alias>
 83         <family>Verdana</family>
 84         <accept><family>sans-serif</family></accept>
 85     </alias>
 86     <alias>
 87         <family>Albany AMT</family>
 88         <accept><family>sans-serif</family></accept>
 89     </alias>
 90     <alias>
 91         <family>Albany</family>
 92         <accept><family>sans-serif</family></accept>
 93     </alias>
 94     <alias>
 95         <family>Nimbus Sans L</family>
 96         <accept><family>sans-serif</family></accept>
 97     </alias>
 98     <alias>
 99         <family>Luxi Sans</family>
100         <accept><family>sans-serif</family></accept>
101     </alias>
102     <alias>
103         <family>Tahoma</family>
104         <accept><family>sans-serif</family></accept>
105     </alias>
106 <!--
107   Monospace faces
108  -->
109      <alias>
110         <family>Bitstream Vera Sans Mono</family>
111         <accept><family>monospace</family></accept>
112     </alias>
113     <alias>
114         <family>DejaVu Sans Mono</family>
115         <accept><family>monospace</family></accept>
116     </alias>
117     <alias>
118         <family>Liberation Mono</family>
119         <accept><family>monospace</family></accept>
120     </alias>
121     <alias>
122         <family>Inconsolata</family>
123         <accept><family>monospace</family></accept>
124     </alias>
125     <alias>
126         <family>Courier New</family>
127         <accept><family>monospace</family></accept>
128     </alias>
129     <alias>
130         <family>Courier</family>
131         <accept><family>monospace</family></accept>
132     </alias>
133     <alias>
134         <family>Andale Mono</family>
135         <accept><family>monospace</family></accept>
136     </alias>
137     <alias>
138         <family>Luxi Mono</family>
139         <accept><family>monospace</family></accept>
140     </alias>
141     <alias>
142         <family>Cumberland AMT</family>
143         <accept><family>monospace</family></accept>
144     </alias>
145     <alias>
146         <family>Cumberland</family>
147         <accept><family>monospace</family></accept>
148     </alias>
149     <alias>
150         <family>Nimbus Mono L</family>
151         <accept><family>monospace</family></accept>
152     </alias>
153 <!--
154   Fantasy faces
155  -->
156      <alias>
157         <family>Impact</family>
158         <accept><family>fantasy</family></accept>
159     </alias>
160     <alias>
161         <family>Copperplate Gothic Std</family>
162         <accept><family>fantasy</family></accept>
163     </alias>
164     <alias>
165         <family>Cooper Std</family>
166         <accept><family>fantasy</family></accept>
167     </alias>
168     <alias>
169         <family>Bauhaus Std</family>
170         <accept><family>fantasy</family></accept>
171     </alias>
172 <!--
173   Cursive faces
174   -->
175     <alias>
176         <family>ITC Zapf Chancery Std</family>
177         <accept><family>cursive</family></accept>
178     </alias>
179     <alias>
180         <family>Zapfino</family>
181         <accept><family>cursive</family></accept>
182     </alias>
183     <alias>
184         <family>Comic Sans MS</family>
185         <accept><family>cursive</family></accept>
186     </alias>
187 
188 </fontconfig>
~/fonts.conf.d/02-classify-english-fonts.conf

第三步:所有不認識的英文字體都分類為 sans-serif

世界上字體那么多,不是每一個都想得到的啦。對於所有不認識的字體,都認為它是 sans-serif。其代碼如下:

 1 <?xml version="1.0"?>
 2 <!DOCTYPE fontconfig SYSTEM "fonts.dtd">
 3 <fontconfig>
 4 <!--
 5   If the font still has no generic name, add sans-serif
 6  -->
 7     <match target="pattern">
 8         <test qual="all" name="family" compare="not_eq">
 9             <string>sans-serif</string>
10         </test>
11         <test qual="all" name="family" compare="not_eq">
12             <string>serif</string>
13         </test>
14         <test qual="all" name="family" compare="not_eq">
15             <string>monospace</string>
16         </test>
17         <test qual="all" name="family" compare="not_eq">
18             <string>宋體</string>
19         </test><test qual="all" name="family" compare="not_eq">
20             <string>黑體</string>
21         </test>
22         <edit name="family" mode="append_last">
23             <string>sans-serif</string>
24         </edit>
25     </match>
26 </fontconfig>
~/fonts.conf.d/03-treat-unclassified-fonts-as-sansserif.conf

到這里,所有的分類工作完成。使用 fc-pattern 命令可以看到字體名被替換的過程。如下圖:

比如,當應用程序請求字體的 pattern 為“Time New Roman”時,pattern 被更改為“Times New Roman” “serif”;當應用程序請求字體的 pattern 為“微軟雅黑,不認識的字體”時,“sans-serif”被添加到了 pattern 的最后面。這也是字體分類的原理,就是將字體的類名添加到列表的后面。在 Fontconfig 的配置語法中,<alias> 是 <match> 的一種簡化寫法,如果需要測試和替換的只是字體名的話,使用 <alias> 就更簡單。如果使用 <alias>,則 <prefer> 表示添加到所選字體的前面,<accept> 表示添加到所選字體的后面,<default> 表示添加到字體列表的最后。在這里選擇用 <accept> 而沒有用 <default> 的原因是,如果用 <default>,每次都是把分類名添加到最后,遇到比較奇怪的pattern(比如上圖中的最后一個測試)就會造成混亂。

第四步:對每一個字體分類,指定自己喜歡的字體

對每一個分類都可以指定一個字體列表,排在越前面的優先級越高。在每一個分類的最后指定一個中文字體的分類,當句子中出現中文時,前面的英文字體中肯定找不到相應的字符啦,這時就會一個一個往字體列表的后面找,直到在最后的中文字體里找到。代碼如下:

 1 <?xml version="1.0"?>
 2 <!DOCTYPE fontconfig SYSTEM "fonts.dtd">
 3 <fontconfig>
 4     <alias binding="strong">
 5         <family>serif</family>
 6         <prefer>
 7             <family>Georgia</family>
 8             <family>Times New Roman</family>
 9             <family>Bitstream Vera Serif</family>
10             <family>DejaVu Serif</family>
11             <family>Thorndale AMT</family>
12             <family>Luxi Serif</family>
13             <family>Nimbus Roman No9 L</family>
14             <family>Times</family>
15             <family>宋體</family>
16         </prefer>
17     </alias>
18     <alias binding="strong">
19         <family>sans-serif</family>
20         <prefer>
21             <family>Arial</family>
22             <family>Verdana</family>
23             <family>Bitstream Vera Sans</family>
24             <family>DejaVu Sans</family>
25             <family>Albany AMT</family>
26             <family>Luxi Sans</family>
27             <family>Nimbus Sans L</family>
28             <family>Helvetica</family>
29             <family>Lucida Sans Unicode</family>
30             <family>BPG Glaho International</family> 
31             <family>Tahoma</family> 
32             <family>黑體</family>
33         </prefer>
34     </alias>
35     <alias binding="strong">
36         <family>monospace</family>
37         <prefer>
38             <family>DejaVu Sans Mono</family>
39             <family>Courier New</family>
40             <family>Bitstream Vera Sans Mono</family>
41             <family>Inconsolata</family>
42             <family>Andale Mono</family>
43             <family>Cumberland AMT</family>
44             <family>Luxi Mono</family>
45             <family>Nimbus Mono L</family>
46             <family>Courier</family>
47             <family>文泉驛等寬正黑</family>
48         </prefer>
49     </alias>
50     <alias binding="strong">
51         <family>宋體</family>
52         <prefer>
53             <family>AR PL UMing CN</family>
54             <family>AR PL UMing HK</family>
55             <family>AR PL UMing TW</family>
56             <family>AR PL UMing TW MBE</family>
57         </prefer>
58     </alias>
59     <alias binding="strong">
60         <family>黑體</family>
61         <prefer>
62             <family>文泉驛正黑</family>
63         </prefer>
64     </alias>
65 <!--
66   Fantasy faces
67  -->
68      <alias>
69         <family>fantasy</family>
70         <prefer>
71             <family>Impact</family>
72             <family>Copperplate Gothic Std</family>
73             <family>Cooper Std</family>
74             <family>Bauhaus Std</family>
75         </prefer>
76     </alias>
77 <!--
78   Cursive faces
79   -->
80     <alias>
81         <family>cursive</family>
82         <prefer>
83             <family>Comic Sans MS</family>
84             <family>ITC Zapf Chancery Std</family>
85             <family>Zapfino</family>
86         </prefer>
87     </alias>
88 
89 </fontconfig>
~/fonts.conf.d/04-prefer-fonts-for-each-class.conf

在這個配置中,依然使用 <alias>,通過把具體的字體名添加到類名的前面來填實字體分類。填實字體分類后,通過 fc-pattern 命令,可以測試 Fontconfig 如何選擇字體,如下圖:

到這一步,我的 Fedora 系統已經能夠正確選擇各種分類中的字體了。打開瀏覽器,用上一篇的開頭測試一下字體的顯示效果,如下圖:

放大后的效果:

從圖片中可以看出,經過前面的配置,瀏覽器已經可以正確區分宋體、黑體,可以區分 serif 和 sans-serif。對於等寬字體,也用上了漂亮的 DejaVu Sans Mono。而且宋體的小字還有點陣。看似比較完美了,但是依然有幾個小問題:

1、宋體的小字有點陣,但 AR PL UMing 自帶的點陣真心不好看;

2、黑體的小字沒有點陣,雖然黑體比較飽滿,沒有點陣也不會發虛,但是有點陣還是更好,而且應用程序菜單中的中文也從點陣變成了不是點陣;

3、宋體的加粗部分沒有正確顯示。

所以,還需要進一步的設置工作。

第五步:控制字體的顯示屬性

上一篇已經論述過,要讓字體顯示得好看也是一個技術活。所以對字體的顯示屬性要詳細控制啦。Gnome-tweak-tool 只能整體指定少量幾個屬性,如 hintstyle 和次像素平滑,很顯然是不夠用的。如下圖:

而且我的系統中用來畫字的 dpi 都不對,只有 75,如下圖(另一個測試字體配置的利器 fc-match 的運行效果):

這樣字體畫出來肯定偏小。事實上我的顯示器 dpi 比 96 都要高 20% 左右。所以得改。為了跟隨主流,還是改成 96dpi 好了。

我控制字體屬性的思路:

1、著名廠家設計的字體,開 hinting,開源的粗制濫造的字體就用 autohint 好了;目前系統中用的字體似乎名頭都很響,所以全局開 hinting,hintstyle 設為 hintslight。

2、英文字體全局開次像素平滑,全局開抗鋸齒,如果在使用過程中發現有哪個字體邊緣顯示為花花綠綠的話,就單獨關閉這個字體的次像素平滑。

3、小於 7.5 像素的字就關閉 hinting,這也是目前開源界的主流做法。

4、中文關閉次像素平滑,除非用的是微軟雅黑之類專為次像素平滑設計的字體;很顯然不在正版 Windows 中用微軟雅黑是違法的,所以中文關閉次像素平滑。

代碼如下:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE fontconfig SYSTEM "../fonts.dtd">
 3 <fontconfig>
 4   <match target="pattern">
 5     <edit name="dpi" mode="assign">
 6       <double>96</double>
 7     </edit>
 8   </match>
 9   <match target="font">
10     <edit name="hinting" mode="assign">
11       <bool>true</bool>
12     </edit>
13   </match>
14   <match target="font">
15     <edit name="autohint" mode="assign">
16       <bool>false</bool>
17     </edit>
18   </match>
19   <match target="font">
20     <edit name="hintstyle" mode="assign">
21       <const>hintslight</const>
22     </edit>
23   </match>
24   <match target="font">
25     <edit name="antialias" mode="assign">
26       <bool>true</bool>
27     </edit>
28   </match>
29   <match target="font">
30     <edit name="rgba" mode="assign">
31       <const>rgb</const>
32     </edit>
33   </match>
34   <match target="font">
35     <edit name="lcdfilter" mode="assign">
36       <const>lcdlight</const>
37     </edit>
38   </match>
39 
40   <match target="font">
41     <test compare="less" name="pixelsize">
42       <double>7.5</double>
43     </test>
44     <edit name="hinting">
45       <bool>false</bool>
46     </edit>
47   </match>
48   <match target="font">
49       <test name="family" compare="contains"> 
50       <string>AR PL UMing</string>
51     </test>
52     <edit name="rgba">
53       <const>none</const>
54     </edit>
55   </match>
56   <match target="font">
57     <test name="family" compare="contains">
58       <string>正黑</string>
59     </test>
60     <edit name="rgba">
61       <const>none</const>
62     </edit>
63   </match>
64 </fontconfig>
~/fonts.conf.d/05-dpi-and-hinting.conf

再來測試一下,如下圖:

第六步:為中文選擇點陣字體

上一篇中論述過,小字不用點陣,看起來會發虛。所以中文應該選擇點陣。文泉驛點陣正黑不錯,系統本身就有安裝。文泉驛點陣宋體需要另外安裝,如下圖:

代碼如下:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE fontconfig SYSTEM "../fonts.dtd">
 3 <fontconfig>
 4     <match target="pattern">
 5         <test name="family" compare="contains">
 6             <string>AR PL UMing</string>
 7         </test>
 8         <edit name="family" mode="prepend" binding="strong">
 9             <string>WenQuanYi Bitmap Song</string>
10         </edit>
11     </match>
12     <match target="pattern">
13         <test name="family">
14             <string>文泉驛正黑</string>
15         </test>
16         <edit name="family" mode="prepend" binding="strong">
17             <string>文泉驛點陣正黑</string>
18         </edit>
19     </match>
20     <match target="pattern">
21         <test name="family">
22             <string>文泉驛等寬正黑</string>
23         </test>
24         <edit name="family" mode="prepend">
25             <string>文泉驛點陣正黑</string>
26         </edit>
27     </match>
28   <match target="font">
29     <test name="family"> 
30       <string>文泉驛點陣正黑</string>
31     </test>
32     <test compare="less_eq" name="pixelsize">
33       <double>16</double>
34     </test>
35     <test compare="more_eq" name="pixelsize">
36       <double>12</double>
37     </test>
38     <edit name="antialias">
39         <bool>false</bool>
40     </edit>
41   </match>
42 </fontconfig>
~/fonts.conf.d/06-chinese-bitmap.conf

以上代碼通過將文泉驛點陣宋體添加到 AR PL UMing 的前面來實現替換掉 AR PL UMing 自己的點陣,通過將文泉驛點陣正黑添加到文泉驛正黑和文泉驛等寬正黑的前面來顯示點陣正黑。文泉驛的點陣只包含 12px 到 16px 的范圍,對該范圍大小的文泉驛正黑關閉抗鋸齒。把控制台字體調到 monospace-12,可以看到控制台中的中文使用點陣,如下圖:

寫到這里,我不得不提到另外一個問題,就是 <edit...binding="?">...</edit> 中 binding 究竟應該設置為什么的問題。binding 屬性有幾種選擇,分別是 binding="strong"、binding="weak" 和 binding="same"。如果該屬性設置不合理,則會出現這樣的問題:明明使用 fc-pattern 查看的時候是文泉驛點陣宋體排在 AR PL UMing 前面,是 DejaVu Sans Mono 排在文泉驛等寬正黑前面,但是使用 fc-match 匹配的時候,偏偏首選的是 AR PL UMing 和文泉驛等寬正黑。為什么會這樣呢?這是因為 Fontconfig 選擇字體的時候不僅僅只看字體名的排列順序,還要綜合考慮一種字體能覆蓋的字符集和字體大小范圍,所以,在前面的例子中,雖然文泉驛點陣宋體排在 AR PL UMing 前面,但是它覆蓋的字體大小范圍只有 12px 到 16px,DejaVu Sans Mono 雖然排在文泉驛等寬正黑前面,但是其覆蓋的字符集不包含中日韓文,所以 Fontconfig 就會首選排在后面的字體。為了解決這個問題,就必須把binding 屬性設置為 strong,這樣,不管什么情況都首選排在前面的字體,只有遇到該字體不能勝任的字符時才選擇后面的字體。在我的配置文件中,我都是一路 strong 到底。

第七步:對沒有包含斜體和粗體的字體自動合成斜體和粗體

代碼如下:

 1 <?xml version="1.0"?>
 2 <!DOCTYPE fontconfig SYSTEM "fonts.dtd">
 3 <fontconfig>
 4 <!-- 
 5  Artificial oblique for fonts without an italic or oblique version
 6  -->
 7  
 8     <match target="font">
 9         <!-- check to see if the font is roman -->
10         <test name="slant">
11             <const>roman</const>
12         </test>
13         <!-- check to see if the pattern requested non-roman -->
14         <test target="pattern" name="slant" compare="not_eq">
15             <const>roman</const>
16         </test>
17         <!-- multiply the matrix to slant the font -->
18         <edit name="matrix" mode="assign">
19             <times>
20                 <name>matrix</name>
21                 <matrix><double>1</double><double>0.2</double>
22                     <double>0</double><double>1</double>
23                 </matrix>
24             </times>
25         </edit>
26         <!-- pretend the font is oblique now -->
27         <edit name="slant" mode="assign">
28             <const>oblique</const>
29         </edit>
30         <!-- and disable embedded bitmaps for artificial oblique -->
31         <edit name="embeddedbitmap" mode="assign">
32             <bool>false</bool>
33         </edit>
34     </match>
35 
36 <!--
37  Synthetic emboldening for fonts that do not have bold face available
38  -->
39 
40     <match target="font">
41         <!-- check to see if the font is just regular -->
42         <test name="weight" compare="less_eq">
43             <const>medium</const>
44         </test>
45         <!-- check to see if the pattern requests bold -->
46         <test target="pattern" name="weight" compare="more">
47             <const>medium</const>
48         </test>
49         <!--
50           set the embolden flag
51           needed for applications using cairo, e.g. gucharmap, gedit, ...
52         -->
53         <edit name="embolden" mode="assign">
54             <bool>true</bool>
55         </edit>
56         <!--
57          set weight to bold
58          needed for applications using Xft directly, e.g. Firefox, ...
59         -->
60         <edit name="weight" mode="assign">
61             <const>bold</const>
62         </edit>
63     </match>
64 </fontconfig>
~/fonts.conf.d/07-synthetic.conf

從這段代碼可以看出,合成斜體的時候使用了矩陣乘法。另一個在 Fontconfig 配置文件中使用矩陣乘法的例子是 /etc/fonts/conf.d 中的第 1 個配置文件 10-scale-bitmap-fonts.conf,它使用矩陣乘法對點陣字體進行縮放,而且如果縮放因子在 0.8 到 1.2 之間則不縮放。閱讀系統的配置文件是一個學習的好方法,在我的系統中,該文件就僅供學習了,因為我不需要對點陣字體進行縮放。

最終效果如下圖:

放大后:

結果:小字時,宋體黑體都有點陣,大字時宋體黑體分別用不同的輪廓字體,能正確區分 serif 和 sans-serif,加粗的宋體、等寬字體也能正確顯示,應用程序菜單中的字體也恢復到了點陣。

總結

展示了 Fedora 20 配置字體的全過程。雖然沒有詳細講解 Fontconfig 的語法,但是通過代碼、截圖和 fc-pattern 以及 fc-match 命令對字體進行測試,讓 Fontconfig 的配置不言自明。當然,每個人對字體的感受是不一樣的,但是只要掌握了 Fontconfig 的配置方法,適當修改以迎合自己的需求,也是一件簡單的事情。也可以將Windows 中的字體借過來使用,微軟還是一個很靠譜的公司,它的那幾個經典的英文字體是開放的,前面有一個截圖中展示有 Fedora 的源中有 mscore-fonts 軟件包,直接安裝就可以。

 

(京山游俠於2014-06-20發布於博客園,轉載請注明出處。)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM