X Window下的字体缩放和TTF的应用(转)
字体属于最直观的东西,直接影响最终的显示和打印结果。在图形界面和所见既所得的要求下,如何发挥X Window在字体方面的能力,是大家十分关心的问题。现在XFree86 4.0已经出来,在TTF方面的扩展已经尘埃落定,所以有了本文。
X Window在字体方面的能力十分强大。X Window的结构很清晰,统一使用X逻辑字体描述XLFD(X Logical Font Description)描述各式各样的字体。每增加一种字体,只是增加一个模块,XLFD并没有多大变化。这样保证了兼容性,避免系统出现大的动荡。但 负作用也是有的,随着功能的增加,我们会发现耗内存越来越多,速度自然也越来越慢了:-)
X Window使用X字体服务器XFS处理字体。XFree86附带有一个网络字体服务器xfs,还有每一个X Server都是XFS。就性能而言,自然是内部的XFS快很多。目前XFree86 4.0支持bdf/pcf,Type1,TrueTypeFont等几种字体格式。
其中bdf/pcf是最基本的格式,TTF可以完美实现无级缩放。
X 逻辑字体描述(X Logical Font Description)的简单说明:
// font fields
// -fndry-fmly-wght-slant-sWdth-adstyl-pxlsz-ptSz-resx-resy-spc-avg Wdth-rgstry-encdng
// fndry -> foundy
// fmly -> family, font style
// wght -> weight
// slant
// sWdth -> ? width
// adstyl -> addtion style
// pxlsz -> pixel size
// ptSz -> point size
// resx -> resolution x
// resy -> resolution y
// spc -> space
// avgWdth -> average width
// rgstry -> register
// encdng -> encoding
example:
-cclib-song-medium-r-normal-jiantizi-16-160-75-75-c-160-gb2312.1980-0
其中:
cclib : 制造商
song : 字体族, 宋体
medium: 线权重(中等), 还有bold(粗体)选项
r : 倾斜, r(Roman), i(Italic), o(Oblique)
normal: 字符集宽度, 此外还有 condensed, narrow, double
jiantizi: 附加说明(简体字)
16: 以像素衡量的宽度.
160: 点数*10
75(1): 水平分辨率(dpi)
75(2): 垂直分辨率(dpi)
c: 间距, (?), m: fixed width, p: variable width
160: 平均宽度(10*pixels)
gb2312.1980: 注册字符集,标准名
0: 第0套,基本集
字体描述文件
在字体同一目录下,有两个文件指导X window如何安装使用字体:
fonts.dir/fonts.alias。虽然fonts.dir可由实用程序mkfontdir生成,但生成的文件中字体的次序不一定合适,所以有时需要人工调整。
fonts.dir 格式:
第一行:字体文件的数目
后面:字体文件 X 逻辑字体描述(字体真名)
......
fonts.dir example:
2
ccs16.pcf.gz -cclib-song-medium-r-normal-jiantizi-16-160-75-75-c-160-gb2312.1980-0
ccs24.pcf.gz -cclib-song-medium-r-normal-jiantizi-24-240-75-75-c-240-gb2312.1980-0
fonts.alias 格式:
字体别名 X 逻辑字体描述(字体真名)
......
fonts.alias example:
ccs16 -cclib-song-medium-r-normal-jiantizi-16-160-75-75-c-160-gb2312.1980-0
ccs24 -cclib-song-medium-r-normal-jiantizi-24-240-75-75-c-240-gb2312.1980-0
这样在使用过程中,程序既可以使用字体真名,也可以使用字体别名装载X字体。
X字体的使用
应用程序调用XLoad(Query)Font函数装载字体。X window会尽量解释和装载字体,其中包括参数里使用"*","?"通配符,还有缩放字体。其中X 逻辑字体描述字段对字体缩放有直接影响的是pixel size/point size, average width字段。其中pixel size的优先级大于point size。也就是,如果传给XLoadFont的字体不存在,X window会根据现有的一个名字匹配,大小(pixel size/point size, average width)不同的字体,在内存里生成一个新字体。
因为X window下的中文字体很少,一般只提供16和24点阵两种大小。所以字体缩放机制就显得很重要。这种机制的好处是只须提供少量的字体,就可以应付大多 数情况。缺点也是有的,就是生成字体的速度很慢,延迟是以秒记的。如果是GB2312字体还好,不到7000个字。而Unicode或GBK字体,汉字就 有20902多个,一个个进行缩放,延迟可想而知。但要注意的是,X window只是在装载生成字体时有延迟,字体生成后,XDraw*函数显示速度并没有延迟。
下面举例说明。如果有字体:
ccs16.pcf.gz -cclib-song-medium-r-normal-jiantizi-16-160-75-75-c-160-gb2312.1980-0
想用字体:
"-*-song-medium-r-normal-jiantizi-12-120-75-75-c-100-gb2312.1980-0"
程序里只须直接调用即可:
......
char *font_name = "-*-song-medium-r-normal-jiantizi-12-120-75-75-c-100-gb2312.1980-0";
XFontStruct *zh_font;
......
zh_font = XLoadFont(display, font_name);
if (zh_font == NULL) {
printf("not find this font: %s\n", font_name);
exit(1);
}
......
这里要讨论字体缩放机制,是为了解决X外挂式中文平台的字符串定位问题。如果光标要定在两个字符之间,就要知道这点的位置。X应用程序一般是调用函数 XTextWidth(16),XTextExtents(16),XQueryTextExtents(16)以确定字符串的宽度。所以X外挂式中文平 台要截取这些函数以便对中英文混排的字符串进行准确定位。但有些程序为了速度,是调用XGetFontProperty函数或直接在 XFontStruct结构里取得单个字符的宽度,乘上字符个数得到字符串的宽度。如果ASCII字体有标准高宽比,也是没有问题。所谓标准高宽比就是 ASCII字体的宽:高为1/2,相应的中文字体就是1:1。如果不是这样,光标定位就有问题。再有就是字符高度,一般是中文字体略高于ASCII字体就 美观了。但具体数值要控制好,否则太矮不好看,太高又会被削去头部。所以字间距和行间距目前是很烦恼的问题。解决的方法可能有一些:
1,截获更多的函数,或修改ASCII字体的高度和宽度。这要求对X window有很深的了解。这也是一个吃力不讨好的方案,因为总有疏漏,X window的函数也会发展和变化,那么就会有遗憾。cleex for Linux 1.0在速度和定位上较好地解决了这个问题,可能是使用了这个方案。
2,使用字体缩放机制,使汉字大小和ASCII字体相匹配。这个方案的问题是装载字体的速度和耗费的资源。我实验了这个方案,使用NetScape浏览网 页,发现很多时间花在了装载字体上。而且,如何管理这些字体也是一个问题。使用TTF字体可能可以完美地解决这个问题。我使用TLC4.0的 ZhWinPro2.0,发现以前定位不准的软件都没有问题了。看来使用TTF字体是今后的方向。应该看到,一个好的XFS,就算不支持TTF,也可以实 现字体的无级缩放。只是bdf/pcf这类字体格式存储的字形信息少,在显示效果上就不及TTF完美,但装载速度感觉就比TTF快。并且在14点阵以 下,TTF的效果倒反不及bdf/pcf。因此今后bdf/pcf主要使用在小点阵低速的环境中,而TTF将用在强调细节和美观的环境里,如字处理。事实 上,X11R6以后的XLFD的功能十分强大,增加矩阵型XLFD和增强别名机制。只需通过XLFD的变换,就可以实现字体的缩放,倾斜,镜像,斜写和环 写的功能,如同MS WORD里的艺术字那样的效果。因为英文水平不高,不敢乱说,有兴趣的可以查看
http://www.winehq.com/x11r6_fonts_94.pdf或者XFree86源代码的随机文档。
TTF以曲线描述字体,可以在各种大小的环境下还原字形。在FreeType的随机文档里有一些这方面的介绍。可以说,XFree86有了TTF,就有了 在所见既所得方面和MS WINDOWS较量的实力。目前XFree86使用的TTF驱动模块是FreeType,这是底层的TTF解释模块,用来把TTF的字形描述转换为可用的 光栅字形。FreeType目前稳定的版本是1.3.1。因为在一些算法上和大公司有专利纠纷,他们决定FreeType依然是freedom。于是放弃 成熟的1.x版,加速开发更好的2.x。这官司让人关注,而FreeType的做法也让人敬佩。有了驱动模块,要想在XFree86下显示这些字,还需要 高一层的X字体服务器(XFS)。目前在XFree86下TTF的XFS有X-TT和xfsft两个,都是使用FreeType作为底层,在实现上个有特 色。XFree86 4.0目前接纳了这两个软件,同时也接纳了这两个软件对fonts.dir文件格式的扩展。
X-TT是日本人的作品。可能同样是要使用汉字,X-TT显示的汉字感觉上要比xfsft的要美观些。X-TT还有一个特色就是把XFree86的字体处 理模块分离出来,做成一个动态链接库libfont.so。但是不知什么原因,XFree86 4.0没有接受这个方案,继续使用静态链接库font.a。
X-TT目前可以通过XLFD的变换把ISO10646编码的TTF转化为GB2312,BIG5,JIS,KSC等编码标准的字体。但是X-TT软件本 身没有提供GBK编码的支持。国内两个提供使用TTF字体的Linux厂商(TurboLinux和红旗Linux)都选用X-TT作为XFS,同时提供 了GBK的支持。例如RF1.1把所有的转换表,包括GBK的,都做成动态链接库形式的convert modules,放在/usr/X11R6/lib/modules/codeconv下。如果这两个厂商的方案能进入X-TT的原始发行版中,进而进入 XFree86今后的发行版中,将是中国Linux界的一件大事。xfsft有一个特点就是比较小巧,功能不多,够用就行。XFree86 4.0缺省就是使用xfsft模块。xfsft在变换TTF的编码时,使用的是外部的转换表。这也是我从3.3.3.1到现在的4.0一直使用xfsft 的原因。xfsft本身也只提供了GB2312和BIG5的转换表,没有提供GBK的支持。但我从Unicode的网站下载了 GBK->Unicode的转换表,简单修改配置文件,就可以使用GBK编码标准的字体了。
前面所说的显示字形美观问题,一个是指个人的感觉,另一个是指在小点阵下中文TTF的显示问题。所谓小点阵字体,是指14点阵以下的字体。目前不论是X- TT还是xfsft,在这种情况下,都不及同样大小的pcf字体美观(我对比使用的是cleex的12和14点阵字体,还有RF1.1提供的一个12点阵 的GB2312编码的点阵字体)。这是中文TTF的问题。观察我们的汉字笔画,点、横、竖、撇、捺、折、钩,从头到尾粗细都是变化的。在小点阵的情况 下,TTF既想表达这些变化,又要丢失一些细节,就会造成中文字横不平,竖不直,都有些打折,同时点和钩常常丢失,因此显示出来的中文字怎么看都不顺眼。 反观英文字母,基本上是粗细相等的线条,上面对比用的小点阵中文pcf字体,笔画基本上也是一条棍子捅到底。其实,在这种情况下,我们要求的不是细节,而 是中文字横平竖直的基本要求,所以TTF的曲线描述这时倒反成了累赘。为解决这个问题,现在的中文TTF都会内嵌小点阵字体。因为没有看过 FreeType,X-TT和xfsft的源代码,不能确定它们的实际效果。但目前MS WINDOWS95/98中文版在显示小点阵中文字体方面比X-TT和xfsft的要好。当然,这也是一个感觉。
ISO10646的TTF通过XLFD变换而变化为其它编码标准的字体,可以算是Unicode在XFree86中的一个应用。通过这个功 能,XFree86只需一套ISO10646编码标准的TTF,就可以同时提供中文,日文,韩文的显示。关键就在于那些转换表的应用。原理很简 单,XLFD最后两个域是注册名和编码号,XFS在处理XLFD时,识别这两个区域,通过配置文件和转换表,就可以提供其它编码标准的字体。
因为在XFree86 3.x下配置TTF的XFS有点麻烦,而且XFree86 3.x很快就成为历史,所以下面主要讨论在XFree86 4.0下如何配置xfsft以支持GBK。如果要使用X-TT,可以安装TLC4.X或RF1.1,不过两者都不好移植到其它Linux套件中。还有一个 是北京腾图出的Manderake Linux 7.0也是使用X-TT。
取来ISO10646的TTF,放在一个目录中:
#ls /usr/X11R6/lib/X11/fonts/FreeType -l
-rw-r--r-- 1 root root 2496 May 3 10:04 encodings.dir
-rw-r--r-- 1 root root 689 May 3 10:10 fonts.alias
-rw-r--r-- 1 root root 1968 May 3 08:50 fonts.dir
-rw-r--r-- 1 root root 1968 May 3 10:04 fonts.scale
-rw-r--r-- 1 root root 3595788 Apr 8 08:54 fzfsjw.ttf
-rw-r--r-- 1 root root 10210620 Apr 8 08:55 fzhtk.ttf
-rw-r--r-- 1 root root 3759712 Apr 8 08:55 fzktjw.ttf
-rw-r--r-- 1 root root 3978284 Apr 8 08:55 fzlsjw.ttf
-rw-r--r-- 1 root root 2763072 Apr 8 08:55 fzssjw.ttf
-rw-r--r-- 1 root root 9300964 Apr 8 08:55 fzssk.ttf
-rw-r--r-- 1 root root 4762912 Apr 8 08:55 fzwbjw.ttf
其中fzssk.ttf和fzhtk.ttf是ISO10646的TTF。
制作fonts.dir和fonts.alias
#cat /usr/X11R6/lib/X11/fonts/FreeType/fonts.dir
13
fzssjw.ttf -freetype-song-medium-r-normal-jiantizi-0-0-0-0-c-0-gb2312.1980-0
fzktjw.ttf -freetype-kai-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
fzlsjw.ttf -freetype-lishu-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
fzwbjw.ttf -freetype-weibei-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
fzfsjw.ttf -freetype-fang-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
fzssk.ttf -freetype-song-medium-r-normal--0-0-0-0-c-0-iso10646.1993-1
fzssk.ttf -freetype-song-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
fzssk.ttf -freetype-song-medium-r-normal--0-0-0-0-c-0-gb13000.1993-1
fzssk.ttf -freetype-song-medium-r-normal--0-0-0-0-c-0-big5.eten-0
fzhtk.ttf -freetype-hei-medium-r-normal--0-0-0-0-c-0-iso10646.1993-1
fzhtk.ttf -freetype-hei-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
fzhtk.ttf -freetype-hei-medium-r-normal--0-0-0-0-c-0-gb13000.1993-1
fzhtk.ttf -freetype-hei-medium-r-normal--0-0-0-0-c-0-big5.eten-0
#cat /usr/X11R6/lib/X11/fonts/FreeType/fonts.alias
-freetype-song-medium-r-normal--0-0-0-0-c-0-gb2312.1980-1
-freetype-song-medium-r-normal--0-0-0-0-c-0-gb13000.1993-1
-freetype-hei-medium-r-normal--0-0-0-0-c-0--gb2312.1980-1
-freetype-hei-medium-r-normal--0-0-0-0-c-0-gb13000.1993-1
把/usr/X11R6/lib/X11/fonts/FreeType加入XFree86的字体目录中,在/etc/X11/XF86Config中的Section "Files"加入
FontPath "/usr/X11R6/lib/X11/fonts/FreeType/"
上面-*-gb13000.1993-1就是GBK字体。这名字在概念上是有些错误,但目前也没有更好的名字,而且大家都这么用,也就习惯了。如果是使用 TLC4.X或RF1.1,设置到此可以结束了。如果是北京腾图出的Manderake Linux 7.0,把RF1.1的/usr/X11R6/lib/modules/codeconv/GB13000.so拷贝到相同的目录下也可以了。
在XFree86 4.0下X-TT和xfsft是两个独立的模块,使用其中一个,就不能用另一个。如果在/etc/X11/XF86Config的Section "Module"是Load "freetype"则使用xfsft,如果是Load "xtt"则使用X-TT。
如果安装有xfsft,就会有一个目录/usr/X11R6/lib/X11/fonts/encodings。
其中CJK的编码转换表放在/usr/X11R6/lib/X11/fonts/encodings/large:
#ls /usr/X11R6/lib/X11/fonts/encodings/large -l
-rw-r--r-- 1 root wheel 65878 Mar 10 06:12 big5.eten-0.enc.gz
-rw-r--r-- 1 root wheel 693 May 3 10:00 encodings.dir
-rw-r--r-- 1 root root 105183 May 3 10:01 gb13000.1993-1.enc.gz
-rw-r--r-- 1 root wheel 33215 Mar 10 06:12 gb2312.1980-0.enc.gz
-rw-r--r-- 1 root wheel 184 Mar 10 06:12 jisx0201.1976-0.enc.gz
-rw-r--r-- 1 root wheel 32847 Mar 10 06:12 jisx0208.1983-0.enc.gz
-rw-r--r-- 1 root wheel 34392 Mar 10 06:12 jisx0208.1990-0.enc.gz
-rw-r--r-- 1 root wheel 23811 Mar 10 06:12 jisx0212.1990-0.enc.gz
-rw-r--r-- 1 root wheel 25951 Mar 10 06:12 ksc5601.1987-0.enc.gz
#cat /usr/X11R6/lib/X11/fonts/encodings/large/encodings.dir
9
big5.eten-0 /usr/X11R6/lib/X11/fonts/encodings/large/big5.eten-0.enc.gz
jisx0212.1990-0 /usr/X11R6/lib/X11/fonts/encodings/large/jisx0212.1990-0.enc.gz
jisx0208.1990-0 /usr/X11R6/lib/X11/fonts/encodings/large/jisx0208.1990-0.enc.gz
jisx0208.1983-0 /usr/X11R6/lib/X11/fonts/encodings/large/jisx0208.1983-0.enc.gz
big5-0 /usr/X11R6/lib/X11/fonts/encodings/large/big5.eten-0.enc.gz
gb2312.1980-0 /usr/X11R6/lib/X11/fonts/encodings/large/gb2312.1980-0.enc.gz
gb13000.1993-1 /usr/X11R6/lib/X11/fonts/encodings/large/gb13000.1993-1.enc.gz
jisx0201.1976-0 /usr/X11R6/lib/X11/fonts/encodings/large/jisx0201.1976-0.enc.gz
ksc5601.1987-0 /usr/X11R6/lib/X11/fonts/encodings/large/ksc5601.1987-0.enc.gz
其中gb13000.1993-1.enc.gz是GBK->Unicode编码转换表,是从Unicode下载转换表后按照enc文件格式自己制 作的。关于enc文件格式,可以看xfsft的随机文档,很简单的。因为gb13000.1993-1.enc.gz大于100kb,所以不能附上。
接着制作TTF目录下的fonts.scale和encodings.dir
#cp /usr/X11R6/lib/X11/fonts/FreeType/fonts.dir /usr/X11R6/lib/X11/
fonts/FreeType/fonts.scale
#cat /usr/X11R6/lib/X11/fonts/FreeType/encodings.dir
9
big5.eten-0 /usr/X11R6/lib/X11/fonts/encodings/large/big5.eten-0.enc.gz
jisx0212.1990-0 /usr/X11R6/lib/X11/fonts/encodings/large/jisx0212.1990-0.enc.gz
jisx0208.1990-0 /usr/X11R6/lib/X11/fonts/encodings/large/jisx0208.1990-0.enc.gz
jisx0208.1983-0 /usr/X11R6/lib/X11/fonts/encodings/large/jisx0208.1983-0.enc.gz
big5-0 /usr/X11R6/lib/X11/fonts/encodings/large/big5.eten-0.enc.gz
gb2312.1980-0 /usr/X11R6/lib/X11/fonts/encodings/large/gb2312.1980-0.enc.gz
gb13000.1993-1 /usr/X11R6/lib/X11/fonts/encodings/large/gb13000.1993-1.enc.gz
jisx0201.1976-0 /usr/X11R6/lib/X11/fonts/encodings/large/jisx0201.1976-0.enc.gz
ksc5601.1987-0 /usr/X11R6/lib/X11/fonts/encodings/large/ksc5601.1987-0.enc.gz
重新启动XF86,打开一个xterm
#xlsfonts | grep freetype
-freetype-fang-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
-freetype-hei-medium-r-normal--0-0-0-0-c-0--gb2312.1980-1
-freetype-hei-medium-r-normal--0-0-0-0-c-0-big5.eten-0
-freetype-hei-medium-r-normal--0-0-0-0-c-0-gb13000.1993-1
-freetype-hei-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
-freetype-hei-medium-r-normal--0-0-0-0-c-0-iso10646.1993-1
-freetype-kai-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
-freetype-lishu-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
-freetype-song-medium-r-normal--0-0-0-0-c-0-big5.eten-0
-freetype-song-medium-r-normal--0-0-0-0-c-0-gb13000.1993-1
-freetype-song-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
-freetype-song-medium-r-normal--0-0-0-0-c-0-gb2312.1980-1
-freetype-song-medium-r-normal--0-0-0-0-c-0-iso10646.1993-1
-freetype-song-medium-r-normal-jiantizi-0-0-0-0-c-0-gb2312.1980-0
-freetype-weibei-medium-r-normal--0-0-0-0-c-0-gb2312.1980-0
#xfd -fn -freetype-song-medium-r-normal--0-0-0-0-c-0-gb13000.1993-1 &
http://www.bross.cn/modules/discuz/viewthread.php?tid=359