LoginSignup
2
3

More than 1 year has passed since last update.

Canvg v3を使ってブラウザ上でSVGをCanvasに変換する

Last updated at Posted at 2021-04-02

2022年2月18日追記

2022年2月17日にリリースされたCanvg v4.0.0については、以下の記事をご参照ください。

はじめに

ブラウザ上に表示されているSVGをPNG画像としてダウンロードしたいことがあります。その場合
1. Canvgを使ってcanvasにSVGをレンダリング
2. canvas.toDataURL()またはcanvas.toBlob()URL.createObjectURL(blob)を使ってdataURLに変換
3. <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でラップしています。

canvg_v2.0.0.js
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を返すため、以前のようにラップする必要は無くなりました。

canvg_v3.0.7.js
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
}

以上です。


  1. Canvgを使わずともctx.drawImage()の引数に SVGImageElementを渡すことでも画像の変換を行うことができます(例えば、「SVGを画像に変換してダウンロードする方法」)。しかし、SVG中のimageタグで外部の画像を読み込んでいる場合には、この方法では上手くいかないようです。 

  2. 「svg.jsとcanvgを使って、SVGタグ内のオブジェクトをクライアント側だけで画像化させてみる」 (2014年) や「[JavaScript] 動的SVGからpngを作りたいときはcanvgを使う。Image.src経由だとIEのSecurity Errorが出ちゃう」(2018年) など。 

2
3
0

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
2
3