Acetaminophen’s diary

化学に関すること,TeXに関すること,ゆきだるまに関すること。

Ghostscript のこと(3):新しいアウトライン化の知見

以前の記事で、2回にわたって Ghostscript のアウトライン化の挙動を考察した。しかし、TeX2img をアップデートするにあたりもう一度検証したことで、いくつかの知見が新たに得られた。

 

高解像度・低解像度とは?

第1回の記事で

gs9.14 以前の epswrite の場合は -r オプションに応じて
  • 低解像度の場合:常に“マスク付ビットマップ化”が起こる
  • 高解像度の場合:基本的にはアウトライン化するが、場合によっては PostScript と「相性が悪い」ために“不完全アウトライン化”が起こる

と書いた。しかし、この低解像度・高解像度という表現はあまり適切ではなかった。このように書いてしまうと、どこかに解像度の -r 値について閾値があるのではないかという発想になるだろう。しかし、それは実験的に正しくない。むしろ「高解像度でアウトライン化、低解像度でビットマップ化」というのが誤りで、より正確な表現としては決められた解像度レベルでの 1 単位に対して

大きな文字はアウトライン化(稀に“不完全アウトライン化”)

小さな文字は“マスク付ビットマップ化”

しているというべきである。つまり文字サイズと解像度レベルの相対的なスケールによって、アウトライン化かビットマップ化かが決定するのである。これを確かめるには、-r20016 のいわゆる高解像度の場合でも「、」や「。」といった小さな文字がアウトライン化されずに“マスク付ビットマップ化”されていることを見ればよいだろう。IllustratorInkscape で生成画像を開いてグループ解除し、パスになっているかどうか確認すれば一目瞭然である*1。逆に -r720 でも、もともと大きな文字であればアウトライン化に成功するはずである。

そこで Ghostscript 9.14 のページを見てみると、確かに Known Limitations. として epswrite の問題が書かれている。

epswrite devices reduce everything to path, fill, stroke, clip image, and imagemask operations. Although the resulting file prints OK it produces unsatisfactory results when scaled, distilled or imported into graphic editors. The file can easily exceed 4GB and hit file size limits in some applications or operation systems. Handling of big files is slow.

Bug #615165, September 26, 2002.

NB. The epswrite device is deprecated as of the 9.12 release, the eps2write device should be used instead which does not suffer these limitations.

Ghostscript Open Issues (9.14).

 

アウトライン化の決定版! 推奨の方法は?

完全にアウトライン化を完了させるためには、どうするのがいいのか。

gs9.14 以下の場合:アウトライン化+クロップ

epswrite デバイスを用いる。ただし、-dNOCACHE オプションを付ける!

まず epswrite デバイスは文字や図形がある領域の外側の余白をクロップする。これに -dNOCACHE オプションを付けると、解像度によらずすべてのフォントをアウトライン化し、文字と解像度の相対的なバランスに依存しないという特徴を持つ。コマンドは

$ gs -dNOPAUSE -dBATCH -dNOCACHE -sDEVICE=epswrite -dFirstPage=1 -dLastPage=1 -sOutputFile=input-outline.eps input.pdf
$ gs -dNOPAUSE -dBATCH -dEPSCrop -sDEVICE=pdfwrite -sOutputFile=output.pdf input-outline.eps

この場合、もともとの PDF に余白があったとしてもそれは epswrite の仕様により失われてしまうことに注意。なお、上のコマンドはあくまで一例であり「元が複数ページ PDF であって、その 1 ページ目をアウトライン化する」という場合である。

gs9.15 以上の場合:アウトライン化+クロップ

eps2write デバイスを用いる。ただし、-dNoOutputFonts オプションを付ける!

まず eps2write デバイス余白をクロップする。これに -dNoOutputFonts オプションを付けると、解像度によらずすべてのフォントをアウトライン化する。

$ gs -dNOPAUSE -dBATCH -dNoOutputFonts -sDEVICE=eps2write -dFirstPage=1 -dLastPage=1 -sOutputFile=input-outline.eps input.pdf
$ gs -dNOPAUSE -dBATCH -dEPSCrop -sDEVICE=pdfwrite -sOutputFile=output.pdf input-outline.eps

 

解説:アウトライン化オプションについて

gs9.15 では epswrite デバイスが廃止され、代わりに gs9.14 で導入された eps2write デバイスを推奨している。従来の epswrite デバイスと同様に eps2write にも -dNOCACHE オプションが存在するが、実は -dNOCACHE オプションはデバッグ用だったというのだ。

調べてみると、-dNOCACHE オプションはもともとフォントがうまく表示されないという問題が起きた場合の「デバッグ用の最終手段」としての利用を想定してデザインされたらしい(以下は StackExchange での回答より)。

You can add -dNOCACHE option. It is originally used for debugging, due to document of GS. But this is the only way I know.
-dNOCACHE is considered a debugging option because it turns the text glyphs into the set of outline curves that represents them, making for a huge file that is slow to render and you can no longer search for the text or copy/paste it.
Althouth it's worth pointing out that -dNOCACHE still vectorizes the text...

そして、まさにその副作用としてアウトライン化が起こるというのが真相のようだ。フォントのアウトライン化は「劣化」だといわれるとおり、テキスト情報を失い、かつファイルサイズも大きくなってレンダリングにも時間がかかる。あくまでデバッグの副作用としてアウトライン化を行うため、実は挙動は既定のものではなく、想定したとおりに動く保証はないのだろう。

しかし、gs9.15 で新設された -dNoOutputFonts オプションは正式にフォントをアウトライン化するためのオプションとして設計され、eps2write / ps2write / pdfwrite でフォントをアウトライン化することを可能にした。したがって、挙動の保証がない -dNOCACHE オプションをやめて -dNoOutputFonts オプションだけに切り替えるのが得策である。eps2write によってアウトライン化すれば、余白をクロップするので、これと併せて従来の epswrite と似たような結果を得ることができる(しかも正式サポートなので信用できる)。この件に関してはこちらが大いに参考になる。

 

新しいアウトライン化の方法:クロップしないアウトライン化

よく見ると gs9.15 では pdfwrite にも -dNoOutputFonts オプションがあるのに気付く。これは余白を保持したままクロップするために用いることができる。

$ gs -o output.pdf -dNoOutputFonts -sDEVICE=pdfwrite input.pdf

従来はアウトライン化するためには「epswrite を用いてアウトライン化 EPS に変換し、再び pdfwrite で PDF に変換する」、すなわち PDF → EPS → PDF という回りくどい方法しかなかったわけだ。しかし、その場合勝手にクロップされてしまい、元の余白を維持できなかった

新しい gs では、pdfwrite でアウトライン化が可能になったため、PDF → PDF という直接的なアウトライン化が可能であるうえ、余白が保持される。ちなみに -o output.pdf-dBATCH -dNOPAUSE -sOutputFile=output.pdf と同じ意味らしい(こちらを参照)。

  • 従来の PDF → EPS → PDF で「アウトライン化+クロップ」
  • 新しい PDF → PDF で「アウトライン化(余白保持)」

この 2 つを使い分ければ、画像変換の可能性が広がることだろう。

*1:しかし細かいことなので気づきにくく、実際に TeX2img がこのバグに気づいたのは TeX2img for Windows 1.4.0 および TeX2img for Mac 1.8.8 のリリース後である。