「 创 造 一 个 中 文 TeX--从 头 开 始 」

GPL的 中 文 Postscript字 型 安 装 、 原 理 及 使 用


这 是 一 系 列 文 章 的 第 一 篇 , 我 将 在 未 来 的 文 章 中 逐 步 的 建 立 一 个 中 文 幕 後 排 版 系 统 。 它 提 供 了 一 般 排 版 系 统 所 应 具 有 的 自 动 走 文 , 图 形 插 入 , 字 型 字 体 变 换 及 图 形 功 能 。 它 的 基 本 系 统 和 TeX一 样 非 常 的 阳 春 , 它 提 供 的 是 机 制 而 非 策 略 , 也 就 是 说 它 提 供 我 们 将 系 统 组 态 为 像 任 何 其 它 系 统 的 机 会 , 如 果 你 希 望 系 统 照 你 的 方 式 运 作 , 你 可 以 藉 由 TCL巨 集 和 各 种 挂 钩 回 叫 函 数 来 达 到 你 控 制 排 版 过 程 的 目 的 。 用 这 些 功 能 你 可 以 加 入 如 页 次 显 示 、 自 动 目 录 产 生 、 交 互 参 考 等 功 能 。 以 後 的 文 章 将 一 一 详 细 的 描 述 这 些 功 能 应 如 何 在 基 本 系 统 下 完 成 。


王 佑 中


   这 一 篇 文 章 是 这 个 系 统 的 基 础 , 这 个 系 统 的 输 出 档 是 Postscript档 。 它 可 以 使 用 中 文 Postscript字 型 , 我 们 很 幸 运 的 有 一 套 GPL的 中 文 Postscript字 型 , 本 文 就 是 介 绍 它 的 原 理 及 安 装 使 用 。

   本 文 中 所 提 到 的 软 体 全 部 是 GPL的 软 体 , 我 对 其 中 许 多 程 式 都 加 入 修 改 , 这 些 修 改 的 程 式 在 将 来 都 会 公 开 , 目 前 在 我 只 把 执 行 档 直 接 放 在 光 碟 上 。 你 可 以 在 光 碟 中 的 [[[!!!麻 烦 您 填 上 正 确 的 路 径 !!!]]] 中 拿 到 这 些 程 式 , 并 且 如 果 你 想 知 道 原 始 程 式 的 位 置 , 请 参 考 ORIGINAL这 个 档 案 。

   目 前 UNIX上 有 许 多 套 中 文 列 印 程 式 , 基 本 上 它 们 的 输 出 档 都 是 Postscript档 。 这 是 因 为 我 们 有 一 个 最 好 的 GPL Postscript档 列 印 程 式 , 它 就 是 Ghsoscript。 Ghostscript有 绝 佳 的 可 移 植 性 , 它 所 支 援 的 列 印 设 备 范 围 几 乎 包 括 了 目 前 市 面 上 所 有 可 见 的 设 备 。 而 且 它 的 品 质 就 和 高 阶 Postscript印 表 机 一 样 好 , 甚 至 也 完 全 支 援 彩 色 列 印 的 功 能 。

   所 以 在 Linux的 环 境 下 所 用 Postscript做 为 输 出 档 的 格 式 是 很 自 然 的 选 择 。 但 是 要 让 Postscript档 支 援 中 文 列 印 也 不 是 一 件 很 容 易 的 事 , 原 因 是 Postscript基 本 上 所 使 用 的 字 型 格 式 中 主 要 是 为 单 位 元 组 字 集 所 设 计 。 对 於 像 中 文 这 种 双 位 元 组 的 字 集 在 当 初 设 计 时 并 未 考 虑 , 但 因 为 Postscript语 言 是 一 种 绘 图 语 言 , 所 以 我 们 当 然 可 以 把 中 文 当 做 图 形 来 处 理 , 不 过 Postscript所 直 接 支 援 的 一 些 文 字 列 印 功 能 就 不 能 用 了 。

   本 文 主 要 的 目 的 是 介 绍 一 套 在 GPL下 发 行 的 中 文 Postscript字 型 , 它 完 全 可 以 在 Ghostscript下 运 作 , 它 的 使 用 就 和 一 般 英 文 字 型 一 样 的 容 易 。 使 用 方 法 也 完 全 一 样 , 这 实 在 要 感 谢 杰 胜 公 司 的 慷 慨 , 使 我 们 能 有 这 一 个 字 型 可 用 。 但 很 可 惜 的 , 可 能 几 乎 没 有 人 知 道 如 何 在 Linux下 使 用 它 , 本 书 将 打 开 它 神 秘 的 面 纱 。 并 在 最 後 提 出 一 个 perl script使 大 家 可 以 使 用 它 来 列 印 简 单 的 文 字 档 。

   不 过 我 提 醒 各 位 , 这 里 所 提 到 的 字 型 在 目 前 附 在 Slackware内 的 Ghostscript 并 不 能 使 用 , 因 为 它 用 了 一 些 level 2的 功 能 (我 猜 )。 请 在 使 用 前 先 安 装 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-Regular findfont 80 scalefont setfont 100 100 moveto
(观 念 篇 ) show
showpage

Jackson字 型 的 原 理

   如 果 你 只 是 单 纯 的 想 使 用 字 型 , 那 这 一 节 就 可 以 省 略 了 。 这 一 节 是 给 那 些 对 Jackson字 型 原 理 有 兴 趣 , 或 想 自 己 做 其 它 Postscript字 型 的 人 看 的 。 我 们 可 以 由 TTF字 型 用 和 Jackson相 同 的 方 法 产 生 字 型 。

   下 文 中 提 到 叁 个 程 式 都 可 在 光 碟 上 找 到 , 它 们 的 档 名 分 别 是 CHPOST1.ps,CHPOST2.ps 和 CHPOST3.ps。 你 应 该 在 看 下 文 前 先 把 它 们 印 一 份 在 手 边 参 考 。

   由 於 在 原 先 的 Postscript level 1中 , Postscript所 提 供 的 Type 1和 Type 3 字 型 均 只 适 用 於 小 於 256字 的 字 集 。 所 以 Postscript在 level 2中 提 供 了 额 外 的 type 0字 型 (注 2), 一 般 称 为 合 成 字 (composite font), 它 本 身 并 没 有 有 关 字 型 的 资 料 。 相 反 的 它 是 用 来 将 多 个 不 同 的 字 型 组 合 成 一 个 字 型 , 也 就 是 说 一 个 13095字 的 字 集 , 须 要 52个 字 型 才 能 装 得 下 , 我 们 可 以 使 用 一 个 type 0字 型 来 代 表 这 些 字 型 。 更 清 楚 的 说 , 一 个 双 位 元 组 的 字 集 有 二 个 位 元 组 , 我 们 可 以 将 第 一 个 位 元 组 看 成 字 型 码 , 第 二 个 位 元 组 看 成 字 型 索 引 。 有 兴 趣 的 人 可 以 在 附 录 中 找 到 一 个 对 Postscript字 型 详 细 的 说 明 , 以 下 我 们 只 针 对 Jackson字 型 如 何 由 双 位 元 组 字 串 选 到 正 确 的 字 型 定 义 的 过 程 做 说 明 。 我 假 设 你 对 Postscript组 识 字 型 的 方 法 有 一 定 了 解 , 我 尽 量 重 复 使 用 到 的 字 型 功 能 , 如 仍 有 不 了 解 之 处 请 参 考 附 录 或 Postscript Language Reference Manual。

   首 先 我 把 KaiSu-Regular中 的 一 小 段 程 式 码 列 出 并 在 其 中 加 上 一 些 注 解 , 我 把 它 放 在 光 碟 中 的 CHPOST1.ps中 。 以 %%!开 头 的 注 解 是 执 行 到 该 行 时 stack的 状 况 (注 1), 它 并 不 在 原 先 的 字 型 中 。 如 果 程 式 看 不 懂 没 关 系 , 你 可 以 直 接 由 我 後 面 的 说 明 了 解 运 作 的 过 程 。

注 1: Postscript是 一 种 堆 叠 导 向 的 语 言 , 它 和 forth有 些 类 似 , 同 样 是 采 後 序 的 运 算 式 并 将 结 果 放 在 堆 叠 之 上 。

注 2: 在 有 些 level I的 系 统 中 也 有 这 个 延 伸 。

   一 个 Jackson字 型 为 一 个 Type 0的 字 型 , 它 被 分 为 89个 子 字 型 。 每 一 个 子 字 型 有 158个 字 元 , 这 刚 好 就 是 BIG5的 编 码 方 式 。 BIG5的 第 一 码 为 0xa1-0xf9共 59个 不 同 的 码 , 而 其 第 二 码 为 0x40-0x7e及 0xa1-0xfe共 158个 不 同 的 码 。 所 以 在 Jackson中 采 取 8/8的 映 射 方 式 , 上 面 的 /bc就 是 每 一 个 子 字 型 中 的 BuildChar程 式 , 这 个 程 式 是 type 3字 型 用 来 画 字 的 程 式 , Postscript在 呼 叫 这 个 程 式 之 前 会 把 字 型 字 典 和 字 型 索 引 堆 进 堆 叠 之 中 , 而 这 个 程 式 在 执 行 完 後 应 把 它 们 移 出 堆 叠 。

   因 为 中 文 字 集 的 字 元 数 实 在 太 多 , 我 们 不 能 如 英 文 字 集 般 把 所 有 字 元 的 定 义 都 一 次 载 入 记 忆 体 中 。 上 面 的 程 式 就 是 用 来 做 动 态 载 入 的 动 作 , 它 只 在 实 际 用 到 时 才 去 载 入 字 型 , 不 过 这 个 程 式 还 有 可 改 进 之 处 , 我 们 可 以 把 它 每 次 载 入 的 定 义 存 在 字 型 字 典 之 中 , 如 此 当 第 二 次 用 到 时 就 不 必 每 次 去 档 案 中 载 入 字 型 定 义 了 。

   上 面 的 程 式 还 有 一 个 可 议 之 处 , 它 放 弃 了 字 型 快 取 (font cache)的 使 用 。 这 可 能 使 程 式 的 速 度 大 受 影 响 , 我 还 不 太 明 白 它 放 弃 的 原 因 , 也 许 要 试 过 才 知 , 不 过 在 Ghostscript中 速 度 似 乎 还 可 以 接 受 。

   我 们 接 下 来 看 一 下 子 字 型 实 际 上 的 定 义 , 由 於 每 一 个 子 字 型 除 了 Offsets以 外 都 一 样 , 我 只 列 出 第 一 位 元 是 0xF9的 字 型 为 例 。 我 把 这 部 份 程 式 放 在 CHPOST2.ps这 个 档 案 中 。

   它 第 一 码 是 0xf9的 字 型 定 义 , 其 它 的 也 大 致 相 同 。 它 首 先 由 CFT1JacksonFontdict 中 将 各 项 字 型 资 料 拷 贝 过 来 , /DataFile就 是 字 型 资 料 档 的 名 称 , 而 /BuildChar就 是 指 到 前 述 的 /bc中 。 值 得 注 意 的 是 最 後 一 项 /Offsets, 它 是 一 个 长 度 为 158*3的 阵 列 , 其 中 每 一 项 就 是 相 对 字 元 在 资 料 档 中 启 始 的 位 置 。

   至 此 我 们 已 将 所 有 Type 3的 字 型 准 备 好 了 , 最 後 我 们 看 一 下 KaiSu-Regular这 个 type 0的 字 型 如 何 把 前 面 定 义 好 的 89个 字 型 组 合 在 一 起 , 且 了 解 一 下 Postscript 解 释 器 如 何 读 入 正 确 数 目 的 字 元 。 请 参 考 CHPOST3.ps这 个 档 案

   在 /KaiSu-Regular的 定 义 中 我 们 可 以 看 到 它 的 字 元 转 译 模 式 是 6(注 ), 这 表 示 它 使 用 SubsVector中 的 讯 息 来 解 释 输 入 字 串 。 它 的 SubsVector的 定 义 为

/SubsVector <00 80 21 58> 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字 型 , 其 馀 的 就 用 原 先 的 字 型 。

所 以 一 个 中 文 字 元 被 取 出 的 过 程 如 下 , 以 0xa1 0x40为 例

  1. KaiSu-Regular看 到 0xa1 0x40, 取 出 encoding为 2, 在 /FDepVector中 取 得 /CFT1JacksonFontSupp, 这 也 是 一 个 typ2 0字 型 。

  2. /CFT1JacksonFontSupp是 一 个 8/8 mapping的 type 0字 型 , 用 0xa1为 索 引 在 /Encoding中 取 出 0, 故 由 /FDepVector中 取 得 第 一 项 /CFT1JacksonFontA1。

  3. 将 CFT1JacksonFontA1堆 入 堆 叠 , 并 将 0x40也 推 入 堆 叠 , 呼 叫 /BuildChar也 就 是 前 述 的 /bc

  4. /bc由 CFT1JacksonFontA1中 的 /Encoding取 得 0x40的 索 引 为 0, 故 由 Offsets 中 取 得 档 案 的 位 置 0, 长 度 为 9。

  5. 读 入 这 个 字 元 定 义 , 这 是 一 个 type 1的 加 密 字 元 定 义 字 串 (encryped char strings)。

  6. 做 一 个 暂 时 的 字 型 叫 存 在 /CFT1JacksonFontTemp中 , 并 造 出 一 个 字 型 , 把 前 面 读 入 的 字 元 定 义 放 在 里 面 。

  7. 用 一 般 show指 令 将 这 个 临 时 产 生 的 Type 1字 型 中 的 字 元 印 出 。

看 起 来 有 些 复 杂 , 不 过 Ghostscript的 速 度 还 可 以 接 受 , 且 用 的 记 忆 体 也 还 可 接 受 。 不 过 我 有 点 怀 疑 它 在 Diplay Postscript时 的 速 度 。

如 何 由 TTF字 型 转 换 而 得 到 一 个 Postscript字 型

   看 到 这 个 标 题 很 多 人 心 跳 加 速 吧 ! 不 过 我 先 声 明 , 我 在 这 里 只 给 你 一 个 食 谱 而 没 有 任 何 菜 色 。 因 为 如 同 中 文 Postscript字 型 一 样 , 我 们 并 没 有 任 何 免 费 的 TTF 字 型 。 所 以 我 也 不 可 能 由 任 何 TTF字 型 做 Postscript字 型 给 你 , 我 只 能 告 诉 你 方 法 , 至 於 结 果 你 必 须 自 行 去 尝 试 了 。 而 且 这 可 能 不 是 一 件 容 易 的 事 , 你 如 果 决 定 要 自 己 一 试 , 那 你 告 检 查 一 下 你 的 配 备 是 否 足 以 胜 任 。

(1) 当 然 一 定 要 有 至 少 一 套 的 中 文 TTF字 型 。
(2) 至 少 16MB最 好 有 20MB以 上 的 记 忆 体 。
(3)至 少 50MB以 上 的 硬 碟 空 间 , 越 大 工 作 会 越 舒 服 , 因 为 你 不 必 把 中 间 产 生 的 档 删 除 。
(4) 很 多 很 多 的 时 间 及 很 多 很 多 的 耐 性 。

如 果 你 准 备 好 了 , 就 跟 着 我 开 始 上 路 吧 !

  1. 由 easyflow同 一 个 子 目 录 取 得 ttf2limn这 支 程 式 , 它 可 以 由 TTF字 型 产 生 一 个 158字 的 pk字 型 档 。 用 法 为

    ttf2limn ntk5161.1440pk ntk5161 1440 161 -s 10 -H 0.75 -D 0.25 -y 150 /cdrom/big5_k5.01_

    它 会 产 生 ntk5161.1440pk及 ntk5161.tfm二 个 档 。 上 面 的 参 数 和 ttf2pk中 使 用 的 相 似 , 唯 一 的 不 同 是 原 先 字 型 产 生 的 起 始 内 码 和 给 束 内 码 现 在 简 化 成 上 面 的 161, 它 是 产 生 字 型 档 中 字 型 的 第 一 码 。 如 果 你 接 着 要 产 生 162开 头 的 字 型 , 可 用

    ttf2limn ntk5162.1440pk ntk5162 1440 162 -s 10 -H 0.75 -D 0.25 -y 150 /cdrom/big5_k5.01_

  2. 由 同 一 个 位 置 取 得 limn这 个 程 式 , 它 可 以 由 上 面 产 生 的 pk档 中 fit产 生 一 个 type 1 的 外 框 字 。 它 有 很 多 参 数 必 须 调 整 , 下 面 是 我 使 用 的 , 你 可 以 参 考 fontutils-0.6 中 的 文 件 。 fontutils-0.6是 GNU的 产 品 。

    limn -verbose -corner-surround=8 \
    -filter-surround=12 \
    -filter-alternative=6 \
    -subdivide-surround=12 \
    -tangent-surround=12 \
    -dpi 1440 \
    -error-threshold=0.6 \
    -subdivide-threshold=0.01 \
    -filter-iterations=1 \
    -reparameterize-threshold=10 \
    ntk5161

  3. 取 得 bzrto产 生 type1的 字 型 , 其 用 法 为

    bzrto -encoding 256 -pstype1 ntk5161 -output ntk5161

  4. 将 58个 字 型 一 一 产 生 , 名 字 依 序 为

    ntk5160.gsf
    ntk5161.gsf
    .
    .
    .
    ntk5259.gsf

    我 用 perl写 了 一 个 程 式 把 产 生 这 些 档 案 的 过 程 自 动 化 , 它 的 用 法 为

    
            maketype1 ntk5  2880 /cdrom/big5_k5.01_
    
                       |     |              |
    
                       |     +-----+         +------ TTF字 型 档 的 路 径 
    
                      字 型 名 称      |
    
                                 使 用 ttf2limn时 产 生 字 型 的 大 小 , 当 然 越 
    
                                 大 越 好 , 但 硬 碟 .....
    
    

       这 个 命 令 会 自 动 执 行 上 述 (1) (2) (3)中 所 有 的 动 作 。 下 了 这 个 命 令 , 你 可 以 去 睡 一 觉 , 醒 来 它 可 能 刚 好 做 完 ,

  5. 将 上 述 档 中 的 Type 1字 元 定 义 取 出 组 成 一 个 字 元 定 义 档 。 在 光 碟 上 有 一 个 程 式 makeup_jackson来 做 这 件 事 。

    # makeup_jackson ntk5 36001

       这 会 产 生 一 个 叫 ntk5.hex的 档 案 , 并 产 生 一 个 叫 ntk5.pf0的 档 案 。 它 是 由 前 述 的 KaiSu-Regular修 改 而 来 。 第 二 个 参 数 是 字 型 的 UID, 要 注 意 不 要 和 其 它 字 型 的 UID 重 复 了 。

  6. 上 一 步 中 产 生 的 ntk5.hex是 一 个 用 hex字 串 格 式 编 码 的 档 案 , 我 们 通 常 把 它 转 换 成 二 进 位 档 以 节 省 空 间 及 增 加 处 理 速 度 。 我 提 供 了 hextobin做 这 件 工 作 , 它 设 计 成 一 个 filter的 型 式 , 用 法 为

    # ./hextobinntk5.dat

  7. 将 ntk5.pf0和 ntk5.dat装 到 /usr/lib/ghostscript/fonts中 , 并 在 /usr/lib/ghostscript/Fontmap中 加 入

    /ntk5 (ntk5.pf0) ;

  8. 拿 下 面 的 程 式 测 试 看 看 你 的 成 果 , 注 意 程 式 中 第 一 行 载 入 一 个 Postscript档 , 这 个 档 定 义 了 一 些 在 字 型 中 会 用 到 的 定 义 。 它 可 以 和 其 它 程 式 一 起 得 到

    /ntk5 findfont 80 scalefont setfont
    100 100 moveto
    (观 念 篇 ) show
    showpage

       看 起 来 不 太 难 , 但 至 少 会 花 去 你 一 天 的 时 间 , 有 兴 趣 的 人 试 试 看 吧 。 也 许 我 们 可 以 慢 慢 的 建 立 一 套 自 动 的 系 统 , 让 每 个 人 都 可 以 容 易 的 产 生 字 型 。 这 个 程 序 产 生 的 字 型 都 有 一 些 虚 胖 的 现 象 , 这 是 因 为 我 们 在 做 fit字 型 的 工 作 时 不 论 对 简 单 的 字 型 或 复 杂 的 字 型 都 用 相 同 的 参 数 , 所 以 简 单 的 字 型 难 免 有 些 虚 胖 的 现 象 。 以 全 形 的 逗 号 而 言 , 在 Jackson字 型 中 用 8个 位 元 就 表 示 出 来 了 , 但 在 用 上 述 过 程 以 文 新 的 big5_k5.ttf 为 例 则 长 达 53个 位 元 。 要 消 除 这 种 状 况 可 能 要 一 个 能 以 字 元 为 单 位 设 定 参 数 的 程 式 , 而 且 要 很 多 人 的 参 与 才 能 做 到 。

使 用 Jackson字 型 列 印 中 文 文 字 档

   在 最 後 我 介 绍 一 个 很 简 单 的 perl script, 它 可 以 用 来 将 中 中 文 件 档 利 用 Jackson 字 型 列 印 。 它 的 功 能 很 简 单 , 但 己 足 够 解 决 大 多 数 中 文 列 印 上 的 问 题 。 其 用 法 为

makeps [-f ] <in> <out> <size>

<font> 字 型 名 称 , 如 /KaiSu-Regular
<in> 欲 列 印 的 文 件 档
<out> 产 生 的 Postscript档
&ltsize> 使 用 的 字 型 大 小

   你 可 以 用 它 来 验 证 你 产 生 的 Postscript字 型 或 是 其 它 任 何 来 源 的 Postscript字 型 , 它 会 用 横 放 二 栏 式 的 方 式 列 印 。 当 然 这 个 程 式 还 没 有 经 过 太 多 的 测 试 , 可 能 还 有 很 多 问 题 , 你 可 以 直 接 直 作 者 反 映 问 题 , 如 果 顺 便 把 解 答 告 诉 我 是 最 好 不 过 的 了 。

(相 关 程 式 见 前 期 光 碟 \AUTHOR\Jackson\子 目 录 )