nmi.jp Twitter → @tkihira
CanvasをSVGで利用する方法 スマートフォン実機デバッグ: JSConsoleを使ってみる

SVGをCavnasで利用する方法


2011-05-16
Takuo Kihira

SVGの描画内容をCanvasで利用するのは、CanvasをSVGで利用するのに比べて幾分か大変です。

(CanvasをSVGで利用する方法はこちら

Operaでは、

ctx.drawImage(svg, 0, 0);

という書き方が許されるのですが、残念ながらFirefoxやChrome、Safariといった他のメジャーなブラウザではこの方法は対応しておりません(そもそも仕様違反です)。というわけで、ちょっとひねった方法を使う必要があります。

<!DOCTYPE html>
<html><head><title>SVGをCanvasで利用する</title>
<script>
var svg = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n' +
            '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">' +
            '<g transform="matrix(0.0298614501953125,-0.0054168701171875,0.0054168701171875,0.0298614501953125,79.8,32.25)">' +
            '<path stroke="none" fill="rgb(0,0,0)" d="M -2782.7569658689836 608.6833301566228 L 84.893028645503 1128.8753322274672 ' +
            'L 1683.7664050978372 132.97224006629114 L -858.0511140648059 -328.1137176765489 L 181.5633642527544 -1047.0521235003948 ' +
            'L -275.57473549460883 -1129.9770215128187 L -2782.7569658689836 608.6833301566228 M -1951.5829286777084 429.60166597823917 ' +
            'L -1237.2442827046566 -65.36827816052792 L 795.561309788937 303.38286406493205 L 19.622494346381792 787.1785311665641 ' +
            'L -1951.5829286777084 429.60166597823917 "/></g></svg>';
 
window.onload = function() {
    var img = new Image();
    img.onload = function() {
        var ctx = document.getElementById("canvas").getContext("2d");
        ctx.drawImage(img, 0, 0);
    };
    img.src = "data:image/svg+xml;base64," + btoa(svg);
};
</script></head><body><canvas id="canvas" width="150" height="100"></canvas></body></html>

コードの簡単な説明をします。

  • 4行目から11行目までは、SVGの文字列です。Canvasで扱うには文字列にしなければいけません。
  • 14行目でimgエレメントを作成し、19行目でソースに先程のSVGをbase64で指定します。
    btoa・atobはbase64に変換する関数で、Canvasをサポートしている大抵のブラウザに組み込まれています
  • 15行目~18行目は、読みこんだ後にCanvasにコピーしています。imgはimgエレメントなので、ここの部分を
     document.body.appendChild(img); 
    とやっても問題なく動きます。

このように、data:を使って画像ファイルとして埋め込むのがポイントです。

実行結果はこちらです。

既にDOM上に出来たSVGを読む場合は、次のURLのコードが参考になると思います。
http://www.svgopen.org/2010/papers/62-From_SVG_to_Canvas_and_Back/index.html
下記、転載です(varの付け忘れとセミコロンの付け忘れを補完しました)。

function importSVG(sourceSVG, targetCanvas) {
    // https://developer.mozilla.org/en/XMLSerializer
    var svg_xml = (new XMLSerializer()).serializeToString(sourceSVG);
    var ctx = targetCanvas.getContext('2d');
 
    // this is just a JavaScript (HTML) image
    var img = new Image();
    // http://en.wikipedia.org/wiki/SVG#Native_support
    // https://developer.mozilla.org/en/DOM/window.btoa
    img.src = "data:image/svg+xml;base64," + btoa(svg_xml);
 
    img.onload = function() {
        // after this, Canvas’ origin-clean is DIRTY
        ctx.drawImage(img, 0, 0);
    };
}

XMLSerializerも、大抵のブラウザで使用可能だと思います。ただ、このコードで気をつけなくてはいけないのは、XMLSerializerは一部のSVGのDOMに対してnamespaceを付与しないことがあります。xlinkなどが特にその犠牲になることがあるので、そのまま読み込むことが出来ない場合は一度シリアライズされたXMLをそのままブラウザで読めるかどうか確認してみてください。

また、一度SVGからCanvasに描画をしてしまうと、そのCanvasではgetImageData関数が使えなくなります。その詳細については先程のページに詳しく書いてありますが、下記のページにも日本語でのコメントが書いてありますので、気になる方は参考にしてみてください。
http://d.hatena.ne.jp/gyuque/20110510