这一篇文章是这个系统的基础,这个系统的输出档是Postscript档。它可以使用中文Postscript字型,我们很幸运的有一套GPL的中文Postscript字型,本文就是介绍它的原理及安装使用。
本文中所提到的软体全部是GPL的软体,我对其中许多程序都加入修改,这些修改的程序在将来都会公开,目前在我只把执行档直接放在光盘上。你可以在光盘中的[[[!!!麻烦您填上正确的路径!!!]]]中拿到这些程序,并且如果你想知道原始程序的位置,请参考ORIGINAL这个文件。
目前UNIX上有许多套中文列印程序,基本上它们的输出档都是Postscript档。这是因为我们有一个最好的GPLPostscript档列印程序,它就是Ghsoscript。Ghostscript有绝佳的可移植性,它所支援的列印设备范围几乎包括了目前市面上所有可见的设备。而且它的品质就和高阶Postscript印表机一样好,甚至也完全支援彩色列印的功能。
所以在Linux的环境下所用Postscript做为输出档的格式是很自然的选择。但是要让Postscript档支援中文列印也不是一件很容易的事,原因是Postscript基本上所使用的字型格式中主要是为单位元组字集所设计。对於像中文这种双位元组的字集在当初设计时并未考虑,但因为Postscript语言是一种绘图语言,所以我们当然可以把中文当做图形来处理,不过Postscript所直接支援的一些文字列印功能就不能用了。
本文主要的目的是介绍一套在GPL下发行的中文Postscript字型,它完全可以在Ghostscript下运作,它的使用就和一般英文字型一样的容易。使用方法也完全一样,这实在要感谢杰胜公司的慷慨,使我们能有这一个字型可用。但很可惜的,可能几乎没有人知道如何在Linux下使用它,本书将打开它神秘的面纱。并在最後提出一个perlscript使大家可以使用它来列印简单的文字档。
不过我提醒各位,这里所提到的字型在目前附在Slackware内的Ghostscript并不能使用,因为它用了一些level2的功能(我猜)。请在使用前先安装3.33版以上的Ghostscript,我帮各位将它编译成gs333.tgz,这个文件也在光盘上可找到。不过其中并没有字型,请各位自己去把字型找来安装。(沿用2.61的字型也无不可,记得把Fontmap拷到/usr/lib/ghostscript/3.33中)
Jackson字型的安装
Jackson的中文Postscript字型可以在NCTUCCCA.EDU.TW://NeXT/Chinese/KaiSu.pkg_0_7.tar.gz中取得。但它没有辨法直接在Linux下列开,我把它解开後取出有用的部份并把它放在光盘中。
Jackson的字型分成二个档,一个是用来建立它的Postscript语言档,另一个是放字型定义的档。
KaiSu-Regular=====>字型定义档
KaiSu-Regular.dat=====>字型资料档
要把它放入Ghostscript内的步骤为
(1)将上述二个文件放入/usr/lib/ghostscript/fonts中。
(2)修改/usr/lib/ghostscript/Fontmap在最後加入/KaiSu-Regular(KaiSu-Regular); 不要忘了最後的分号。
(3)用下列文件测试它的功能。
你应该可以看到大大的观念篇叁个字。
#!
/KaiSu-Regularfindfont80scalefontsetfont100100moveto
(观念篇)show
showpage Jackson字型的原理
如果你只是单纯的想使用字型,那这一节就可以省略了。这一节是给那些对Jackson字型原理有兴趣,或想自己做其它Postscript字型的人看的。我们可以由TTF字型用和Jackson相同的方法产生字型。
下文中提到叁个程序都可在光盘上找到,它们的档名分别是CHPOST1.ps,CHPOST2.ps和CHPOST3.ps。你应该在看下文前先把它们印一份在手边参考。
由於在原先的Postscriptlevel1中,Postscript所提供的Type1和Type3字型均只适用於小於256字的字集。所以Postscript在level2中提供了额外的type0字型(注2),一般称为合成字(compositefont),它本身并没有有关字型的资料。相反的它是用来将多个不同的字型组合成一个字型,也就是说一个13095字的字集,须要52个字型才能装得下,我们可以使用一个type0字型来代表这些字型。更清楚的说,一个双位元组的字集有二个位元组,我们可以将第一个位元组看成字型码,第二个位元组看成字型索引。有兴趣的人可以在附录中找到一个对Postscript字型详细的说明,以下我们只针对Jackson字型如何由双位元组字串选到正确的字型定义的过程做说明。我假设你对Postscript组识字型的方法有一定了解,我尽量重复使用到的字型功能,如仍有不了解之处请参考附录或PostscriptLanguageReferenceManual。
首先我把KaiSu-Regular中的一小段程序码列出并在其中加上一些注解,我把它放在光盘中的CHPOST1.ps中。以%%!开头的注解是执行到该行时stack的状况(注1),它并不在原先的字型中。如果程序看不懂没关系,你可以直接由我後面的说明了解运作的过程。 注1:Postscript是一种堆叠导向的语言,它和forth有些类似,同样是采後序的运算式并将结果放在堆叠之上。 注2:在有些levelI的系统中也有这个延伸。
一个Jackson字型为一个Type0的字型,它被分为89个子字型。每一个子字型有158个字元,这刚好就是BIG5的编码方式。BIG5的第一码为0xa1-0xf9共59个不同的码,而其第二码为0x40-0x7e及0xa1-0xfe共158个不同的码。所以在Jackson中采取8/8的映射方式,上面的/bc就是每一个子字型中的BuildChar程序,这个程序是type3字型用来画字的程序,Postscript在呼叫这个程序之前会把字型字典和字型索引堆进堆叠之中,而这个程序在执行完後应把它们移出堆叠。
因为中文字集的字元数实在太多,我们不能如英文字集般把所有字元的定义都一次载入记忆体中。上面的程序就是用来做动态载入的动作,它只在实际用到时才去载入字型,不过这个程序还有可改进之处,我们可以把它每次载入的定义存在字型字典之中,如此当第二次用到时就不必每次去文件中载入字型定义了。
上面的程式还有一个可议之处,它放弃了字型快取(fontcache)的使用。这可能使程式的速度大受影响,我还不太明白它放弃的原因,也许要试过才知,不过在Ghostscript中速度似乎还可以接受。
我们接下来看一下子字型实际上的定义,由於每一个子字型除了Offsets以外都一样,我只列出第一位元是0xF9的字型为例。我把这部份程式放在CHPOST2.ps这个档案中。
它第一码是0xf9的字型定义,其它的也大致相同。它首先由CFT1JacksonFontdict中将各项字型资料拷贝过来,/DataFile就是字型资料档的名称,而/BuildChar就是指到前述的/bc中。值得注意的是最後一项/Offsets,它是一个长度为158*3的阵列,其中每一项就是相对字元在资料档中启始的位置。
至此我们已将所有Type3的字型准备好了,最後我们看一下KaiSu-Regular这个type0的字型如何把前面定义好的89个字型组合在一起,且了解一下Postscript解释器如何读入正确数目的字元。请参考CHPOST3.ps这个档案
在/KaiSu-Regular的定义中我们可以看到它的字元转译模式是6(注),这表示它使用SubsVector中的讯息来解释输入字串。它的SubsVector的定义为
/SubsVector<00802158>def
第1个00代表每次读入一个字元,後面叁个数字代表整个字型被分为四段,依次为第0-3号字型,然後由/Encoding中取出实际的字型编号,在这里就刚好是0-3,然後再由/FDepVector中取出实际的字型。上面的过程用意在分辨中文和英文的字型,如果把实际的字型范围列出。
0-0x7f第0号字型/_@ASCII
0x80-0xa0第1号字型/NotDefFont
0xa1-0xf9第2号字型/CFT1JacksonFontSupp
0xfa-0xff第3号字型/NotDefFont
这就是BIG5码的定义,在这个过程中只有合法的第一码实际取用到了Jackson字型,其馀的就用原先的字型。
所以一个中文字元被取出的过程如下,以0xa10x40为例
KaiSu-Regular看到0xa10x40,取出encoding为2,在/FDepVector中取得/CFT1JacksonFontSupp,这也是一个typ20字型。
/CFT1JacksonFontSupp是一个8/8mapping的type0字型,用0xa1为索引在/Encoding中取出0,故由/FDepVector中取得第一项/CFT1JacksonFontA1。
将CFT1JacksonFontA1堆入堆叠,并将0x40也推入堆叠,呼叫/BuildChar也就是前述的/bc
/bc由CFT1JacksonFontA1中的/Encoding取得0x40的索引为0,故由Offsets中取得档案的位置0,长度为9。
读入这个字元定义,这是一个type1的加密字元定义字串(encrypedcharstrings)。
做一个暂时的字型叫存在/CFT1JacksonFontTemp中,并造出一个字型,把前面读入的字元定义放在里面。
用一般show指令将这个临时产生的Type1字型中的字元印出。
看起来有些复杂,不过Ghostscript的速度还可以接受,且用的记忆体也还可接受。不过我有点怀疑它在DiplayPostscript时的速度。
如何由TTF字型转换而得到一个Postscript字型
看到这个标题很多人心跳加速吧!不过我先声明,我在这里只给你一个食谱而没有任何菜色。因为如同中文Postscript字型一样,我们并没有任何免费的TTF字型。所以我也不可能由任何TTF字型做Postscript字型给你,我只能告诉你方法,至於结果你必须自行去尝试了。而且这可能不是一件容易的事,你如果决定要自己一试,那你告检查一下你的配备是否足以胜任。
(1)当然一定要有至少一套的中文TTF字型。
(2)至少16MB最好有20MB以上的记忆体。
(3)至少50MB以上的硬碟空间,越大工作会越舒服,因为你不必把中间产生的档删除。 (4)很多很多的时间及很多很多的耐性
如果你准备好了,就跟着我开始上路吧!
由easyflow同一个子目录取得ttf2limn这支程式,它可以由TTF字型产生一个158字的pk字型档。用法为
ttf2limnntk5161.1440pkntk51611440161-s10-H0.75-D0.25-y150/cdrom/big5_k5.01_
它会产生ntk5161.1440pk及ntk5161.tfm二个档。上面的参数和ttf2pk中使用的相似,唯一的不同是原先字型产生的起始内码和给束内码现在简化成上面的161,它是产生字型档中字型的第一码。如果你接着要产生162开头的字型,可用
ttf2limnntk5162.1440pkntk51621440162-s10-H0.75-D0.25-y150/cdrom/big5_k5.01_
由同一个位置取得limn这个程式,它可以由上面产生的pk档中fit产生一个type1的外框字。它有很多参数必须调整,下面是我使用的,你可以参考fontutils-0.6中的文件。fontutils-0.6是GNU的产品。
limn-verbose-corner-surround=8
-filter-surround=12
-filter-alternative=6
-subdivide-surround=12
-tangent-surround=12
-dpi1440
-error-threshold=0.6
-subdivide-threshold=0.01
-filter-iterations=1
-reparameterize-threshold=10
ntk5161
取得bzrto产生type1的字型,其用法为
bzrto-encoding256-pstype1ntk5161-outputntk5161
将58个字型一一产生,名字依序为
ntk5160.gsf
ntk5161.gsf
.
.
.
ntk5259.gsf
我用perl写了一个程式把产生这些档案的过程自动化,它的用法为
maketype1ntk52880/cdrom/big5_k5.01_
|||
|+-----++------TTF字型档的路径
字型名称|
使用ttf2limn时产生字型的大小,当然越 大越好,但硬碟.....
这个命令会自动执行上述(1)(2)(3)中所有的动作。下了这个命令,你可以去睡一觉,醒来它可能刚好做完。
将上述档中的Type1字元定义取出组成一个字元定义档。在光碟上有一个程式makeup_jackson来做这件事。
#makeup_jacksonntk536001
这会产生一个叫ntk5.hex的档案,并产生一个叫ntk5.pf0的档案。它是由前述的KaiSu-Regular修改而来。第二个参数是字型的UID,要注意不要和其它字型的UID重复了。
上一步中产生的ntk5.hex是一个用hex字串格式编码的档案,我们通常把它转换成二进位档以节省空间及增加处理速度。我提供了hextobin做这件工作,它设计成一个filter的型式,用法为
#./hextobinntk5.dat
将ntk5.pf0和ntk5.dat装到/usr/lib/ghostscript/fonts中,并在/usr/lib/ghostscript/Fontmap中加入
/ntk5(ntk5.pf0);
拿下面的程式测试看看你的成果,注意程式中第一行载入一个Postscript档,这个档定义了一些在字型中会用到的定义。它可以和其它程式一起得到
/ntk5findfont80scalefontsetfont
100100moveto
(观念篇)show
showpage
看起来不太难,但至少会花去你一天的时间,有兴趣的人试试看吧。也许我们可以慢慢的建立一套自动的系统,让每个人都可以容易的产生字型。这个程序产生的字型都有一些虚胖的现象,这是因为我们在做fit字型的工作时不论对简单的字型或复杂的字型都用相同的参数,所以简单的字型难免有些虚胖的现象。以全形的逗号而言,在Jackson字型中用8个位元就表示出来了,但在用上述过程以文新的big5_k5.ttf为例则长达53个位元。要消除这种状况可能要一个能以字元为单位设定参数的程式,而且要很多人的参与才能做到。
使用Jackson字型列印中文文字档
在最後我介绍一个很简单的perlscript,它可以用来将中中文件档利用Jackson字型列印。它的功能很简单,但己足够解决大多数中文列印上的问题。其用法为
makeps[-f]
字型名称,如/KaiSu-Regular
欲列印的文件档
产生的Postscript档
使用的字型大小
你可以用它来验证你产生的Postscript字型或是其它任何来源的Postscript字型,它会用横放二栏式的方式列印。当然这个程式还没有经过太多的测试,可能还有很多问题,你可以直接直作者反映问题,如果顺便把解答告诉我是最好不过的了。