LoginSignup
27
21

More than 1 year has passed since last update.

SVGからPDFへの変換はHeadless Chromeでやろう(と思ったけどやっぱりrsvg-convertでやろう)

Last updated at Posted at 2020-04-29

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出力したものです。

image.png

環境は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

image.png

さすがはinkscapeですね。問題なくPDFに変換され、、、おっと危ない。fooの点線が変ですね。
svgではfoobarの点線は区別されていたのに一緒になっています。これは結構困る。

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

image.png

惜しいですね。x軸からはみ出してます。

2021/09/09追記: 少なくともバージョン2.50.3ではこのバグが消えていました。

Cairosvg

$ cairosvg --version
1.0.20
$ cairosvg plot.svg -o plot.pdf

image.png

同じくはみ出してます。あとなんかよく見るとフォント変わってません??

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

image.png

良いですね。ちゃんと変換されているようです。

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を使おう、という話でした。おしまい。

参考

(2021/07/29 追記)pattern fillへの対応状況

SVGのpattern fillをベクタ形式のままPDFに出力してくれるかどうか確認しました。pattern fillは

こんな感じのやつ。

結果としては、

  • Inkscape: OK
  • rsvg-convert: OK
  • Cairosvg: patternが消える
  • Headless Chrome: ラスタ画像になっちゃう

一概にHeadless Chromeを使うべきとも言えなくなってきた。うーむ。
場合に応じて使い分けましょう!

27
21
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
21