TeX 出力から SVG への変換
この記事は、サブブログの 2015-03-10 ~ 2015-03-12 投稿記事から移転したものです。
という訳で、検討メモを貼っておく。今回の検証は初めにすべて Mac で行い、そのあと Windows でも追試した。
目標
ウェブサイトに載せる画像としても利用したいし、拡大でギザギザになるのもいや。また、フォントがないと表示できないのも困るので、アウトライン化されたベクター画像を最終目的とする。すなわち、こんな感じの SVG 画像をつくりたい。(図中の青い点は、Illustrator で開いてパスのノードを選択した状態。)
以下では、検討した(実験した)順に掲載する。すなわち、上にあるものほど良い方法だという訳ではないことに注意。
1:Ghostscript で EPS から SVG へ
Ghostscript が SVG 出力に対応しているという話(例えばこことかここ)を見つけたので、gs9.10 で試してみた。これは確かに成功する。
$ gs -dBATCH -dNOPAUSE -sDEVICE=svg -sOutputFile=equation.svg equation.eps
しかし、gs9.15 では output device から svg が消えている。調べてみると、Ghostscript の svg デバイスは品質が良くなかったようで…。
Customer has already been notified that the SVG device is not of commercial quality.
いや、でもサポートをやめなくてもいいんじゃないかな…
2:dvisvgm で DVI から SVG へ
TeX Live や W32TeX には、dvisvgm というソフトウェアが収録されている(ここやここ参照)。画像化の目的ではフォントのアウトライン化をしたいので、とりあえず DVI から SVG への変換を試してみる。-n オプションでフォントをパスに変換できるらしいので…
$ dvisvgm -n equation.dvi
これでパスに変換できた。ただし、この方法では DVI を経由する方法しか対処できず、かつ map によるフォント埋め込みもできないという制約がある。
3:dvisvgm で EPS から SVG へ
同じく dvisvgm であるが、これなら先に PDF から EPS への変換を eps(2)write で行う(=アウトライン化)ことができるので、フォント埋め込みの問題も解消するはず。しかし、実際にやってみると
$ dvisvgm -E equation.eps
ERROR: Ghostscript is required to process the EPS file
というわけで、(少なくとも自分の OS X 環境では)何もしないと Ghostscript のライブラリを認識できなかった…。
dvisvgm の FAQ によると dvisvgm のビルド方法には 3 種類あるらしく*1、それぞれで PostScript を扱う方法が異なる。3 つめのビルド方法では gs を使えないのだが、幸い MacTeX-2014 の TeX Live の場合は 2 番目のビルド方法らしく、--libgs オプションで場所を指定すれば使える。僕の場合は TeX Live とは独立に MacPorts でインストールした gs を使っているので
$ dvisvgm --libgs=/opt/local/lib/libgs.dylib -E equation.eps
これで変換できた。ただし、人によっては MacPorts を使っていないはずだし、そもそもこのライブラリを TeX Live 側から発見することが不可能なので、一般性は無い。
ちなみに Windows ではこのような問題は発生しなかった(正しく gsdll32.dll/gsdll64.dll を認識してくれる模様)。
この「gs をどうやって見つけるか・見つけられるか」という課題のほかにも、この方法には以下の懸念点がある。
- Illustrator で dvisvgm で出力した SVG を開くと「SVG Tiny に書き出し後に読み込むとクリッピングは失われます」というエラーが出る*2
- そもそも dvisvgm の -E オプションや --eps オプションは 2013 年 3 月 1 日の version 1.2 で新設されたかなり最近の変更
というわけで、不便に感じる面も多そうだ。
4:pstoedit で EPS/PDF から SVG へ
pstoedit は GPL ライセンスであるが、pstoedit の svg サポートは「シェアウェアのプラグインでの対応」らしい。代わりにフリーで使えるのが plot-svg というオプション。
$ pstoedit -f plot-svg -dt -ssp equation.eps equation.svg
この方法はここやここを参照。ただし、後者によるとうまく画像を変換できない場合があるらしく、一般的な方法とするには少々不安である。
5:pdf2svg で PDF から SVG へ
GPL ライセンスの pdf2svg というものがある。これなら、既にアウトライン済みの PDF を使って SVG に変換できる! 品質も問題なく、特にエラーも発生しない。
$ pdf2svg input.pdf output.svg
というわけで、以上 5 つのなかではこれが最善のように感じる。
6:ImageMagick で PDF から SVG へ
ImageMagick の convert も SVG を出力可能である。convert は良く用いられているので一般性がありそうだが…
$ convert equation.pdf equation.svg
この方法はベクター画像の PDF であっても勝手にビットマップ化してしまう。そのうえ、XML 的にも規格にあわない SVG ファイルを出力するのでブラウザで表示することもできない(Thanks: @golden_lucky さん)。
7:Potrace で PNM から SVG へ
こちらに書かれている方法。PNM とは PBM, PGM, PPM すなわち白黒・グレースケール・フルカラーの ASCII テキスト形式の画像フォーマットの総称(こちらが詳しい)で、ビットマップである。すなわち、この方法ではいったんビットマップ化した後に再度 Potrace によってアウトラインをトレースする。PNM の作成は ImageMagick の convert でも gs の pnm 系デバイスでも構わないが、アウトラインの精度を高めるためには解像度を高くしておきたいところ(なお解像度は適当に決めた)。
- ImageMagick の convert の場合
$ convert -density 500x500% equation.eps equation.pbm $ potrace -o equation.svg -s equation.pbm
- gs の pbm device の場合
$ gs -q -sDEVICE=pbm -sOutputFile=equation.pbm -r2400 -dNOPAUSE -dBATCH -dSAFER -dEPSCrop equation.eps $ potrace -o equation.svg -s equation.pbm
なお、PBM を選んだのは Potrace の仕様に従っている。
制約として、Potrace は白黒の 2 値画像しかトレースできない。カラー画像を処理しようとすると、下のようにもやもやしたパターンができる(元画像で「あいうえお」を黒、「かきくけこ」をピンクにしていた場合で試した。Potrace でトレースして得た SVG のスクリーンショット)。
色を扱えないのは致命的だが、公式に「グレースケールやフルカラーの画像のトレースには事前に mkbitmap を使って閾値で 2 値化しておく」ということらしい。
8:Poppler の pdftocairo で PDF から SVG へ
Poppler という PDF ライブラリの中に、pdftocairo というツールが入っている。
$ pdftocairo -svg equation.pdf
これは結果が(見た目・コードともに)綺麗。
9:MuPDF の mudraw で PDF から SVG へ
MuPDF という PDF ライブラリの中に、mudraw というツールが入っている。
$ mudraw -o equation.svg equation.pdf
これも(見た目・コードともに)良い結果。
10:Inkscape で PDF から SVG へ
Inkscape でもできなくはないらしいので、やってみた。
$ inkscape -z -f equation.pdf --export-plain-svg equation.svg
変換はできたが、なんだかソースが汚いようにみえる。--export-plain-svg というのは Inkscape の独自 SVG から標準 SVG への変換オプションのようなので、仕様がよくわからない…。
ちなみに TeX2img では
これらの検討のきっかけは、TeX2img で SVG 出力をサポートしたかったからである。TeX2img for Mac 1.8.9 では 5 番目の方法である pdf2svg を搭載した*3が、のちに 1.9.2 時点で mudraw を使う方法に変更されている。