svgにラスタ画像を埋め込みたい!
SVGとはベクターイメージ用の形式ですが、時にpngとかのラスターイメージを埋め込みたい場合もあると思います。実際埋め込むことができます。イラレをお使いの奥様方でしたら、ラスターイメージが含まれてようがsvgで書き出しできるっちゅうことはご存知やと思います。
今回は、pythonでsvgにラスタ画像を埋め込む方法を書いときます。備忘録ですね。
svgwriteは便利や!
環境を教えときます。python3.x.xです。あと、SVGデータを扱うため、「svgwrite」というパッケジを使います。リンク先はドキュメントなので、よく読んどけばいいです。入れ方?しらん、どうせpip install svgwriteやろ!?
全体像
まず、普通にコード丸ごと載せときますわ!いうてもめっちゃ短い!
svgwriteは当然使うので当然importします。osは画像ファイル開くんで使います。base64はあとで使います。そしたら、それ以降を説明していきますね。
svgwriteを使う部分
SVGそのものについては、defghi1977さんのまとめが超まとまっててありがたいので、そちらで学んどきましょう。ここでは、svgwriteでどうsvgを作るかという話をします。まず、
ってやってsvg要素を作ります。filenameのとこに出力ファイル名をいれときます。カンマ入れて後にsize=(200, 300)ってやることでビューポートをwidth=200, height=300にできたりとかもします。ドキュメントに書いてます。
では、作ったsvg要素に画像を入れます。画像ですが、とりあえず書いてるコードと同じ階層にinu.pngを用意しました。
inu.pngです。ペットアンブレラ付きです。さて、svg要素にどうやってinu.pngを追加しますか。
俺は雰囲気でpythonをやっているから正確な説明ができなくてアレですが、さっきdwgという大枠のSVG要素を作ったと思います。その中に丸とか三角とか四角とか画像とかをdwg.add()で追加していくわけですね。
その中のdwg.imageはその名の通りImageオブジェクトを作ります。'inu.png'は犬の画像で、つまり入れたい画像のパスを入力するわけですね。insert=(x,y)は座標(入れる画像の左上がくる場所)、sizeはそのまんまサイズです。sizeについては少しハマりポイントがあるんですが、ここでは言及しません。
あとは、dwg.save()で.svgが生成されます。
ところで、'inu.png'とパスを指定するのには問題があります。何故なら、inu.pngが置いてる場所が変わっちゃうと、当然inu.pngが見つからんのでSVG側ではワンちゃんが表示されんくなります。
.svgと同じ階層にinu.pngを置いておけばいいのですが、それはあまりにも面倒です。どうしたらええねん?
ありがとうbase64
幸いにも、バイナリデータをASCII文字列にエンコードできるbase64っちゅうやつがいます。実際、イラレとかでもラスタ画像を埋め込みにしてSVGを吐き出した場合、ラスタ画像はbase64エンコードされた状態でSVGに埋め込まれています。そしたら、その通りやりましょう。
with構文を使うと、close()とかいうお片づけを勝手にやってくれるので便利でいいですね。読み込んだ画像を、b64encodeでエンコードするだけです。
あとは、
といった具合に、パスをbase64スタイルにします。data:image/png;base64, ちゅうのは、HTMLとかでbase64化された画像を埋め込む時のお作法みたいなんですね。jpegを埋め込む場合は、image/pngのとこをimage/jpegにしてください。
その後ろにbase64化データの文字列を足すのですが、少し注意しておきたいのが、b64encodeされて出てくるのはbytes型なんで、そのままでは死にます。.decode("ascii")するとstr型になるのでそうしときましょう。asciiじゃなくてもいいと思う、知らん
ただ、あんまファイルサイズがデカいpngとかは埋め込まんのが吉かもしれませんね。知らん。
犬をsvgに埋め込めると、嬉しい点ですが、例えばsvgはアニメーションができますので、犬を回せます。
(環境によっては回ってないかもしれません、回ってなかったらスマソ)
犬が回って何が嬉しいのかようわからんが、犬が回ってよかったね!