h20y6m.github.io

2023年12月02日

和文VFで異体字する話

これは「TeX & LaTeX Advent Calendar 2023」の2日目の記事です。
(1日目は zr_tex8r さん、3日目は uwabami さんです。)

この記事ではカスタム和文VFを作成して異体字を出力する方法を紹介します。

この記事では前提として最新のTeX Live 2023を利用し、upLaTeXとDVIPDFMxでPDFを作成していることを想定しています。

upLaTeXで異体字する話

古い作品をupLaTeXで再現しようとしたとき、字体もなるべく似せようと異体字を使いたくなることがみなさんもよくあるかと思います。例えば、以下の日本語LaTeXユーザーにはおなじみの作品

では「名前」の「前」の「月」部分が横棒ではなく点になっています。また「記憶」の「記」の旁も見慣れたものとは少し違っていますね。

(まぁ、この作品の組版をupLaTeXで再現しようとすると異体字よりももっと大変そうなことがあるわけですが……)

Adobe-Japan1

使いたい異体字がAdobe-Japan1に含まれている場合は、otfパッケージ\CID命令を使用して簡単に出力できます。otfパッケージはTeX Liveに含まれていて、さらにTeX Live 2020以降はAdobe-Japan1の全漢字を収録した原ノ味フォントがデフォルトの和文フォントになっているため、最新のTeX Liveをインストールするだけで最初から使える状態になっています。

\CID命令を使うためには、当然ながら異体字のCIDを探す必要があります。例えば、以下のWebページで「前」を検索すると「月」の横棒が点になっている異体字がCID+13889だとわかります。

IPAmj明朝フォント

Adobe-Japan1の異体字では足りない場合は、IPAmj明朝フォントの異体字を使う方法があります。ipamjmパッケージ\MJMZM命令を使うと、upLaTeXでIPAmj明朝フォントの異体字を使うことができます。TeX Liveには含まれていないため、自分でインストールする必要があったり、明朝体1ウェイトだけでゴシック体などはありませんが、たくさんの異体字が使えるようになります。

なお、ipamjmパッケージ(2020/01/09 v0.5)はLaTeX 2021-06-01以降のバージョンでは動かないため修正するパッチを作ってみました。

\MJMZM命令を使うためには、MJ文字図形名の番号部分を知る必要があります。以下のWebサイトで検索することができます。例えば、「記」を検索すると目的の異体字がMJ024358だとわかります。

なお、IPAmj明朝の異体字(UCS符号に対するデフォルトグリフではないグリフ)をdvipdfmxで使用すると、該当の文字がPDFのToUnicode CMapに入りません。このためPDF上で該当の文字をコピーしたり検索したりすることができません。また、IPAmj明朝で使用している文字が全てこのような文字だった場合は、

dvipdfmx:warning: Creating ToUnicode CMap failed for "ipamjm.ttf"
dvipdfmx:warning: Failed to load ToUnicode CMap for font "ipamjm.ttf"

のような警告がでてPDFにToUnicode CMapそのものが埋め込まれません。PDF/Aのような規格ではToUnicode CMapの埋め込みが必須になっていたりしますので、ipamjmパッケージを使用するとこのような規格に準拠できなくなる可能性があるので注意してください。

otfパッケージとipamjmパッケージで異体字するサンプル

otfパッケージとipamjmパッケージで先ほどの『吾輩ハ猫デアル』を組んでみます。文書クラスとしてjlreqクラスを使いたいと思うのでotfパッケージを直接使わずにjlreq-deluxeパッケージを使い、ipamjmパッケージにscaleオプションを付けます。(a6paperlandscapeは紙面の都合です。)

\documentclass[uplatex,dvipdfmx,a6paper,tate,landscape]{jlreq}
\usepackage{bxpapersize}
\usepackage{jlreq-deluxe}
\usepackage[scale=1]{ipamjm}
\begin{document}
吾輩は猫である。名\CID{13889}はまだ無い。

どこで生まれたのか頓と見當がつかぬ。
何ても\CID{13638}\CID{13977}いじめじめした\CID{13826}で
ニャー〳〵泣いて居た事\CID{13463}は\MJMZM{24358}\MJMZM{11957}している。
\end{document}

結果は以下のようになります。

吾輩は猫である

和文VFで異体字する話

前述のような方法で異体字を使うことができますが、異体字が増えてくると、

などいろいろつらくなってきます。

そこで独自の和文VF(Virtual Font)を作ってソースコードではフツーの文字を入力しても、生成されるPDFでは異体字が出力されるようにしてみたいと思います。

和文VFのカスタマイズについては以下のWebページに詳しい解説があります。

先きほどのサンプルではjlreq-deluxeパッケージを使用しているため、本文の和文フォントはjlreq--upnmlminrn-vです。上記のページではZVP形式を使っていますが、jlreq-deluxeの和文VFはZVP形式では扱えないため、ZVP0形式を使うことにします。今回はwagahai-minr-vという名前で和文フォントを作成することにします。「minr」は明朝Regular、「v」は縦組み用を表します。

ZVP形式ではVFに対応するJFMも一緒に扱えますが、ZVP0形式はそうではないため、JFMは別に準備する必要があります。JFMは元のJFMと全く同じもので良いため、単純にコピーするだけです。

$ cp $TEXMFDIST/fonts/tfm/public/jlreq-deluxe/jlreq--upnmlminrn-v.tfm wagahai-minr-v.tfm

元になるjlreq--upnmlminrn-vのVFをjfmutilでZVP0形式に変換し名前をwagahai-minr-v.zvp0に変更します。

$ jfmutil vf2zvp0 jlreq--upnmlminrn-v
$ mv jlreq--upnmlminrn-v.zvp0 wagahai-minr-v.zvp0

wagahai-minr-v.zvp0を編集していきます。まず、Adobe-Japan1の異体字を使いたいため、otfパッケージの\CID命令用のフォントotf-cjmr-vを追加します。「mr」は明朝Regular、「v」は縦組み用を表します。

(実際には\CID命令はotf-cjmr-vを直接使うのではなく分割・コード変換をしたVFを経由しています。文字コードをpTeXが扱えるJIS漢字の範囲に収めるための工夫のようです。)

jlreq--upnmlminrn-vはフォントを1つしか使っていないため、フォント番号1にotf-cjmr-vを割り当てることにします。他のMAPFONTの続きに以下を追記します。

(MAPFONT D 1
   (FONTNAME otf-cjmr-v)
   (FONTCHECKSUM O 0)
   (FONTAT R 1.0)
   (FONTDSIZE R 10.0)
   )

異体字にしたい文字ごとにCHARACTERを定義していきます。CHARACTERは文字コード順になるようにします。例えば「前」(U+524D)をCID+13889(16進で3641)をマップするには以下のような定義を書きます。(ZVP形式の場合はCHARWDは省略できます。)

(CHARACTER H 524D
   (CHARWD R 1.0)
   (MAP
      (SELECTFONT D 1)
      (SETCHAR H 3641)
      )
   )

次にIPAmj明朝の異体字を使えるようにしていきます。IPAmj明朝ではAdobe-Japan1フォントでCIDを指定するようにMJ番号で指定することができません。GIDに変換してやる必要があります。もちろんipamjmパッケージはMJ番号からIPAmj明朝フォントのGIDに変換しているのですが、そのためのVFはpTeXのサポートするJIS漢字コードの範囲に収めるために分割されていたり、文字コード変換をしていたりしてややこしくなっています。

そこで今回はMJ番号からIPAmj明朝のGIDに変換するVFを作成するためのスクリプトを作成し、このスクリプトで作ったipamjmm--vを使うことにします。

ipamjmm--vをフォント番号2で追加します。

(MAPFONT D 2
   (FONTNAME ipamjmm--v)
   (FONTCHECKSUM O 0)
   (FONTAT R 1.0)
   (FONTDSIZE R 10.0)
   )

例えば「記」(U+8A18)をMJ024358(16進で5F26)にマップするには以下のような定義を書きます。

(CHARACTER H 8A18
   (CHARWD R 1.0)
   (MAP
      (SELECTFONT D 2)
      (SETCHAR H 5F26)
      )
   )

ZVP0ファイルの編集が終わったらjfmutilのzvp02vfコマンドでVFに変換します。

$ jfmutil zvp02vf wagahai-minr-v

VFで異体字するサンプル

作成したVFで『吾輩ハ猫デアル』を組んでみます。

\documentclass[uplatex,dvipdfmx,a6paper,tate,landscape]{jlreq}
\usepackage{bxpapersize}
\usepackage{jlreq-deluxe}
\makeatletter
\expandafter\let\csname JT2/hmc/m/n/10\endcsname\relax
\DeclareFontShape{JT2}{hmc}{m}{n}{<->s*[1]wagahai-minr-v}{}
\makeatother
\begin{document}
吾輩は猫である。名前はまだ無い。

どこで生まれたのか頓と見當がつかぬ。
何ても暗薄いじめじめした所で
ニャー〳〵泣いて居た事丈は記憶している。
\end{document}

結果は先ほどのサンプルと同じになるはずです。

LuaLaTeXで幸せになる?

この記事で登場したAdobe-Japan1やIPAmj明朝フォントに収録されているMoji_Johoの異体字は国際的なデータベースのUnicode IVDに登録されており、UnicodeのIVSという仕組みを使って表現することができます。

LuaLaTeXはこのIVSに対応しているためフォントがサポートしていれば特別な命令を使うことなく異体字を利用できます。LuaTeX-jaのデフォルトの和文フォントはAdobe-Japan1の漢字を全てサポートしている原ノ味フォントですから、デフォルトの状態でAdobe-Japan1の異体字を全て使うことができます。例えば、Adobe-Japan1のCID+13889の「前」はIVSを使って「前󠄁」(U+524D U+E0101)と表現できます。

一方MJの異体字は原ノ味フォントではサポートされていないのでそのままでは使えませんが、LuaLaTeXでは簡単にフォントを変更できるのでその部分だけフォントをIPAmj明朝に切り替えることで簡単にMJの異体字を使うことができます。(もしかしたら、“最強”のLuaLaTeXならその部分だけ自動的にフォントを変更する方法があるかもしれません。)

\documentclass[lualatex,a6paper,tate,landscape]{jlreq}
\usepackage{luatexja-fontspec}
\newjfontfamily{\ipamjmfamily}[
  YokoFeatures={JFM=jlreq},
  TateFeatures={JFM=jlreqv},
]{IPAmjMincho}
\NewDocumentCommand \MJ { m } {{\ipamjmfamily #1}}
\begin{document}
吾輩は猫である。名前󠄁はまだ無い。

どこで生まれたのか頓と見當がつかぬ。
何ても暗󠄁薄󠄁いじめじめした所󠄁で
ニャー〳〵泣いて居た事丈󠄁は\MJ{記󠄂憶󠄂}している。
\end{document}

こちらも最初のサンプルとほぼ同じになるはずです。

ただし、出力されたPDFではIVSを使った文字部分の文字がToUnicode CMapでU+FFFDにマップされてしまい、文字のコピーや検索ができなくなってしまうようです……(ちょっとざんねん……)

まとめ

カスタム和文VFを作成して生成されるPDFの文字を自動的に異体字にすることができます。

また、LuaLaTeXならIVSが使えるのでIVSをサポートしているフォントを利用すれば簡単に異体字を使うことができます。

というわけで、みなさんカスタム和文VFを作ってLuaLaTeXで幸せになりましょう!