PDFlibPas 能让日文和中文文本沿页面自上而下排布。SetVerticalWritingMode 打开竖排模式,普通的 DrawText 调用随之向下行进,GetVerticalWritingMode 报告当前状态。在此之前,要把文本竖排意味着逐字手工摆放,再祈祷间距看起来过得去
竖排不是把水平文本旋转九十度。字符保持正立,字距沿竖向而非横向推进,而且相当一部分字符会彻底改形——这正是一份读起来自然的文档与一份日文读者一眼就认出是机器生成的文档之间的分水岭
PDF 内部发生了什么变化
这样绘制的文本会经过一个处于竖排模式、携带字形自身竖排度量(metrics)的 Type0 字体。这在两个方向上都很重要。一方面,阅读器按字符设计者意图的距离推进每一个字,而不是按统一的步长,所以这一列的节奏正是字体为之绘制的那种节奏。另一方面,把文本复制出来得到的是原始字符,因为这段竖排仍然是带正确映射的真实文本,而不是一串被定位过的字形
一个不携带自身竖排度量的字形会按每个字一个 em 推进,这正是阅读器在默认情况下会做的。这个回退值得了解,因为当你用一份合适的 CJK 字形得到正确渲染、用某个恰好包含一些假名的拉丁字形得到机械式间距时,看到的差别就来自这里
var
Lib: TPDFlib;
H: Double;
begin
Lib := TPDFlib.Create;
try
Lib.SetOrigin(1);
Lib.AddTrueTypeFont('MS Mincho', 1); // 1 = embed the face
Lib.SetTextSize(12);
Lib.SetVerticalWritingMode(1); // ordinary DrawText now runs down
H := Lib.GetVerticalTextHeight('MS Mincho', 12, '第三章 保守点検');
Lib.DrawText(480, 72, '第三章 保守点検');
Lib.SetVerticalWritingMode(0); // back to horizontal
Lib.DrawText(72, 72 + H, 'Chapter 3');
Lib.SaveToFile('manual-ja.pdf');
finally
Lib.Free;
end;
end;
为什么竖排里的括号看起来不对
因为括号有两种形态,在竖列中只该出现其中一种。当文本沿页面自上而下排布时,括号、长音符号和小写假名的画法不同——圆括号会旋转成顺着列的方向,而不是横跨着摆放;长音符号则变成一道竖线。把水平形态画进竖列,每一个都会侧躺着
PDFlibPas 从字体自身的竖排特性(vertical feature)里取这些形态,所以每种字形提供的是其设计者所画的形态,而不是从字符猜出的替换。这一区别对正确性很关键:一份猜测出来的替换表对常见情况是对的,但对那些把某个字符处理得与众不同的字形就是错的;而一个没有声明任何竖排形态的字形会被原样绘制,而不是被迫穿过一个它从未要求的表
GetVerticalTextHeight 度量的是实际将要绘制的形态,所以一列里字符会发生改形时仍能得到正确的度量。度量水平形态却绘制竖排形态,是那些列会多溢出几个字符到框外的经典根源
不改模式画一段竖排
DrawVerticalText 不改动书写模式,单独画一段竖排文本,它接收位置、字体名、字号和文本。用在水平文档里偶尔需要的竖排例外——书脊标签、印章、单列人名——这些场景里每次调用都围绕一个全局模式来回开关,带来的状态比任务本身应得的还要多
同一字形的水平形态和竖排形态在内部是分开维护的,所以一页可以同时携带两者而互不干扰。这正是让混排页面可行的原因:一页带竖排正文和水平页眉的日文书页,或一份标题竖排、明细行水平排列的中文证书
// One vertical run inside an otherwise horizontal page
Lib.DrawVerticalText(520, 96, 'MS Mincho', 14, '保守点検記録');
// The horizontal text around it is unaffected
Lib.DrawText(72, 96, 'Maintenance inspection record');
先把字体搞定再谈其他
竖排完全取决于字形。一个带正确竖排度量和竖排特性的 CJK 字体无需额外工作就能产生正确输出;缺少这两者的字体会输出正立但每字一个 em 推进、毫无改形的字符。如果竖排文本看起来微妙地不对,先查字体,再查代码
嵌入遵循通常的规则,也付出通常的代价。一个完整的 CJK 字形体积庞大,所以对要发往任何地方的文档来说子集化不是可选项——PDF 文件大小优化与字体子集化的笔记覆盖了可以预期什么,而 给既有 PDF 嵌入缺失字体的详解覆盖了一份竖排文档到达时缺字体的修复场景
竖排文本仍需你来做的排版决策
列序。日文竖排按列从右到左推进,所以一个双栏页面从右边缘开始,没有任何书写模式设置能从文本里推断出这一点。整份从右到左阅读的文档的页面顺序、振假名、脚注和图注的位置,同理
库所保证的是每一段文本都被正确排布:正确的形态、正确的推进、可提取的文本。这些文本在页面上落在何处是排版问题,对于由数据拼装而成的文档,文本搜索与页面元素枚举的详解有助于在事后核实落到页面上的正是你想要的
PDFlibPas 是面向 Delphi、C++Builder 和 Lazarus 的原生 Pascal PDF 库,竖排 CJK 是绘图 API 的一部分而非附加件——文本与字体的功能清单见 PDFlibPas 产品页