在 jsarticle 里指定「10 磅」,实际排出的日文字号只有约 9.25 磅。这不是缺陷,而是设计:奥村晴彦的 jsclasses(jsarticle、jsbook)是以日文印刷使用的 13 级(3.25 mm) 为基准来搭建正文的,而不是西文的 10 pt。js 系 class 保留 LaTeX 标准 class 的操作感,只替换日文真正需要的部分——和文字体度量、字号的梯级,以及缩放这些字号的机制。ltjsclasses 把这套设计带到 LuaLaTeX,BXjscls 把它带到所有引擎。本页要讲的是这三个系谱各自解决了什么,以及该怎么选。
jsclasses 相对标准 class 改动的两件事
jsclasses 附带的手册把「与标准 document class 的差异」明确列为两点:和文字体度量和字号选项的处理方式。它并没有改写页边距或行距的理念,而是修好了排日文时真正坏掉的两个地方。第一,和文 TFM 不再使用旧的 min10、goth10,而是采用东京书籍印刷的 小林肇 制作的 JIS 字体度量 jis.tfm、jisg.tfm。第二,重做了字号选择:标准 class 只有 10pt、11pt、12pt 三档,而且用手册自己的话说,「除了标准的 10 磅之外,字体的平衡多少会走样」。
这两点其实同出一源。日文印刷用 级(Q,1 级 = 0.25 mm) 计量字号,正文常用 13 级即 3.25 mm。但 JIS 字体度量的全角原样是 13.527 级,所以 jsclasses 把和文字体缩放 0.961 倍(= 13 ÷ 13.527),让全角正好落在 13 级。手册把这个算式写得很清楚,并指出把 9.62216 pt 的度量再乘 0.961 之后,名义上的 10 磅正文其实「只有 9 磅出头」。这个比值保存在实数宏 \Cjascale 中,在 jsarticle、jsbook、jsreport 里是 0.924690(= 9.62216 pt × 0.961 ÷ 10 pt)。2018 年以后的 OTF 宏包会读取这个宏来对齐日文字号。
% upLaTeX: the dvipdfmx option is a global option for graphicx/hyperref
\documentclass[uplatex,dvipdfmx,a4paper,papersize]{jsarticle}
\begin{document}
こんにちは、\LaTeX!
\end{document}class 的阵容是 jsarticle(论文与报告)、jsbook(书籍)、jsreport(报告)三个,另外还捆绑了学会期刊用的 jspf 和纪要用的 kiyou。jsreport 是 2017 年 2 月经论坛讨论后,把原先用 jsbook 的 report 选项代替的用途独立出来的 class。这套 class 最初由奥村基于 LaTeX3 Project 的 classes.dtx 和 株式会社 ASCII 的 jclasses.dtx 编写;2009 年并入了 田中琢爾 的 upLaTeX 支持补丁,自 2016 年 7 月起由 Japanese TeX Development Community(GitHub 上的 texjporg/jsclasses)维护。它随 TeX Live 提供,无需另行安装。
| 选项 | 作用 |
|---|---|
a4paper / b5j / a4var | 纸张。ISO 的 a4paper、b5paper,JIS B 系的 b4j、b5j,以及变形开本 a4var(210×283 mm)、b5var(182×230 mm)。默认 a4paper |
papersize | 向 DVI 写入纸张尺寸的 \special。走 DVI 转 PDF 的路线时基本上是必需的 |
tombow / tombo / mentuke | 打印裁切标记。纸张四周各加 1 英寸的出血区,tombow 还会印上作业名和本次处理的日期时间 |
mingoth / jis | mingoth 把和文 TFM 退回旧的 min10、goth10;jis 在 pLaTeX 下显式选择 JIS 度量 |
disablejfam | 不把日文字体注册为数学字族;在数学字族用尽的文档中有用 |
openright / openleft / openany | 在 jsbook、jsreport 中决定章从哪一页开始;openleft 表示从左页开始 |
正文字号是怎么做出来的:\mag 与 nomag
jsclasses 先以 10 磅排正文,再用 TeX 的 primitive \mag 整体缩放文档以达到指定字号(11pt 为 1.095 倍,12pt 为 1.200 倍)。正因如此,它才能提供标准 class 没有的等比字号 8pt、9pt、14pt、17pt、20pt、21pt、25pt、30pt、36pt、43pt,以及按级指定的 12Q、14Q 和实际尺寸的 10ptj、10.5ptj、11ptj、12ptj。\mag 会把纸张、字形和线条一并放大,思路很有力;缺点是有些工具读不懂这个值,结果还取决于后续 dvipdfmx 或 dvips 如何处理。
| 选项 | 行为 |
|---|---|
usemag | 用 \mag 整体缩放文档的原始方式。jsclasses 的 默认值,也是 2016 年 7 月 8 日以前唯一的方式 |
nomag | 2016 年 7 月 8 日加入:不用 \mag,改为缩放版式中的各种尺寸 |
nomag* | 2016 年 7 月 24 日加入:在 nomag 基础上给 NFSS 打补丁,同时调整 optical size |
实际操作中,从默认的 usemag 开始就好。只有当 geometry、图像定位或 PDF 后处理出现真实的尺寸不符时,再尝试 nomag*。比起一开始就堆满所有选项,更该优先保证同样的步骤能得到同样的 PDF。另外,使用 \mag 的文档必须把「带放大率」这件事传达给下游每一个 DVI 工具,所以在协作中把缩放方式和构建步骤一起定下来,可以少出事故。
jsarticle 该用 pLaTeX 还是 upLaTeX
两者都可以,因为 class 会自己判定引擎。 只写 \documentclass{jsarticle} 并用 upLaTeX 处理时,日志会出现 Class jsarticle Info: Autodetected engine: upLaTeX,日文内部编码切换为 JY2/JT2;用 pLaTeX 则是 Autodetected engine: pLaTeX。即便如此,仍要在 class 选项里写 uplatex(或 platex、autodetect-engine),一是把意图留在原稿里,二是防止判定不一致时悄悄排出另一种版面。若指定与实际处理系不符,class 会直接停下:! Class jsarticle Error: Option 'platex' is specified but you are running upLaTeX.
而 dvipdfmx 根本不是 class 选项。jsclasses 不处理的指定会作为全局选项传给后续的宏包,graphicx、color、hyperref 读到它来选择驱动。因此只要在 \documentclass 的方括号里写一次,就不必在每个宏包上分别写——这就是常见写法 [uplatex,dvipdfmx] 的真相。
明明按 A5 排版,PDF 却出成 A4
如果写了 a5paper 而 PDF 却是 A4,原因不在 class,而在于 DVI 里没有写入纸张尺寸。在 TeX Live 2024 上,把 \documentclass[uplatex,a5paper]{jsarticle} 交给 dvipdfmx,得到的 PDF 是 595.28 × 841.89 pt,也就是 A4:DVI 文件本身没有纸张的概念,dvipdfmx 只好用自己的默认值。给 class 选项加上 papersize,就会写出 \special{papersize=...},同一份原稿随即输出为 419.53 × 595.28 pt 的 A5。若同时使用 tombow,纸张会因裁切标记而变大:A5 变成 563.53 × 739.28 pt,正好四边各加一英寸。LuaLaTeX(下一节的 ltjsclasses)直接写 PDF,不会遇到这个问题。
ltjsclasses — 移植到 LuaLaTeX 的 jsclasses
ltjsclasses 是把 jsclasses 改写为 LuaLaTeX(LuaTeX-ja) 使用的一组 class,由 LuaTeX-ja 项目维护。它提供 ltjsarticle、ltjsbook、ltjsreport(另有 ltjspf、ltjskiyou),正如名称所示与 jsclasses 一一对应。这里最大的差别在缩放方式。LuaTeX 官方手册明确写着 \mag 只在 DVI 输出模式下受支持,因此直接输出 PDF 的 LuaLaTeX 用不了它。于是 ltjsclasses 把 nomag* 设为默认;若指定 usemag,它会警告 This ltjsarticle cls does not support 'usemag' option, since LuaTeX does not support \mag in pdf output 并退回 nomag*。
与引擎相关的选项处理也变了。传入 uplatex 会报错(this class does not support 'uplatex' option),而 autodetect-engine 只是警告并被忽略——既然只有一种处理系,这样设计很自然。和文度量默认使用 LuaTeX-ja 的标准 jfm-ujis.lua;加上 ptexjis 选项则切换为 jsclasses 所用的同一 JIS 度量(jfm-jis.lua),mingoth 则切换为旧的 jfm-min.lua。要更换字体时配合 luatexja-fontspec,可以直接按名称指定系统里安装的 OpenType 字体。
% compile with lualatex; nomag* is already the default here
\documentclass[a4paper]{ltjsarticle}
\usepackage{luatexja-fontspec}
\setmainjfont{Noto Serif CJK JP}
\setsansjfont{Noto Sans CJK JP}
\begin{document}
こんにちは、\LaTeX!
\end{document}BXjscls — 同一份原稿在任意引擎上通过
BXjscls(八登崇之,通称 ZR)把 jsclasses 的设计扩展到可在任意引擎上使用,提供 bxjsarticle、bxjsbook、bxjsreport、bxjsslide。这里最容易一开始就弄错的是引擎的写法。引擎是裸的 class 选项,而不是 engine=——可写 lualatex、xelatex、pdflatex、platex、uplatex、latex、platex-ng,或用 autodetect-engine 自动判定。若写成 engine=lualatex,这个设定根本传不到,编译会以 ! Class bxjsarticle Error: An engine option must be explicitly given. 停下。
% the engine is a bare option; ja= picks the Japanese driver
\documentclass[lualatex,ja=standard,a5paper]{bxjsarticle}
\begin{document}
こんにちは、\LaTeX!
\end{document}
% same body, different engine: swap the first option only
% \documentclass[uplatex,ja=standard,dvipdfmx,a5paper]{bxjsarticle}第二个键是 ja=(旧称 jadriver),用来从 standard、minimal、modern、pandoc 中选择日文处理方式。真正的陷阱就在这里。省略 ja= 时,只有 (u)pLaTeX 会自动补上 standard,其他引擎都会退回 minimal,并给出警告 The option 'ja' is MISSING!! So 'ja=minimal' is assumed as fallback, but such implicit setting is now DEPRECATED!。反过来,一旦写了 ja=,就必须显式给出引擎选项。所以实用上唯一稳妥的写法,是把引擎和 ja= 永远成对写出。选择 ja=standard 时,class 会为当前引擎加载合适的日文宏包。
| 引擎选项 | ja=standard 下加载的日文处理 |
|---|---|
platex / uplatex | 直接使用 (u)pLaTeX 本身的日文功能;换字体用 pxchfon |
lualatex | luatexja;字体指定用 luatexja-fontspec / luatexja-preset |
xelatex | zxjatype(构建在 xeCJK 之上);字体用 zxjafont |
pdflatex / latex | bxcjkjatype(构建在 CJK 宏包之上);限制最多的路线 |
与尺寸有关的写法同时借鉴了 jsclasses 和 jlreq。西文基准字号是 base=(别名 fontsize=),日文是 jbase=(别名 jafontsize=),日文缩放比是 scale=(别名 jafontscale=),其默认值为 \jsScale = 0.924715(\Cjascale 指向同一个值)。版面既可用 textwidth=、number-of-lines=,也可用与 jlreq 相同拼写的 line_length=、number_of_lines=。缩放方式用 magstyle= 选择 usemag、nomag、nomag*;从 LuaTeX v0.87 起以及在 pTeX-ng 上,默认切换为 nomag*,此时指定 magstyle=usemag 会以 ! Class bxjsarticle Error: The engine does not support 'magstyle=usemag' 停下。
jsclasses、ltjsclasses、BXjscls 该选哪个
顺序是 先决定引擎,再选择与之匹配的 class。即使要的是同样的「jsarticle 风格」,处理系一变,class 名也随之改变。反过来,只换 class 而不动引擎,日文处理本身就会失效,版面随之崩坏。
- 使用 pLaTeX/upLaTeX 时用 jsclasses。 当既有资产或投稿规定已经限定处理系时,这是标准选择。可以从
\documentclass[uplatex,dvipdfmx,papersize]{jsarticle}出发。 - 以 LuaLaTeX 为主时用 ltjsclasses。 系统 OpenType 字体可直接使用,PDF 无需经过 DVI 就能写出;
nomag*是默认值,也不会丢失纸张尺寸。 - 不想固定引擎,或要把源文件分发给别人时用 BXjscls。 只改两处——引擎名和
ja=——同一份文件就能在 pdfLaTeX、XeLaTeX、LuaLaTeX、(u)pLaTeX 之间移动。 - 想用数值指定版面时用 jlreq。 它与 js 系是不同谱系,可以依据规范设计每行字数、行数和边距。
在日志中确认处理路线
js 系里引擎和 class 是成对确定的,因此只看 .log 开头就能知道文档是否按预期的路线排出。在协作或 CI 中,要确认的不是「生成了 PDF」,而是 PDF 是通过指定路线生成的。理想状态是构建命令、\documentclass 那一行和 README 三者指向同一个名字。
| class | 在日志中确认什么 |
|---|---|
jsarticle | Autodetected engine: 那一行是 pLaTeX 还是 upLaTeX;若加了 papersize,还要量一下 PDF 的纸张尺寸 |
ltjsarticle | 是否加载了 luatexja、字体设置是否生效,以及有没有出现 usemag 警告 |
bxjsarticle | 引擎选项和 ja= 是否都写了;若出现 ja 缺失警告,就补上 |