序幕有些长
为一份 ConTeXt 中文教程整理的序
背景
TeX 相关软件中文字体嵌入一个存在已久的问题水落石出,兼谈不拘小节的中文字体设计中 Wang Yue 谈到了这样的问题:
中文字体设计不拘小节也让我也想到了另一个问题,用先前,中文用户使用 XeTeX,需要频繁地切换中英文字体,后来 XeTeX 开发者不得不提供了一个机制来让字体切换变得不那么折腾。而我和 ConTeXt 开发者交流中文排版问题,还要煞费苦心地讲怎么切换,需要编程实现复杂的虚拟字体机制来实现。这个都归罪于中文字体普遍地缺乏高质量的英文部分,仔细看看 simsun 或者 simhei 的英文部分,就可以看出有多么夸张了。
如果说这个问题的原因是中国的字体公司,向来没有很好的英文字体设计基础,同时对这个问题也不加以重视,那么中文标点的设计,就没有丝毫的可以开罪的地方了,这个问题直接导致用户和开发者都非常为难。我们知道,高质量的中文排版,标点并不是占据一个中文字符的位置,而要比中文字符略小。 同时,标点之间需要存在压缩,比如逗号后紧紧跟随的关门引号,需要使用类似 kerning 的特性把两个 glyph 的距离减小。另外,类似破折号和省略号, 其实应该放在一个 glyph 中而不应该分开。而现在所有的中文字体的糟糕程度,竟然到所有的标点符号都占用一个中文字符距离的程度。本来这个问题如果中文 字体设计得当,使用默认的排版算法,就基本上能够解决一般的中文的排版问题,而现在糟糕的设计就使得排版软件的设计难上加难。首先我们需要重新定义一系列 的新算法和新规则,然后需要手工赋值去确定标点的大小和两个标点连在一起时候的压缩程度。更麻烦的是,不同字体中的相同的 glyph,比如逗号或者句号, 往往会在这个 box 的不同的位置,大小也会千差万别。调好了中易宋体的冒号和开门引号,把相同的数值使用到中易的隶书中,顿时两个符号就会挤在一起,这就 使得如果不针对每一个字体仔细调整,高质量的中文排版就几乎不可能。
我是受了 Wang Yue 几篇文章忽悠才开始使用 ConTeXt MkIV(下面简称 MkIV)的,迄今为止一年又半载。期间,看见了 MkIV 的效率以及 CJK 文字支持的诸多进步。比如,现在利用 MkIV 的 fallback 字体机制,已经很好地解决了中西文字体混合的问题,也就是说用设计比较专业的英文字体去替换中文字体所包含的英文字符部分。此外 Wolfgang Schuster 实现了 simplefonts 模块,提供了类似 XeLaTeX 的 fontspec 宏包那样的功能,简化了 ConTeXt 字体配置过程。但是,对于中文标点符号的处理,迄今也未有解决。虽然 Hans 多次许诺将来会解决这个问题,但是我们不知道他说的将来是什么时候了。
为了让 ConTeXt 对中文支持的更好一些,我想自己动手解决这个问题。假如将来 Hans 真的兑现了他所说的,提供了很好的中文支持,大不了我就扔掉这块工作。
一开始,我不知道该从哪里入手,在 ConTeXt 的 base 目录里 grep 了好长时间,发现有关中文断行以及标点处理的代码集中在 font-otf.lua 文件里,当时我对这个文件进行了一些 hack,只得到到了轻微的改善,不过我却受到了鼓舞,打消了对 ConTeXt 的畏惧。后来 Hans 对 CJK 文字的处理进行了调整,原先在 font-otf.lua 文件里的 CJK 文字处理部分的代码被重新改写了,并且放在了 scrp-ini.lua 和 scrp-cjk.lua 文件中,我对这两个文件继续 hack,工作成果见 http://bbs.ctex.org/viewthread.php?tid=48562。在此期间,把学习 MkIV 过程中胡乱写的一些笔记整理了一下,挂在了 http://bbs.ctex.org/viewthread.php?tid=45237。我不是一个有耐心的人,做什么事情都是三分钟热度,再加上 MkIV 层出不穷的 bug,所以有一段时间对 MkIV 的喜欢的热度也退却了很多。
在 hack MkIV 的时候,我感觉 MkIV 对中文标点的处理方式很脏,太依赖具体的字体。像 scrp-cjk.lua 文件中的许多参数,对 AdobeSongStd-Light.otf 字体是适合的,但是换成 simsun.ttc 就不行了,具体见 http://bbs.ctex.org/viewthread.php?tid=47559。仅仅是因为这个看似很小的问题,我还几次都想回到 XeTeX + xeCJK 的环境里。如果 OpenOffice.org 在排版方面不是那么废柴,我甚至都可以放弃 TeX。
再后来,看到 Wang Yue 频率较高的宣扬利用 bbox 来解决中文标点间距压缩问题,说这样就可以做到不依赖具体的字体。一开始,我对此是不以为然的,而且我也没法以之为然,因为那时我只是比较浅薄地知道 scrp-cjk.lua,其它的我都不知道。直到后来,孙文昌(CTeX 论坛的 mytex)老师给出了一个示例(见 http://bbs.ctex.org/viewthread.php?tid=49757)之时,我才大致明白所谓 bbox 的解决方式是怎么一回事。另外,Wang Yue 精简 ConTeXt Minimals,作了一个 mini luatex 包,我从他那里学会了如何生成 luatex 格式文件,如何在 tex 文件里加载自己写的 lua 程序。
我对 LuaTeX 和 MkIV 的认识就是这样私有似无地累积起来了,直到有一天我感觉可以从 LuaTeX 的层面上来实现对中文的单独处理,这样我就可以摆脱 Hans 的那套目前有些残废的中文支持方式,不必再担心他每一次升级 beta 版本而让我没法再用中文。虽然事实上还是有隐患,因为 Hans 为 LuaTeX 分离出来的字体处理部分,也就是 luatex-fonts-merged.lua 文件,它也是不稳定的,但是至少要比 MkIV 稳定。这段时间,我一直在折腾这件事情,随着最后一个有关标点边界对齐问题得到了解决,现在整套方案终于有了一个大概的眉目。
现在,打算正式开始解决这个问题。在此过程中,我会再重新整理一下思路,以连载的形式记录整个过程,希望能够对喜欢 LuaTeX与 MkIV 的同学有所帮助。
开始全面接触 GTK+
说来也惭愧,2 年前我就打算好好学习 GTK+,期间断断续续的进行了几次,每次都是浅尝辄止。这主要是因为在我们的项目里,我不负责界面设计,因此也没有足够的动力。另外,我将大把的时间都用来折腾 TeX 上了,从 PDFTeX、XeTeX 到 LuaTeX,从 LaTeX 到 ConTeXt,又从 ConTeXt MkII 到 ConTeXt MkIV。现在之所以决定认真的搞定 GTK+,是因为有些鲠骨在咽般的因素在刺激我。
实现 ConTeXt MkIV 中文标点压缩与边界对齐
这几天,抽了些时间,试图自行解决 ConTeXt MkIV 的标点压缩与边界对齐。由于 Hans 在新的 MkIV 中对 CJK 文字处理框架进行了修整,只需要很简单的一点 hack 工作,问题基本上就得以解决。现在总算有一点心满意足,可以继续耐心地等待 Hans 他们实现 MkIV 对中文排版的完善支持的那一天。
简单 show 一下效果,因为很少有人关注,主要是自我欣赏一下。
我将 hack 过程整理成两份文档,可以从 http://bbs.ctex.org/viewthread.php?tid=48562&extra=page%3D1 下载。
We need a perfect solution of Chinese support in TeX
These days I have tried to understand a few segments of source code about Chinese support in ConTeXt MkIV, because, with my own efforts, I want to solve the problem of Chinese puncuations appeared on the right side of pages which often affect the aesthetic feel of typesetting. I noticed that there two lines of code that look like unnecessary and I hide them with comment sign. After regenerating ConTeXt formats, I recompiled those documents that I have already finished including those in CTXnotes project. I found all is ok! Now Chinese puncuations never appear on the right side and the layout looks very tidy.
被迫清心寡欲地使用中文字体
最近,ConTeXt MkIV 的混合字体机制出现了一个以前出现过的问题,即:在不同的 typescript 环境中(比如 Serif 和 Mono),如果向同一款中文字体的相同编码区域注入两种不同的西文字体,那么只有首次注入的西文字体才是有效的。That is to say, 只能是一款中文字体与一款英文字体进行混合。
压缩标点之间的间距
昨天,耐心地阅读了 MkIV 的 font-otf.lua 最后那一部分处理中文的代码,终于看出了一点门道,并向其中添加了一小段代码用于压缩两个紧挨着的中文标点的间距。另外,font-otf.lua 也未对中文引号进行标点压缩,这个问题我也通过 hack 的方式解决了。
首字下沉
Taco 从 LaTeX 的 lettrine.sty 宏包中 port 过来一个 t-lettrine,使得 ConTeXt 可以很方便地处理首字下沉问题。
\usetypescript[palatino][qx]
\setupbodyfont[11pt,palatino]
\usemodule[lettrine]
\setuplettrine[Nindent=0pt]
\starttext
\lettrine{M}{an} was last to come but the first to use his brain for the purpose of conquering the forces of nature. That is the reason why we are going to study him, rather than cats or dogs or horses or any of the other animals, who, all in their own way, have a very interesting historical development behind them.
\stoptext