Ted's Blog

Happy coding

Gentoo Linux on T43 (7) 中文字体

Linux 下字体的配置可以很简单,也可以很复杂,这取决于个人需求的复杂程度,以及对相关知识的了解和技术掌控程度,其差别会导致悬殊的时间成本。在我本人开始这项工作之前,对相关内容了解很少,因此不得不花费时间来了解一些基础性内容。

在这个过程中,一本在线书籍Free/Open Source Software Localization 为我提供了有益的帮助,其整个第七章都是有关字体的内容,介绍了基本的字体概念字体的分类,以及Linux 如何处理字体 等。

对于中文字体的详细配置,参考了quanliking 的2 篇文章: Linux 字体微调 - windows 效果版Linux 字体微调- Vista 效果版 以及kemean 的字体配置local.conf详解[带Win效果和AA效果]

下面先描述一下字体的安装方法,然后给出我的字体配置,更多的内容可以参考以上的链接。

安装字体

Gentoo Linux有2种主要的字体系统并存:Core X11 font systemxft font system,分别有不同的安装方法。

Core X11 font system

对于Core X11,系统与应用程序的字体一般放在/usr/share/fonts 下面的子目录内,建议把用户自己安装的字体放在/usr/local/share/fonts 下的子目录,并且需要将这些路径加入到Xwindow的配置文件 /etc/X11/xorg.conf。举例:

将新的truetype 类型字体放在/usr/local/share/fonts/TTF 目录,然后执行以下命令(注意顺序):

# mkfontscale  /usr/local/share/fonts/TTF
# mkfontdir /usr/local/share/fonts/TTF

接着编辑/etc/X11/xorg.conf 来让使用Core X11 font system 的X 应用程序知道有新的字体可以利用,添加以下行到文件的Files 与Module Section(其实这个目录默认已经存在,无须添加)。

Section "Files"
    FontPath   "/usr/local/share/fonts/TTF"
    ...
EndSection

重启Xwindow 即可,新的字体将会被识别。 

xft font system

有些X 应用程序使用xft font system ,Gentoo Linux 默认设置了以下环境变量,使gtk+ 2.0 应用程序的字体使用xft,而不是Core X11 font system。

$ cat /etc/env.d/50gtk2
GDK_USE_XFT=1

xft font system 会自动搜索标准的字体路径并发现新字体,无须多余的步骤。如果希望新字体可以立即使用,那么执行命令fc-chache -fv 来即可刷新字体缓存。

对字体的配置可以存放在2个文件当中,其一是系统级别的/etc/fonts/local.conf (没有此文件可以自己建立),其二是用户Home目录下的.fonts.conf,仅影响当前用户。

字体配置

目前Linux 下的中文字体配置主要分为以下几种。

Windows 或Mac 效果 

使用Windows 平台的宋体(SimSun)、新宋体(NSimSun)与黑体(SimHei) ,或者最新vista 系统中的微软雅黑字体(Microsoft YaHei)。另外还有Mac 平台采用的华文黑体(STHeiti),其效果与SimHei 类似,但小字体的效果更出色。这几种字体包含的字符集非常齐全,覆盖了汉字简繁以及日韩字体,因此对繁体以及日韩字体显示效果要求不很高的用户,就没必要再去配置细明体(PMingLiU) 等其它字体。

使用这些字体的方法很简单,将其从Windows 目录复制到Linux 下简单配置即可,但严格来讲,这里面有版权问题,因此,在大多数Linux 发布之中,我们找不到以上字体。

使用免费的开源字体 

在这方面做得比较出色的是文泉驿 字体,目前通过网络协作的方式,已经开发出了点阵宋体、黑体以及等宽三大类字体,并不断升级改善中。

可以直接在Gentoo 中安装其中的点阵宋体和正黑字体:

# emerge -av  media-fonts/wqy-bitmapfont media-fonts/wqy-zenhei
配置文件 

为了对比,我尝试了以上的各种字体配置方案,经过调整后,在T43 高分屏1400x1050分辨率下,效果都不错,其差别仅在个人喜好罢了。因此,我将配置文件整理,如果你安装了以上几种字体,那么简单修改几行,重启Xwindow ,即可更换一种字体。

下面是我的.fonts.conf (整理自quanliking 与kemean 的文章),放在我的HOME 目录,会被/etc/fonts/fonts.conf 自动读取,其优先级低于/etc/fonts/local.conf

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<!-- ~/.font.conf file for user customizations -->
<fontconfig>
<!--
    Breaf:
    Search keyword "editable" for configuation.
    Section:
    1. Fonts family configuration

    2. Fonts substitution
    3. Global configuration
    4. English fonts configuration
    5. CJK fonts configuration
    Installed fonts list:
    STHeiti
    微软雅黑,Microsoft YaHei
    黑体,SimHei
    宋体-18030,SimSun-18030

    宋体,SimSun
    新宋体-18030,SimSun-18030,NSimSun-18030
    新宋体,NSimSun
    WenQuanYi Bitmap Song
    文泉驿正黑,文泉罅正黑,WenQuanYi Zen Hei
    Arial
    Arial Black
    Verdana
    Comic Sans MS

    Georgia
    Times New Roman
    Courier New
    Andale Mono
    Fixed
    Impact
    Trebuchet MS
    Webdings
-->

<!--
*******************************************************************************
    1. Fonts family configuration [Begin]
*******************************************************************************
-->
    <alias>
        <family>serif</family>
        <prefer>
            <!-- @@@ editable -->

            <family>SimSun</family>
        </prefer>
    </alias>
    <alias>
        <family>sans-serif</family>

        <prefer>
            <!-- @@@ editable -->
            <family>Microsoft YaHei</family>
        </prefer>
    </alias>

    <alias>
        <family>monospace</family>
        <prefer>
            <!-- @@@ editable -->
            <family>NSimSun</family>

        </prefer>
    </alias>
<!--
*******************************************************************************
    1. Fonts family configuration [End]
*******************************************************************************
-->
<!--
*******************************************************************************
    2. Fonts substitution [Begin]
*******************************************************************************
-->
<!--
    fonts alias substitution
-->

    <match target="pattern">
        <test name="family">
            <string>宋体</string>
        </test>
        <edit name="family" mode="assign">

            <string>SimSun</string>
        </edit>
    </match>
    <match target="pattern">
        <test name="family">

            <string>新宋体</string>
        </test>
        <edit name="family" mode="assign">
            <string>NSimSun</string>
        </edit>

    </match>
    <match target="pattern">
        <test name="family">
            <string>宋体-18030</string>
        </test>

        <edit name="family" mode="assign">
            <string>SimSun-18030</string>
        </edit>
    </match>
    <match target="pattern">

        <test name="family">
            <string>新宋体-18030</string>
        </test>
        <edit name="family" mode="assign">
            <string>NSimSun-18030</string>

        </edit>
    </match>
    <match target="pattern">
        <test name="family">
            <string>黑体</string>

        </test>
        <edit name="family" mode="assign">
            <string>SimHei</string>
        </edit>
    </match>

    <match target="pattern">
        <test name="family">
            <string>微软雅黑</string>
        </test>
        <edit name="family" mode="assign">

            <string>Microsoft YaHei</string>
        </edit>
    </match>
    <match target="pattern">
        <test name="family">

            <string>文泉驿正黑</string>
        </test>
        <edit name="family" mode="assign">
            <string>WenQuanYi Zen Hei</string>
        </edit>

    </match>
<!--
    not installed fonts substitution
-->
    <match target="pattern">
        <test name="family">
            <string>Times</string>

        </test>
        <edit name="family" mode="assign">
            <string>Times New Roman</string>
        </edit>
    </match>

    <match target="pattern">
        <test name="family">
            <string>Helvetica</string>
        </test>
        <edit name="family" mode="assign">

            <string>Verdana</string>
        </edit>
    </match>
    <match target="pattern">
        <test name="family">

            <string>Courier</string>
        </test>
        <edit name="family" mode="assign">
            <string>Courier New</string>
        </edit>

    </match>
    <match target="pattern" >
        <test name="family" >
            <string>PMingLiU</string>
            <string>MingLiU</string>

            <string>FangSong_GB2312</string>
            <string>KaiTi_GB2312</string>
            <string>AR PL KaitiM GB</string>
            <string>AR PL KaitiM Bit5</string>

            <string>AR PL SungtiL GB</string>
            <string>AR PL Mingti2L Bit5</string>
            <string>AR PL ShanHeiSun Uni</string>
            <string>AR PL ZenKai Uni</string>

            <string>Bitstream Vera Serif</string>
            <string>Bitstream Vera Sans</string>
            <string>Bitstream Vera Sans Mono</string>
            <string>DejaVu Sans</string>

            <string>DejaVu Sans Mono</string>
            <string>DejaVu Serif</string>
            <string>MS 明朝</string>
            <string>MS ゴシック</string>

            <string>Kochi Mincho</string>
            <string>Kochi Gothic</string>
            <string>Baekmuk Batang</string>
            <string>Baekmuk Dotum</string>

            <string>Baekmuk Gulim</string>
            <string>Baekmuk Headline</string>
        </test>
        <edit name="family" mode="assign" >
            <string>san-serif</string>

        </edit>
    </match>
<!--
    english portion substitution
-->
    <match target="pattern" >
        <test name="family" >
            <string>serif</string>

        </test>
        <edit name="family" mode="prepend" binding="strong" >
            <!-- @@@ editable -->
            <string>Georgia</string>
        </edit>

    </match>
    <match target="pattern" >
        <test name="family" >
            <string>sans-serif</string>
        </test>

        <edit name="family" mode="prepend" binding="strong" >
            <!-- @@@ editable -->
            <string>Verdana</string>
        </edit>
    </match>

    <match target="pattern" >
        <test name="family" >
            <string>monospace</string>
        </test>
        <edit name="family" mode="prepend" binding="strong" >

            <!-- @@@ editable -->
            <string>Courier New</string>
        </edit>
    </match>
<!--
*******************************************************************************
    2. Fonts substitution [End]
*******************************************************************************
-->

<!--
*******************************************************************************
    3. Global configuration [Begin]
*******************************************************************************
-->
<!--
    target dots per inch, change dpi to 96
-->
    <match target="pattern" >
        <edit name="dpi" mode="assign" >
            <double>96</double>

        </edit>
    </match>
<!--
    enable sub-pixel rendering.
    if you are using CRT, set rgb -> none
-->
    <match target="font">

        <edit name="rgba" mode="assign">
            <const>none</const>
        </edit>
    </match>
<!--
    default Fonts setting

    here autohint = ture / hinting = false is for free fonts in your system
    we will use autohint = false / hinting = true for MS core fonts
-->
    <match target="font" >
        <edit name="antialias" mode="assign" >
            <bool>true</bool>
        </edit>

        <edit name="autohint" mode="assign" >
            <bool>true</bool>
        </edit>
        <edit name="hinting" mode="assign" >
            <bool>false</bool>

        </edit>
        <edit name="hintstyle" mode="assign" >
            <const>hintfull</const>
        </edit>
    </match>

<!--
    font size settings:
    set the apposite font size,so it is easy to be read
-->
    <match target="pattern" >
        <test name="pixelsize" compare="more_eq" >
            <double>8</double>

        </test>
        <test name="pixelsize" compare="less_eq" >
            <double>12</double>
        </test>
        <edit name="pixelsize" mode="assign" >

            <double>12</double>
        </edit>
    </match>
<!--
    synthetic emboldening for fonts that do not have bold face available
-->
    <match target="font">

        <!-- check to see if the font is just regular -->
        <test name="weight" compare="less_eq">
            <int>100</int>
        </test>
        <!-- check to see if the pattern requests bold -->

        <test target="pattern" name="weight" compare="more_eq">
            <int>180</int>
        </test>
        <!-- set the embolden flag -->
        <edit name="embolden" mode="assign">

            <bool>true</bool>
        </edit>
    </match>
<!--
*******************************************************************************
    3. Global configuration [End]
*******************************************************************************
-->
<!--
*******************************************************************************
    4. English fonts configuration [Begin]
*******************************************************************************
-->

<!--
    default : smoothed and hinted
-->
    <match target="font" >
        <test name="foundry" qual="any" >
            <string>monotype</string>
            <string>microsoft</string>

        </test>
        <edit name="antialias" mode="assign" >
            <bool>true</bool>
        </edit>
        <edit name="autohint" mode="assign" >

            <bool>false</bool>
        </edit>
        <edit name="hinting" mode="assign" >
            <bool>true</bool>
        </edit>

        <edit name="hintstyle" mode="assign" >
            <const>hintfull</const>
        </edit>
    </match>
<!--
    for point size less equal than 6 : only smoothed
-->

    <match target="font" >
        <test name="foundry" qual="any" >
            <string>monotype</string>
            <string>microsoft</string>
        </test>

        <test name="size" compare="less_eq" >
            <double>6</double>
        </test>
        <edit name="antialias" mode="assign" >
            <bool>true</bool>

        </edit>
        <edit name="autohint" mode="assign" >
            <bool>false</bool>
        </edit>
        <edit name="hinting" mode="assign" >

            <bool>false</bool>
        </edit>
    </match>
<!--
    Arial Regular
-->
    <match target="font" >

        <test name="family" >
            <string>Arial</string>
        </test>
        <test name="weight" compare="eq">
            <const>regular</const>

        </test>
        <test name="slant" compare="eq" >
            <const>roman</const>
        </test>
        <test name="size" compare="more_eq" >

            <double>7</double>
        </test>
        <test name="size" compare="less_eq" >
            <double>13</double>
        </test>

        <edit name="antialias" mode="assign" >
            <bool>false</bool>
        </edit>
        <edit name="autohint" mode="assign" >
            <bool>false</bool>

        </edit>
        <edit name="hinting" mode="assign" >
            <bool>true</bool>
        </edit>
        <edit name="hintstyle" mode="assign" >

            <const>hintfull</const>
        </edit>
    </match>
<!--
    Times New Roman Bold Italic
-->
    <match target="font" >

        <test name="family" >
            <string>Times New Roman</string>
        </test>
        <test name="weight" compare="eq">
            <const>bold</const>

        </test>
        <test name="slant" compare="eq" >
            <const>italic</const>
        </test>
        <test name="size" compare="more_eq" >

            <double>7</double>
        </test>
        <test name="size" compare="less_eq" >
            <double>13</double>
        </test>

        <edit name="antialias" mode="assign" >
            <bool>false</bool>
        </edit>
        <edit name="autohint" mode="assign" >
            <bool>false</bool>

        </edit>
        <edit name="hinting" mode="assign" >
            <bool>true</bool>
        </edit>
        <edit name="hintstyle" mode="assign" >

            <const>hintfull</const>
        </edit>
    </match>
<!--
    Courier New:
    both enable autohint and hinting looks very well.
-->

   <match target="font" >
      <test name="family" >
         <string>Courier New</string>
      </test>
      <edit name="antialias" mode="assign" >

         <bool>true</bool>
      </edit>
      <edit name="autohint" mode="assign" >
         <bool>true</bool>
      </edit>

      <edit name="hinting" mode="assign" >
         <bool>true</bool>
      </edit>
      <edit name="hintstyle" mode="assign" >
         <const>hintfull</const>

      </edit>
   </match>
<!--
    Courier New font size
-->
   <match target="font" >
      <test name="family" >
         <string>Courier New</string>

      </test>
      <test name="pixelsize" compare="less_eq" >
         <double>14.7</double>
      </test>
      <edit name="pixelsize" mode="assign" >

         <double>14.7</double>
      </edit>
   </match>
<!--
*******************************************************************************
    4. English fonts configuration [End]
*******************************************************************************
-->
<!--
*******************************************************************************
    5. CJK fonts configuration [Begin]
*******************************************************************************
-->

<!--
    the dual-width Asian fonts (spacing=dual) are not rendered correctly,
    apparently FreeType forces all widths to match. Trying to disable the
    width forcing code by setting globaladvance=false alone doesnot  help.
    as a brute force workaround, also set spacing=proportional, i.e. handle
    them as proportional fonts:
-->
    <match target="font" >

        <test target="pattern" name="lang" compare="contains" >
            <string>zh</string>
            <string>ja</string>
            <string>ko</string>

        </test>
        <test name="spacing" compare="eq">
            <const>dual</const>
        </test>
        <edit name="spacing" mode="assign" >

            <const>proportional</const>
        </edit>
        <edit name="globaladvance" mode="assign" >
            <bool>false</bool>
        </edit>

    </match>
<!--
    adjusting
-->
    <match target="font" >
        <test qual="any" name="family" compare="eq" >
            <!-- installed fonts -->
            <!--

            <string>STHeiti</string>
            -->
            <string>Microsoft YaHei</string>
            <string>SimHei</string>

            <string>SimSun</string>
            <string>NSimSun</string>
            <string>SimSun-18030</string>
            <string>NSimSun-18030</string>

            <string>WenQuanYi Bitmap Song</string>
            <string>WenQuanYi Zen Hei</string>
        </test>
        <edit name="rgba" mode="assign">
            <const>none</const>

        </edit>
        <edit name="antialias" mode="assign" >
            <bool>true</bool>
        </edit>
        <edit name="autohint" mode="assign" >

            <bool>false</bool>
        </edit>
        <edit name="hinting" mode="assign" >
            <bool>true</bool>
        </edit>

        <edit name="hintstyle" mode="assign" >
            <const>hintfull</const>
        </edit>
        <edit name="embeddedbitmap" mode="assign" >
            <bool>true</bool>

        </edit>
    </match>
<!--
    enable embedded bitmap fonts
    non-bitmap:
       STHeiti: sthei.ttf 13563000 bytes
       Microsoft YaHei: msyh.ttf 15043584 bytes
       SimHei: simhei.ttf 10044356 bytes

    with bitmap:
       SimSun/NSimSun: simsun.ttf 10500792 bytes
       SimSun-18030/NSimSun-18030: simsun-18030.ttf 12642204
       WenQuanYi Zen Hei: wqy-zenhei.ttf 12844372 bytes
    checked by Linux tool: fontforge
-->
    <match target="font" >
        <test qual="any" name="family" compare="eq" >

            <string>SimSun</string>
            <string>NSimSun</string>
            <string>SimSun-18030</string>
            <string>NSimSun-18030</string>

        </test>
        <test name="pixelsize" compare="eq" >
            <double>12</double>
            <double>13</double>
            <double>14</double>

            <double>15</double>
            <double>16</double>
            <double>18</double>
        </test>

        <edit name="antialias" mode="assign" >
            <bool>false</bool>
        </edit>
    </match>
    <match target="font" >

        <test qual="any" name="family" compare="eq" >
            <string>WenQuanYi Bitmap Song</string>
        </test>
        <test name="pixelsize" compare="more_eq" >
            <double>9</double>

        </test>
        <test name="pixelsize" compare="less_eq" >
            <double>12</double>
        </test>
        <edit name="antialias" mode="assign" >

            <bool>false</bool>
        </edit>
    </match>
    <match target="font" >
        <test qual="any" name="family" compare="eq" >

            <string>WenQuanYi Zen Hei</string>
        </test>
        <test name="pixelsize" compare="eq" >
            <double>12</double>
            <double>13</double>

            <double>15</double>
            <double>16</double>
        </test>
        <edit name="antialias" mode="assign" >
            <bool>false</bool>

        </edit>
    </match>
<!--
*******************************************************************************
    5. CJK fonts configuration [End]
*******************************************************************************
-->
</fontconfig>

上面的字体配置使用3种虚拟字体:

  • 衬线字体:Serif
  • 非衬线字体:Sans-serif/Sans serif/Sans
  • 等宽字体:Monospace/Mono

虚拟字体已经被定义在/etc/fonts/conf.d/ 下面的配置文件中,并拥有了一个字体列表,以上字体配置中的字体会被加在顶部,具有更高的优先级。并且,/etc/fonts/fonts.conf 中也为虚拟字体添加了可能采用的别名,比如mono。有关衬线字体与非衬线字体,请参看:细说字体 Sans Serif 与 Serif

在上面,我定义了:对于衬线字体,中文使用宋体,英文使用Georgia;非衬线的字体,中文使用微软雅黑,英文使用Verdana;等宽字体,中文使用新宋体,英文使用Courier New,共6种字体。其中,除了中文字体需要自己额外安装以外,其它英文字体默认已经存在于/usr/share/fonts/corefonts 目录,它们属于media-fonts/corefonts ,如果你找不到这些字体,可以emerge 这个包。

如果想换不同的口味,只需要把上述6处字体名称替换为系统中已经安装的字体即可,为了方便配置,我在每一处增加了<!-- @@@ editable --> 这样的注释。

另外,有人觉得/etc/fonts/conf.d 下面的配置文件没什么用处,还可能干扰自己的配置,可以删除了事。我仔细看过,不提倡删除,如果删除的话,以下2个文件一定要保留,否则fontconfig 就不会读取~/.fonts.conf 与/etc/fonts/local.conf ,它们是这2个配置文件的装载入口。

  • 50-user.conf
  • 51-local.conf

下面是雅黑的效果截图:

screenshot-msyh.jpg

字体有关的命令 

下面介绍几个字体有关的命令,在配置过程中可能会用来进行配置的确认、除错等。

fc-list

列出系统中所有可用的字体名称(包含中英文别名),以及支持的style。

命令后面可加字体名称,但必须是全称,不支持通配符,否则无法匹配。如果是中文字体,要求环境为UTF-8,否则匹配不成功,输出也是乱码。字体名称如果包含空格,使用引号引起。

虚拟字体不会被列出。

fc-match  

列出字体文件名称、英文名称,不支持中文字体名匹配。同样不支持通配符,但支持虚拟字体,可以列出虚拟字体中优先级最高的字体。可以使用-v 参数输出字体详细信息。 

对于配置文件中进行过字体替换的字体,fc-match 会输出替换后的字体名称

$ fc-match courier
cour.ttf: "Courier New" "Normal"
fc-cat

从cache 文件中读取字体信息,很少用到。

以上三个命令来自media-libs/fontconfig,属于xft 的命令。

xlsfonts

xlsfonts 也用于列出字体,但格式不同,此外,它也可以列出一些未被xft 系统识别并cache 的字体。同时这个命令也支持通配符。

$ xlsfonts -fn "*sim*"
-misc-simhei-medium-r-normal--0-0-0-0-p-0-iso10646-1
-misc-simsun 18030-medium-r-normal--0-0-0-0-m-0-iso10646-1
-misc-simsun 18030-medium-r-normal--0-0-0-0-m-0-iso8859-1
-misc-simsun 18030-medium-r-normal--0-0-0-0-m-0-koi8-r
-misc-simsun-medium-r-normal--0-0-0-0-p-0-iso10646-1
-misc-simsun-medium-r-normal--0-0-0-0-p-0-iso8859-1
-misc-simsun-medium-r-normal--0-0-0-0-p-0-koi8-r

如果系统中找不到这个命令,需要emerge x11-apps/xlsfonts

fontforge

这是一个GUI 程序,可用于编辑字体文件,同时也可以获得大量的字体信息,比如一个TrueType 字体是否内嵌了点阵字体,size是多少。对于MS的宋体,fontforge 只能识别出部分size 的点阵字体:12、14、16,13、15、18 则识别不出来,开时我认为是字体文件的版本问题,后来看了quanliking 的回帖才知道是fontforge 的问题。

如果系统中找不到这个命令,需要emerge  media-gfx/fontforge

Tips

如果字体没有变化,仅仅修改了字体配置文件,如果使用fc-match 这样的命令,不需要重启Xwindow。对于其它应用程序,比如gedit,仅仅重新运行这个程序即可应用新的配置,但有些应用程序则需要重启动Xwindow 才可以应用新的配置,比如gnome-terminal 。了解这些可以在测试字体配置的时候节省一些时间。

下载

  • fontconfig 配置文件:.fonts.conf(如果直接使用这个文件,请重命名为 .fonts.conf,下载的文件名中没有点)
  • 因为版权问题,不提供一些字体的下载,在Windows 系统以及本文链接的文章中可以找到。

延展阅读

(未完)