TeX2img (Windows/Mac) の動作の詳細
重要:以下の内容は古くなっています!(2015-03-26)
この記事は Windows 版 1.4.0 と Mac 版 1.8.8 に対応した内容であるが、念のためアーカイブとして残しておく。最新記事はこちら。
【最終更新:2015-02-23】この記事は TeX2img の画像変換処理の解説であり、画像変換スキームについては Windows 版 1.2.5 以降と Mac 版 1.8.3 以降において有効である。コンパイル回数推定機能については Windows 版 1.3.0 以降と Mac 版 1.8.6 以降で有効である。
TeX2img による画像変換処理
TeX2img Windows 版 1.2.5 と Mac 版 1.8.3 は、Ghostscript の仕様変更に対応すべくリリースされた*1。このリリースでは全体的に画像変換工程における内部処理を見直したため、その詳細を解説する。類似の画像変換スクリプトを自前で作成したい場合にも、本記事の内容が役に立つはずである。
元々 TeX2img の Win/Mac 両バージョンは、寺田さんによって開発された当初から異なるワークフローを用いていた。このうち Windows 版が阿部さんによって引き継がれ、さらにカスタマイズが行われた。したがって、両バージョンは(ユーザが同じように処理したつもりでも)出力結果が微妙に異なる。そこで、これは個別に説明する必要がある。
TeX2img Windows 版の変換方式
Windows 版は以下のように処理する。
【アウトライン化 PDF 出力の場合】
TeX →…→ PDF →[gs (eps(2)write)でアウトライン化+クロップ]→
EPS →[BB情報を編集して余白付与]→[gs (pdfwrite)]→ PDF
eps(2)write はデフォルトでは -r20016 固定で解像度調節は無効だが、基本設定で「低解像度での処理を行う」を ON にすると解像度調節が有効になり、-r オプションの値は 解像度レベル×72 となる。
【アウトライン化 EPS 出力の場合】
TeX →…→ PDF →[gs (eps(2)write)でアウトライン化+クロップ]→
EPS →[BB情報を編集して余白付与]→ EPS
eps(2)write はデフォルトでは -r20016 固定で解像度調節は無効だが、基本設定で「低解像度での処理を行う」を ON にすると解像度調節が有効になり、-r オプションの値は 解像度レベル×72 となる。
【JPEG/PNG 出力の場合】
TeX →…→ PDF →[gs (eps(2)write)でアウトライン化+クロップ]→
EPS →[BB情報を編集して余白付与]→[gs (jpeg/pngalpha)]→ JPEG/PNG
eps(2)write の -r オプションの値は 解像度レベル×72 となる。余白付与は EPS ソースの BoundingBox 情報の編集によって行うが、余白の単位はデフォルトでは px であり、ピクセル単位で (指定された余白) 分に対応する余白を付加する。単位を bp に指定すると PDF/EPS と同じ処理により BoundingBox 情報の編集を行うため、結果としてはピクセル単位で (指定された余白)*(解像度レベル) 分に対応する余白を付加したことになる*2。
【JPEG/PNG 出力の場合(ImageMagick 使用)】
TeX →…→ PDF →[gs (eps(2)write)でアウトライン化+クロップ]→
EPS →[ImageMagick (convert)]→[ImageMagickで余白付与]→ JPEG/PNG
オプションでインストールが推奨されている ImageMagick を用いると、若干ではあるがアンチエイリアスによりきれいな JPEG/PNG を出力できる。eps(2)write はデフォルトでは -r20016 固定で解像度調節は無効だが、基本設定で「低解像度での処理を行う」を ON にすると解像度調節が有効になり、-r オプションの値は 解像度レベル×72 となる。余白付与は、EPS ソースの BoundingBox 情報の編集の代わりに、ImageMagick の convert の -splice オプションによって行う。余白の単位はデフォルトでは px であり、ピクセル単位で (指定された余白) 分の余白を付加するが、単位を bp に指定するとピクセル単位で (指定された余白)*(解像度レベル) 分の余白を付加することにより、PDF/EPS の結果に近づけている*3。
TeX2img Mac 版の変換方式
Mac 版は以下のように処理する。Windows 版に比べて若干複雑になるが、これは高機能な OS X の API をフル活用するためであり、最終的な出力がよりきれいになるように gs と OS X の API を使い分けている。大雑把には
となるようである。
【テキスト情報を残す PDF 出力の場合】
TeX →…→ PDF →[pdfcropでクロップ+余白付与]→ PDF
Mac では Perl インタプリタが内蔵されているという前提があるので、pdfcrop を用いて簡単である。
【アウトライン化 PDF 出力の場合】
TeX →…→ PDF →[gs (eps(2)write)でアウトライン化+クロップ]→
EPS →[epstopdf (gs)]→ PDF →[pdfcropで余白付与]→ PDF
eps(2)write はデフォルトの「画質優先モード」では -r20016 固定で解像度調節は無効だが、変換処理で「速度優先モード」に変更すると解像度スケール調節が有効になる。このとき、-r オプションの値は 解像度レベル×144 となる。gs の epstopdf は Perl インタプリタを用いる pdfwrite のラッパだと考えて差し支えない。
【アウトライン化 EPS 出力の場合】
TeX →…→ PDF →[gs (eps(2)write)でアウトライン化+クロップ]→
EPS →[BB情報を編集して余白付与]→ EPS
eps(2)write はデフォルトの「画質優先モード」では -r20016 固定で解像度調節は無効だが、変換処理で「速度優先モード」に変更すると解像度スケール調節が有効になる。このとき、-r オプションの値は 解像度レベル×144 となる。
【JPEG/PNG 出力(画質優先モード)の場合】
TeX →…→ PDF →[gs (eps(2)write)でアウトライン化+クロップ]→
EPS →[epstopdf (gs)]→ PDF →[OS XのAPIでビットマップ化+余白付与]→ JPEG/PNG
変換処理はデフォルトで「画質優先モード」である。OS X の API によるビットマップ化が美しいため、これを用いるためにまず epswrite/eps2write によってアウトライン化 EPS を作成して再び epstopdf によって PDF に変換する。画質優先のため -r20016 固定で解像度調節は無効である。
【JPEG/PNG 出力(速度優先モード)の場合】
TeX →…→ PDF →[pdfcropでクロップ+余白付与]→
PDF →[OS XのQuartz API]→ JPEG/PNG
変換処理で「速度優先モード」に変更すると、そもそも JPEG/PNG 処理の結果は元ファイルがテキスト保持かアウトラインかは問題とならないため、eps(2)write を通さずに pdfcrop を用いることにした。これによって、結果的には gs9.14 以前の epswrite でまれに起こる VMerror を根本から回避することができる。
TeX2imgの余白付与機能
前々回の記事で説明した通り、eps2write により生成したEPSのソースにはバイナリが含まれることがある。このことは、TeX2img の余白設定機能に影響する。
EPS ファイルへの余白付与は EPS の BoundingBox 情報を書き換えることによって実装されている*4のだが、以前のバージョンの TeX2img では EPS ファイルの読み書きにおいてテキストファイルを前提とするコードになっていた。これではバイナリを含むソースを編集できないため、書き換え方式を変更した。詳細は Windows 版と Mac 版のソースコードを参照。
フォントのアウトライン化
前々回の記事で説明した通り、eps2write は小さなパーツやフォントサイズの小さな文字をビットマップ化してしまうことがある。TeX2img の使用用途のうちで結構大きな部分を占めるであろう「TeXの数式を Illustrator や Inkscape にアウトライン化して貼り込む」という用途に対応するため、gs9.15 以上を用いる場合は、eps2write に新たに増設された -dNoOutputFonts オプションによってフォントを必ずアウトライン化するようにした*5。これに伴い「gs9.14 以前では eps2write に -dNoOutputFonts オプションが存在しないため epswrite を用い、gs9.15 以降では eps2write を用いる」ように微妙に変更した。
複数ページ処理について
Mac 版 TeX2img は、(Windows 版が更新停止している間に開発が進んだこともあって)かなり前から複数ページ処理に対応していた。この処理をどのように行っているかというと
- 初めに OS X の API で PDF の総ページ数を取得
- epswrite/eps2write のオプションで -dFirstPage=2 -dLastPage=2 というように開始と終了を規定
- 特定のページのみを EPS 化するという行為をページ数分繰り返す
ようになっている。このため前回説明したような「余計なラストページが生じるかどうか」という問題とは無縁だった。
一方5年ぶりに開発再開した Windows 版 TeX2img は、先月リリースの 1.2.0 で複数ページ処理を初めて取り入れた。このとき「-%d」を付けることで実装されたため、 TeX2img は Ghostscript が常に 1 ページ多くはき出してしまうのを前提として最後の一枚を無視する処理になっていた。もし今後 Ghostscript の Windows 版が修正されてページ数ぴったりになってしまうと対応できなくなるという問題を避けるため、今回のバージョン 1.2.5 からは pdfinfo でページ数を取得し、ページごとに処理するようにした。
なんかよくわからないけど,ともかく出力ファイルに%dの指定をするとおかしいみたいなので,pdfinfoでページ数を取得してページごとに処理するようにした.そもそも前から1ページ多くでたりしておかしいとは思っていたんだよなぁ.
— abenori (@abenori) 2014, 10月 16
コンパイル回数推定について
数式番号などを相互参照する際に有用な「コンパイル回数推定・指定機能」が、Windows 版 1.3.0 と Mac 版 1.8.6 で付加された。この機能は .aux などの補助ファイルを監視し、変化しなくなるまでコンパイルを繰り返すことにより実装されている*6。ただし、Windows 版は .toc など他のファイルの変化も監視するのに対し、Mac 版ではとりあえず .aux の変化のみを見るようになっている*7。なお .aux が収束しない場合*8を考慮し、回数推定を働かせる場合にも上限を設定できるようにしてある。
疑問に思われるかもしれない点について
以上が現在の TeX2img の動作の解説である。まだ疑問をもつ方がいるかもしれないので、補足しておく。
「TeX2imgが epswrite/eps2write を用いるスキームを貫いているのはなぜ?」
PDF → EPS → PDF と変換することは「劣化が不可避」という見方があるかもしれない。
で、この記事を注意深く読むと、 (Ghostscriptを使って)PDF→EPS→PDFと変換する というパスは“絶対に絶対にやってはいけない”(劣化が不可避)ことが解る。
— ZR-TeXnobabbler(既定値) (@zr_tex8r) 2014, 10月 16
トリミングや余白付与を行うだけであれば pdfcrop を用いれば良いと思うかもしれないが、以前の記事で述べた通り Perl インタプリタが必須となるため、避けることにしてある。では ZR さんのおっしゃるように pdflatex と preview パッケージを用いればよいかというと、これも以前の記事で述べたような「アウトライン化」の目的を達成するには不十分である。TeX2img の用途としてアウトライン化の需要の方が多いであろうというという推測から、今後とも epswrite/eps2write を用いる予定である*9。アウトライン化すれば例えば
のように Illustrator を用いてエフェクトをかけることもできる(図は物理のかぎしっぽより)*10。もし Perl のない環境で pdfcrop のようなことを実行したければ ZR さん提案の方法を参照してほしい。
途中のTeXコードではpdfcropの手順を真似した。 複数ページある場合は、 “\proc[bbox値]”を実行→“\setbox0{画像}”→\shipout を各ページで行った後 \end、でいけると思う。#TeX
— ZR-TeXnobabbler(既定値) (@zr_tex8r) 2014, 10月 16
これを読むと、いかに pdfTeX が PDF 操作ツールとして有用であるか思い知らされる。
追記:2014-10-18 23:49 はい、まさにその通りです!
要は、同じ「LaTeXコードからPDF画像を作る」という作業であっても、その作業の目的をきちんと考えて、適切な方法を使い分けることが必要だということ。#TeX
— ZR-TeXnobabbler(既定値) (@zr_tex8r) 2014, 10月 18
というわけで、次回は TeX2img の「使い方」を説明するつもりである。
*1:Ghostscript のアウトライン化の挙動や仕様変更については前々回と前回の記事まとめた。
*2:“対応する”という表現を用いたのには意味がある。実際の処理は、BB 情報編集で「余白単位が bp ならば PDF/EPS と同じ値で付加し、px ならば PDF/EPS の場合の値を解像度レベルで割った値で付加」している。
*3:なぜ ImageMagick を用いる場合だけ EPS ソース編集を行う方法でないのかと疑問に思うかもしれないが、すぐ上の脚注を読めば理由はわかるはずである。EPS ソース編集で px 単位の余白付与を行うのは間接的で、本来の px 単位を直接用いる -splice オプションの方が本質的には“普通”であろう。
*4:詳しくは「EPS のソースの %%BoundingBox: や %%HiResBoundingBox: の行を書き換えることによって余白を作って」いる。
*5:ただし、言うことを聞かない場合もある。前回書いた通り TeX2img を介してもコマンドラインから操作しても、例えば例のロゴは Windows/Mac ともにアウトライン化できなかった。
*6:リリース順序としては Mac 版が先行したが、機能実装は Windows 版が先であった。これは Windows 版リリースを CUI の動作テスト完了まで保留したためである。ちなみに、寺田さんによって Mac 版 1.8.4 に「コンパイル回数指定機能」が追加されたことを受け、Windows 版 1.3.0 では阿部さんが以前から常用している「コンパイル回数推定ルーチン」を取り入れ、最大コンパイル回数を指定できるようにした。このため Mac 版 1.8.5 から 1.8.6 にかけて類似のルーチンを付加して仕様を統一したというのが真相である。
*7:寺田さんいわく「TeX2img の用途を考えると,目次や索引,参考文献リストがあるような大きな書類を丸ごと画像化する必要性は少ないだろうと思われるので,実装の手間を考えて現時点ではauxのみを見ることにしました。ですが,必要性があるようでしたら,今後tocなど他のファイルを見るようにも拡張しようと思います。」とのこと。
*8:実例としては、寺田さんによる一例あるいは阿部さんによる一例が考えられる。
*9:そもそもテキスト情報を保持してトリミングと余白付与したいといいうのであれば、Perl が使える環境で pdfcrop を直接コマンドラインから使えばいいではないか! 寺田さんも Mac 版のテキスト保持の場合について
特に需要があったわけではありません。単になんとなく付けてみただけです(^^;
テキスト保持でのPDF出力であれば,pdfcropでもpreviewパッケージでもstandaloneクラスでもいいわけですから,あまり需要はないかもしれません。
(実際,このモードでのTeX2imgは,機能的にも内部的にも TeX+dvipdfmx+pdfcrop の単なるGUIラッパとなっています。)
とおっしゃっているので、TeX2img の Windows 版でわざわざ取り入れるほどでもないよね?
*10:TeX のフォントをシステムにインストールすれば Illustrator の機能でテキストのアウトライン化が可能かもしれないが、TeX のフォント形式は特殊なのでうまくいかない可能性がある。