日本語組版の方法

LaTeX で日本語組版をやろうとすると、最初に決めなければならないのは「どの経路を通るか」です。いま生きている道は三本——upLaTeX + dvipdfmxLuaLaTeX + LuaTeX-jaXeLaTeX + zxjatype。同じ .tex が三本とも通り、三本とも同じ本文フォントを PDF に埋め込みます。違うのは速さと、使えるパッケージと、事故の起きる場所です。このページでは TeX Live 2024 で実際に三経路をコンパイルして測った数字をもとに、経路と文書クラスの選び方を決め切ります。

日本語 LaTeX の三経路 — 何がどこに置かれているか

三経路の本当の違いは、日本語組版の知識がシステムのどの層に置かれているか です。upLaTeX では知識がエンジンの中にあります——縦組も禁則も文字間のグルーも C で書かれた組版器の一部で、だから速い。LuaLaTeX では知識が Lua のコールバックにあり、LuaTeX が組んだノードの列を LuaTeX-ja が走査して和文の規則を適用します——だから遅く、そのぶん書き換えやすい。XeLaTeX では知識が zxjatype(内部で xeCJK を使う)というマクロパッケージにあり、これは日本語専用というより CJK 全般の仕組みを日本語向けに調整したものです。出力の作り方も違い、upLaTeX だけが DVI を経由して dvipdfmx で PDF にします。残り二つは PDF を直接吐きます。

経路エンジン出力和文フォント
uplatex + dvipdfmxe-upTeX(pTeX 系)DVI → PDFTFM/VF 経由。埋め込みは dvipdfmx が担当
lualatex + luatexjaLuaTeXPDF 直接OpenType を直接。\setmainjfont で指定
xelatex + zxjatypeXeTeXXDV → PDF(xdvipdfmx)OS のフォントも可。zxjafont が定番

この表の右下に、日本語 TeX の歴史がひとつ隠れています。dvipdfmx は Mark A. Wicks の dvipdfm を多バイト・CID 対応に拡張したもの——つまり日本語のために生まれた道具です。ところが XeTeX が自分の出力段としてこれを採用し、xdvipdfmx になりました。TeX Live 2024 の実際のインストールを見ると、dvipdfmxxdvipdfmx への シンボリックリンク です。日本語の都合で作られた変換器が、いまや日本語と無関係な XeTeX 文書すべての最終工程を担っている、というわけです。

どれくらい速さが違うのか — 同じ原稿を三経路で測る

同じ 10 ページの和文原稿を TeX Live 2024 でコンパイルすると、uplatexdvipdfmx0.31 秒lualatexltjsarticle)が 0.59 秒xelatexbxjsarticlezxjatype)が 0.74 秒 でした。おおむね 1 : 1.9 : 2.4 で、この比は 1 ページでもほぼ同じです——差の大半は起動と組版そのものであって、原稿の長さではありません。0.3 秒と 0.6 秒の差は一回なら誰も気にしませんが、latexmk -pvc で保存のたびに走らせる書き方をしていると、体感として効いてきます。逆に言えば、それが pLaTeX 経路が二十年以上たっても消えない理由でもあります。生成された PDF はどれも同じ Harano Aji Mincho をサブセット埋め込みしており、pdftotext で本文を取り出すと三つとも正しい日本語が返ってきます。つまり「速い経路は品質が低い」ということはありません。

terminal
# route 1 -- fastest; DVI in between
uplatex main.tex && dvipdfmx main.dvi
ptex2pdf -l -u main            # the same two steps in one command

# route 2 -- LuaTeX-ja, PDF straight out
lualatex main.tex

# route 3 -- XeTeX via zxjatype
xelatex main.tex

文書クラスの選び方 — jsclasses・jlreq・ltjsclasses・bxjscls

経路を決めたら、対応する文書クラスはほぼ自動的に決まります。upLaTeX なら jsarticlejsclasses)か jlreq、LuaLaTeX なら ltjsarticleltjsclasses)か jlreq、XeLaTeX なら bxjsarticlebxjscls)。ただし例外がひとつ——jlreq は pLaTeX・upLaTeX・LuaLaTeX の三つに対応しますが、XeLaTeX には対応しません。実際に xelatex\documentclass{jlreq} を通すと ! Undefined control sequence. が出て、そのまま ! LaTeX Error: Missing \begin{document}. まで転がり落ちます。「クラスを固定しておけばエンジンを乗り換えられる」というのは正しいのですが、その乗り換え先に XeLaTeX は含まれません。

クラス通るエンジン素性
jsarticlepLaTeX / upLaTeX奥村晴彦氏の jsclasses(書籍は jsbook)。事実上の標準で、既存資産が最も多い
jlreqpLaTeX / upLaTeX / LuaLaTeXW3C の JLReq に沿った設計。縦組は tate オプション一つ
ltjsarticleLuaLaTeX のみjsclasses を LuaTeX-ja へ移植したもの。移行の互換性が高い
bxjsarticlepdfLaTeX / XeLaTeX / LuaLaTeX / (u)pLaTeXbxjscls。エンジンをまたぐ薄い共通層で、XeLaTeX 経路の入口

クラス選びで一度は驚かされるのが、同じ 10pt が同じ大きさを意味しない ことです。jsarticle を 10pt で組んで漢字一文字の幅を測ると 9.24683pt しかありません。クラスファイルに \def\Cjascale{0.924690} と書かれていて、和文フォントを欧文の 0.924690 倍で読み込んでいるからです。同じことを jlreq でやると、漢字はきっかり 10pt。つまり jsarticle から jlreq にクラスを差し替えると、行長も一行の字数も版面も変わります。移行するときは「同じ設定のまま比べる」のではなく、版面を組み直すつもりでいてください。

latex
% route 1: uplatex main.tex && dvipdfmx main.dvi
\documentclass[uplatex,dvipdfmx]{jsarticle}
\begin{document}
日本語と English を混ぜた段落です。約物(かっこ)も混じります。
\end{document}
latex
% route 2: lualatex main.tex
\documentclass{ltjsarticle}
\usepackage{luatexja-fontspec}
\setmainjfont{Harano Aji Mincho}
\setsansjfont{Harano Aji Gothic}
\begin{document}
日本語と English を混ぜた段落です。約物(かっこ)も混じります。
\end{document}

pLaTeX 経路で使えなくなるパッケージ — fontspec・unicode-math・microtype

速い代わりに、pLaTeX 経路では OpenType を前提とする現代のパッケージ群がまとめて使えません\usepackage{fontspec}! Fatal Package fontspec Error: The fontspec package requires either XeTeX or (続いて LuaTeX)で止まり、unicode-math! Package unicode-math Error: Cannot be run with uptex! を出します。厄介なのは microtype で、これは エラーにならず、ログに Package microtype Warning: You don't seem to be using pdftex, luatex or xetex. と出したまま黙って何もしません。読み込んだのに効いていない、という一番気づきにくい壊れ方です。逆に graphicxhyperreftikz はドライバさえ合っていれば普通に動くので、「昔のパッケージしか使えない」という話ではありません。境界は OpenType とマイクロタイポグラフィのところに引かれています。

しおりが文字化けする — hyperref と pxjahyper

(u)pLaTeX + hyperref で日本語の見出しを書くと、PDF のしおり(ブックマーク)だけが文字化けします。本文は正しいのに、目次パネルの文字が崩れる。原因は、hyperref が見出しの UTF-8 バイト列をそのまま UTF-16BE に流し込んでしまうことです。実際に生成される .out を覗くと \376\377\000\346\000\227\000\245… のように、1 バイトごとにヌルが挟まった列になっています。\usepackage{pxjahyper} を足すと同じ見出しが \376\377\145\345\147\054\212\236…——0x65E5 0x672C 0x8A9E すなわち「日本語」——になります。(u)pLaTeX で hyperref を使うなら pxjahyper はほぼ必須 と覚えてください。LuaLaTeX + LuaTeX-ja では素の hyperref だけで正しい UTF-16BE が出るので、この一手間は要りません。

latex
% (u)pLaTeX: load pxjahyper AFTER hyperref, or the outline panel is garbage
\documentclass[uplatex,dvipdfmx]{jsarticle}
\usepackage{hyperref}
\usepackage{pxjahyper}
\begin{document}
\section{日本語の見出し}
本文。
\end{document}

結局どれを選ぶか

新しく書き始めるなら LuaLaTeX + LuaTeX-ja(ltjsarticlejlreq)を選んでください。0.3 秒ぶんの遅さと引き換えに、Unicode がそのまま通り、OS のフォントが使え、fontspecunicode-mathmicrotype も動き、しおりも黙って正しく出ます。既存の卒論テンプレートや学会のスタイルファイルが jsclasses 前提で配られている場合、あるいはビルド時間が本当に効く反復作業なら、upLaTeX + dvipdfmx のままでかまいません——古い道ではなく、いまも最速の道です。XeLaTeX + zxjatype を選ぶのは、すでに XeLaTeX の資産があってそこに日本語を足したいときで、日本語だけのために新規に選ぶ理由はあまりありません。無印の platex を新規に選ぶ理由はもう無く、uplatex にしておけば扱える文字の範囲が広がります(この違いは「文字コードと改行」で扱います)。

  • 新規・研究室の縛りなしlualatexltjsarticle(または jlreq)。Unicode・OS フォント・microtype が全部使える。
  • 既存テンプレートが jsclasses 前提/ビルドが速い方がいいuplatexdvipdfmxptex2pdf -l -u で 1 コマンドにできる。
  • すでに XeLaTeX の文書があるbxjsarticlezxjatypezxjafontjlreq は XeLaTeX では動かない。
  • (u)pLaTeX で hyperref を使うなら pxjahyper を必ず読み込む。 しおりだけが化けるという症状はほぼこれ。
  • microtype は (u)pLaTeX では警告だけ出して無効。 効かせたいなら Lua か Xe の経路へ。