2019年12月12日

クラスファイルを作ろう (1)

和文用LaTeXのクラスファイルを作る,ということをしてみる.汎用的なものではなく,目的を絞ったものにする.基本的にはpLaTeX用(正確にはepTeX上のpLaTeX)だが,upLaTeX/LuaTeX-ja相手にはその都度差分について述べる.前提知識として,LaTeXの基本的な文書作成と,TeXによるマクロ,ボックス,各種レジスタおよびLaTeXによるカウンタあたりは知っていると仮定する.気がする.

新しいプリミティブなどを躊躇せず使うことにします.従って古いTeXでは動かない可能性があります.

何を見るべきか

標準クラスファイルが参考になります.とりあえずjarticle.clsあたりをみればよいでしょう.ソースファイルの解説はjclasses.dtxをplatexで処理すれば出てきます.これはtexmf-dist/source/platex/base以下にあります.jsclasses.pdfの説明はもう少し丁寧だったりします.が,独自の処理も多いので参考にするのはほどほどに.なお,欧文クラスファイルについてはtexdoc classesで出てくるPDFファイルにソースファイルの解説があります.

ちなみに以下で出てくる例の設定量の大半はjsarticleのものです.

クラスファイルの情報

まずはクラスファイルの情報に関する宣言を行います.

\NeedsTeXFormat{pLaTeX2e}
\ProvidesClass{myclass}[2018/01/01 myclass]

\NeedsTeXFormatで,対応するフォーマットの指定を行います.pLaTeXやupLaTeXの場合はpLaTeX2eを,LuaTeX-jaでも使いたい場合はLaTeX2eとすればよいでしょう.さらに\NeedsTeXFormat{pLaTeX2e}[2018/01/01]のようにオプションで日付を与えることで,例えばこの場合は「2018年1月1日以降にリリースされたpLaTeX2e」を要求することもできます.

\ProvidesClass{<クラス名>}[<年>/<月>/<日> <情報>]がクラスファイルの情報です.オプションは最初は日付で必須,その後は割と自由で,バージョン情報や作者,簡単な説明などがあるようです.ここでは簡単にクラス名のみにしてみました.

クラスファイルの文字コードの宣言

クラスファイル内で使う文字コードを指定します.以下はUTF-8でクラスファイルを作成する場合の例です.

\epTeXinputencoding utf8

sjisやeucも指定できます.または,ISO-2022-JP(JIS)で作成しておけば,この指定なしに常に正しく処理されます.

LuaTeX-jaの場合はUTF-8しか使えません.特に,\epTeXinputencodingによる文字コードの指定は不要(行うとエラー)です.

オプション処理

\documentclassに与えられたオプションを処理します.標準クラスファイルのような汎用的なものはここでの処理が大きくなりますが,今回は汎用的なものを作るわけではないので,あまり必要ないでしょう.draft / finalのみサポートすることにします.

\DeclareOption{draft}{\setlength\overfullrule{5pt}}
\DeclareOption{final}{\setlength\overfullrule{0pt}}

\DeclareOption{<オプション名>}{<処理>}でオプションの宣言ができます.draftオプションを入れてOverfullした時に出るあの黒四角の幅を設定しています.終えたらデフォルトのオプションを実行し,オプションの処理を宣言します.

\ExecuteOption{final}% デフォルトはfinalオプション
\ProcessOptions\relax

和文フォントの設定

JFMとフォント拡大率の設定

クラスファイルにおける和文フォントの設定では,

  • JFMの設定
  • フォント拡大率の設定
を行います.

NFSS(New Font Selection Scheme)におけるフォント管理を簡単に復習しておきましょう.NFSSでは,フォントを「エンコーディング」「ファミリー」「シリーズ」「シェイプ」「サイズ」の五つで管理します.ただしサイズはやや別扱いされますが.例えばpLaTeX横書きでの本文中のフォントは「エンコーディングJY1」「ファミリーmc」「シリーズm」「シェイプn」となります.(もちろん設定によりますが.)これを単にJY1/mc/m/nと書きます.内部で使われる命令名でもあります.

現在の和文フォントのファミリーを変更するには,\kanjifamily{gt}のようにします.ただし,変更を有効にするために,\selectfontの呼び出しが必要です.例えば以下のようにすることで文字が明朝からゴシックになります.(ゴシックに対応するファミリ名は\gtdefaultに入っています.)

\kanjifamily{\gtdefault}\selectfont あいうえお% あいうえおはゴシックになる
同様にシリーズの変更は\kanjiseries,シェイプの変更は\kanjishapeを使います.

四つの属性が指定された時のフォントの設定は

\DeclareFontShape{<エンコーディング>}{<ファミリー>}{<シリーズ>}{<シェイプ>}{<->s*[<フォントの拡大率>]<JFM名>}{}
により行います.

もちろんpLaTeX自身がフォント設定を行っていますので,この設定は必須というわけではありません.が,pLaTeXのデフォルトJFMは(悪名高い)min10ですので,jisへと変更しておきましょう.また,フォントの拡大率を(jsarticleにならい)0.961倍にすることにします.

\DeclareFontShape{JY1}{mc}{m}{n}{<->s*[0.961] jis}{}% 明朝
\DeclareFontShape{JY1}{gt}{m}{n}{<->s*[0.961] jisg}{}% ゴシック

なお,jisメトリックは,(歴史的な事情により)そのフォントサイズが0.962216倍されています.従って,上記設定による実際の和文フォントサイズは約0.925倍ということになります.逆に,フォントサイズを1倍にしたい場合には1/0.962216倍,つまり約1.039倍すればよいことになります.

\DeclareFontShape{JY1}{mc}{m}{n}{<->s*[1.039] jis}{}
\DeclareFontShape{JY1}{gt}{m}{n}{<->s*[1.039] jisg}{}

通常のpLaTeXでは「明朝」と「ゴシック」の二書体のみですので,ここではその二つの設定のみをします.新たにJFMを用意し,新しいファミリーなどを導入して設定を行えば,さらに多くの書体を扱う,いわゆる多書体を実現することができます.ただし,dviドライバの設定が必要になるでしょう.これ以上は踏み込まないことにします.

縦書きフォントのファミリーはJT1ですので,同様にして縦書き時の和文フォントも設定できます.ただし,“標準的な”FMはデフォルトのtmin10およびtgoth10のみのようですので,ここでは設定しないことにします.

他属性のエイリアス

その他の属性(特にシリーズとシェイプが異なるフォント)に対しても同様に設定をすることもできますが,既に設定した明朝体/ゴシックで代替することもできます.例えば,JY1/mc/m/itの設定をJY1/mc/m/nのそれ(上記で設定した明朝体)と同様にするには

\DeclareFontShape{JY1}{mc}{m}{it}{<->ssub*mc/m/n}{}
とします.なお,同様の設定がある程度pLaTeXでなされているためしなくても不都合が起こらないこともあります.

他のJFM

OTFパッケージやjlreqクラスにはJFMが付属していますので,そのJFMを利用することも可能です.これらは縦書き用のJFMも含んでいます.また,上記のjisと違い,文字幅は1倍としてデザインされています.または,otfパッケージを直接読み込んでもよいかもしれません.

upLaTeXの場合

エンコーディングは横書きがJY2,縦書きがJT2です.標準のJFMも改善されており,特に文字幅が1倍になっています.ただし,標準の設定では(\DeclareFontShapeを使って)0.962216倍されています.jis / jisgに対応するJFMとして,ujis / ujisgが用意されています.これらも文字幅は1倍です.

LuaTeX-jaの場合

エンコーディングは横書きがJY3,縦書きがJT3です.LuaTeX-jaの場合は,フォントサイズとJFMの他,実フォントも指定できます.

\DeclareFontShape{<エンコーディング>}{<ファミリ>}{<シリーズ>}{<シェイプ>}{<->s*[<欧文に対するスケール値>]<実フォント名>:jfm=<JFM名>;<その他フォント属性>}{}

細かくは述べませんが

  • デフォルトの実フォント名は\ltj@stdmcfont(明朝),\ltj@stdgtfont(ゴシック)に入っています.多くの場合はIPAexです.
  • <その他フォント属性>の一例として,実フォントのカーニング情報を使わないようにするには,-kernを指定します.
\DeclareFontShape{JY3}{mc}{m}{n}{<->s*[0.9622]\ltj@stdmcfont:jfm=jis;-kern}{}
\DeclareFontShape{JY3}{gt}{m}{n}{<->s*[0.9622]\ltj@stdgtfont:jfm=jis;-kern}{}

(u)pLaTeXの場合は異なるフォントには異なるJFMを指定する必要がありましたが,LuaTeX-jaの場合は実フォントで認識されるので,JFMは同じものを使うことができます.

さらなる使い方

\DeclareFontShapeやNFSSに関するさらなる情報は,texdoc fntguideで表示されるドキュメントから得ることができます.

欧文フォントの設定

欧文フォントも\DeclareFontShapeなどを使い設定することが可能です.ただし,通常既存パッケージを読み込めば十分で,無理に行う必要はないかと思います.lmodernパッケージを読み込んでおくだけにしておきましょう.

\RequirePackage{lmodern}

和文ファミリと欧文ファミリの連動

欧文にサンセリフが指定された時に,和文がゴシックになると便利かもしれません.このためには,\sffamilyを書き換えて和文のファミリも同時に変更されるようにします.

\DeclareRobustCommand\sffamily{%
  \not@math@alphabet\sffamily\mathsf
  \romanfamily\sfdefault
  \kanjifamily{\gtdefault}% 追加
  \selectfont
}

同様に\rmfamilyで明朝体に,\ttfamilyでゴシックになるようにします.

\DeclareRobustCommand\rmfamily{%
  \not@math@alphabet\rmfamily\mathrm
  \romanfamily\rmdefault
  \kanjifamily{\mcdefault}%
  \selectfont
}
\DeclareRobustCommand\ttfamily{%
  \not@math@alphabet\ttfamily\mathtt
  \romanfamily\ttdefault
  \kanjifamily{\gtdefault}%
  \selectfont
}

ちなみに\kanjifamily\gtdefaultでも問題ありません.

段落行頭グルーの抑制

JFMによるグルーは段落先頭にも入ります.特に,“「”のような括弧類の前には伸縮可能なグルーが入ります.そのため,行頭の括弧がそろわないことがあります.これを防ぐためには,\everyparトークンに\inhibitglueを設定すれば良いでしょう.ただし,\everyparトークンの直接書き換えはLaTeXの内部処理と衝突するので,everyhookパッケージを使うことにします.

\RequirePackage{everyhook}
\PushPostHook{par}{\inhibitglue}

なお,この影響で段落行頭の括弧は(全角二分ではなく)全角下がりになります.(ただし,もともと折り返し行の行頭の括弧天付きでしたから,こちらの方が整合的な挙動ですが.)

  • 元々の挙動(段落行頭は全角二分下がり,折り返し行頭は天付き)にするには,\futureletあたりで行頭が括弧であるか判定し,二分の空きを入れる処理を入れます.
  • 更に折り返し行頭を二分下がりとするには,括弧の幅を一文字分としたJFMを作る必要があります*1
LuaTeX-jaの場合

LuaTeX-jaについては強化されたJFMを使うことで,最初からこのグルーが入りません.従ってここでの対処は不要ですが,enumerate環境などで使われている\list内ではやはりグルーが挿入されてしまいます.これはLaTeXにより\itemの後が行頭ではないとされてしまっているためです.このために,改めて行頭であると見なさせる\ltjfakeparbeginを実行しておくことにします.

\RequirePackage{everyhook}
\PushPostHook{par}{\ltjfakeparbegin}

あれ,LuaTeX-jaの方が「強い」はずなのにコードの文字数が多い……

*1
jlreqにはそのようなJFMが含まれています.

0 件のコメント:

コメントを投稿

コメントの追加にはサードパーティーCookieの許可が必要です