2022年2月18日追記
2022年2月17日にリリースされたCanvg v4.0.0については、以下の記事をご参照ください。
はじめに
ブラウザ上に表示されているSVGをPNG画像としてダウンロードしたいことがあります。その場合
- Canvgを使ってcanvasにSVGをレンダリング
-
canvas.toDataURL()
またはcanvas.toBlob()
とURL.createObjectURL(blob)
を使ってdataURLに変換 -
<a>
タグのhref
属性にdataURLを指定し、ダウンロード
という手順で行われることが多いです。1
このような日本語の解説記事はいくつかありますが、Canvg v2.0.0を基にした古いものが多く2、2019年にリリースされた最新のv3.0.7について書かれたものは筆者が見た限りなさそうです。
そこでこの記事では、手順1.について、Canvgのv2とv3でどのように記法が変わったのかについて説明します。
v2とv3の比較
前提として、ブラウザ上のアニメーションの含まれないSVG DOM (#svg_root
)を、Canvasに変換することを考えます。CanvgはWebpackを使ってインポートしています。
v2.0.0を使う場合は以下のように書きました。
描画は非同期で行われ完了時にrenderCallback
が呼ばれるため、Promiseでラップしています。
import canvg from "canvg";
function render() {
const svgRoot = document.querySelector("#svg_root");
const svgString = svgRoot.outerHTML.replace(/NS[0-9]+:href/g, "xlink:href");
// .replace()はiOS Safari等でnamespaceが"xlink"ではなく"NSなんとか"になるのに対応するため
const canvas = document.createElement("canvas");
const canvas.width = 1920; // canvasの幅を指定
const canvas.height = 1080; // canvasの高さを指定
return new Promise((resolve) => {
canvg(canvas, svgString, {
renderCallback: () => resolve(),
});
});
}
これに対して、v3.0.7を使う場合には以下のようになります。
違いの一つは、Canvgに渡す引数がcanvasからctx(CanvasRenderingContext2D)に変わったことです。
ほかには注意点として、Canvg.fromString()
だけでは描画が行われないため、その後v.render()
を呼ぶ必要があります。v.render()
はPromiseを返すため、以前のようにラップする必要は無くなりました。
import Canvg from "canvg";
function render() {
const svgRoot = document.querySelector("#svg_root");
const svgString = svgRoot.outerHTML.replace(/NS[0-9]+:href/g, "xlink:href");
// .replace()はiOS Safari等でnamespaceが"xlink"ではなく"NSなんとか"になるのに対応するため
const canvas = document.createElement("canvas");
const canvas.width = 1920; // canvasの幅を指定
const canvas.height = 1080; // canvasの高さを指定
const ctx = canvas.getContext('2d');
const v = Canvg.fromString(ctx, svgString);
return v.render(); // Promise
}
以上です。
-
Canvgを使わずとも
ctx.drawImage()
の引数に SVGImageElementを渡すことでも画像の変換を行うことができます(例えば、「SVGを画像に変換してダウンロードする方法」)。しかし、SVG中のimageタグで外部の画像を読み込んでいる場合には、この方法では上手くいかないようです。 ↩ -
「svg.jsとcanvgを使って、SVGタグ内のオブジェクトをクライアント側だけで画像化させてみる」 (2014年) や「[JavaScript] 動的SVGからpngを作りたいときはcanvgを使う。Image.src経由だとIEのSecurity Errorが出ちゃう」(2018年) など。 ↩