2021/09/09追記: やっぱりrsvg-convert
でやろう
Headless Chromeはpattern fillがラスタ画像になってしまったり、コメントでご指摘を受けた通りなんだかグリッド線が太くなっていたり、なんだかんだそんなに良いものではないことが分かってきました。
そんな中、試しにrsvg-convert
の新しいバージョンで再度試してみたら以下で紹介しているようなはみ出しバグが消えていることに気づきました。
試したrsvg-convert
のバージョン:
$ rsvg-convert --version
rsvg-convert version 2.50.3
rsvg-convertならグリッド線が太くなることもないしpattern fillもちゃんと扱えるので、やっぱりHeadless Chromeではなくrsvg-convert
でやるのがベストっぽいです。
以下の記事の内容は古いですが、ログとして一応残しておきます。
はじめに
LaTeXがsvgに対応していないというのは深刻な問題で、古代ギリシャではそれに怒った民衆が国を滅ぼしたとも伝えられます。
にも関わらず令和の時代になってもまともなsvgサポートがLaTeXでなされないのはそれだけsvgの仕様が複雑ということでしょうか。
現代においてすら、我々はsvgからpdfへの変換を余儀なくされています。
しかし最近、svg -> pdfの変換はそう簡単なものではないらしく、inkscapeですらまともに変換できない場合があることに気付いてきました。
各種ライブラリを試してみましたが、結論から言えば、Google ChromeのheadlessモードでのPDF出力が最もまともな変換をなすということが分かりました。身も蓋もない。
ということでsvg -> pdfの変換を行うシェルスクリプトを作りました。先に置いておきます。
svg2pdf.bash:
https://gist.github.com/s417-lama/84bf66de1096c4587e8187092fb41684
$ ./svg2pdf.bash plot.svg plot.pdf
chromeがインストールされていれば動くと思います。
google-chrome
というコマンドは環境依存かもしれないので適宜対応してください。
※ 2021/07/29 追記: Headless Chromeでもpattern fillはあんましちゃんと出力してくれないことが分かったので一概にHeadless Chromeが最良の選択肢とも言えなくなってきました。
記事の末尾参照。
各種ライブラリの(簡単な)検証
ここでは実際のsvgの例を通して各種svg -> pdf変換ライブラリの出力を確認していきます。
使用するのはPlotly.jsで描いたグラフをsvg出力したものです。
環境はUbuntu 18.04です。
Inkscape
LaTeXでsvgを貼りたいよstackoverflow〜〜〜〜。と言うと真っ先に返ってくるのが「inkscapeでPDFに変換しろ」という答え。はたして上手く行くのか。
$ inkscape --version
Inkscape 0.92.3 (2405546, 2018-03-11)
$ inkscape -D -z -f plot.svg -A plot.pdf
さすがはinkscapeですね。問題なくPDFに変換され、、、おっと危ない。foo
の点線が変ですね。
svgではfoo
とbar
の点線は区別されていたのに一緒になっています。これは結構困る。
rsvg-convert
$ apt install librsvg2-bin
で入るやつ。librsvgというライブラリ。
$ rsvg-convert --version
rsvg-convert version 2.40.20
$ rsvg-convert -f pdf plot.svg -o plot.pdf
惜しいですね。x軸からはみ出してます。
2021/09/09追記: 少なくともバージョン2.50.3ではこのバグが消えていました。
Cairosvg
$ cairosvg --version
1.0.20
$ cairosvg plot.svg -o plot.pdf
同じくはみ出してます。あとなんかよく見るとフォント変わってません??
Headless Chrome
先程の。
svg2pdf.bash:
https://gist.github.com/s417-lama/84bf66de1096c4587e8187092fb41684
$ google-chrome --version
Google Chrome 81.0.4044.129
$ ./svg2pdf.bash plot.svg plot.pdf
良いですね。ちゃんと変換されているようです。
svg2pdf.bash
の説明
svg2pdf.bash:
https://gist.github.com/s417-lama/84bf66de1096c4587e8187092fb41684
このスクリプトが何をしているのか簡単な説明です。
基本的にはchromeのheadlessモードでPDF印刷をすればいいので、
$ google-chrome --headless --disable-gpu --print-to-pdf=plot.pdf plot.svg
基本的にはこれを走らせれば良いわけですが、このままでは印刷特有の謎のheader, footerが表示される上、サイズがA4で出てきてしまうのでこの辺を調整してやる必要があります。
shell scriptと言っても中身はほぼhtmlとjsなのですが、svgのサイズをjsで抜き出して印刷設定のCSS attributeを設定しています。
おわりに
ベクター画像の代表たるsvgですが、もはやブラウザしかまともに取り扱えない仕様になってしまっているんですかね。
でもよく考えればsvgにcssとか設定できるしブラウザが得意なのは当然なのかも。
ということで、svg -> pdfの変換にはchromeを使おう、という話でした。おしまい。
参考
- https://superuser.com/questions/381125/how-do-i-convert-an-svg-to-a-pdf-on-linux
- https://stackoverflow.com/questions/44970113/how-can-i-change-paper-size-in-headless-chrome-print-to-pdf/56844278#56844278
- https://stackoverflow.com/questions/44575628/alter-the-default-header-footer-when-printing-to-pdf
(2021/07/29 追記)pattern fillへの対応状況
SVGのpattern fillをベクタ形式のままPDFに出力してくれるかどうか確認しました。pattern fillは
こんな感じのやつ。
結果としては、
- Inkscape: OK
- rsvg-convert: OK
- Cairosvg: patternが消える
- Headless Chrome: ラスタ画像になっちゃう
一概にHeadless Chromeを使うべきとも言えなくなってきた。うーむ。
場合に応じて使い分けましょう!