読者です 読者をやめる 読者になる 読者になる

はしくれエンジニアもどきのメモ

情報・Web系技術の勉強メモ・備忘録です。

SVG画像を canvgでCanvas に変換してみる

Canvas SVG

SVG画像を canvgでCanvas に変換してみる

SVG画像を canvgでCanvas で扱えるように変換してみたのでメモ。

canvg とは

SVGコードをCanvas用のコードへ変換してくれるJavaScriptライブラリです。 MITライセンスで、GitHubにも挙がってます。 

gabelerner/canvg · GitHub

今回使用したのは、こちらのcanvasgで作られているWebサービスです。 SVGコードを貼り付けると、Canvasでpreview し、かつCanvas用のコードを返してくれます。

Professor Cloud

類似ツール

SVGのようなベクターデータをCanvas コードに変換してれる類似ツールはいくつかあるので、 まとめておきます。

  • Drawscript

    Illustrator のプラグイン。 Creativei Cloud 利用できる環境でインストールできるようです。 Illusrtror で描いたデータをCanvasやCreateJSのコードに変換できます。

  • Toolkit for CreateJS

    Flash のプラグインです。 Flashで生成したデータを CreateJS(Canvas)のコードへ変換できます。 CreateJSでアニメーションを作るときに、コード直書きするよりもこっちのほうが使われていそう。

  • ink2canvas

    Inkscape の拡張機能としてインストールできるようです。 3, 4年前から更新が止まっているようなので使うのは難しいかもしれません。

サンプル

以下のInkscapeで描いたSVG画像を、Canvas用のコードに変化したいと思います。

image/svg+xml
描いたSVG

ちなみコードは、以下の様になっています。


  <svg
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:cc="http://creativecommons.org/ns#"
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns:svg="http://www.w3.org/2000/svg"   xmlns="http://www.w3.org/2000/svg"
  version="1.1"
  id="svg2"
  viewBox="0 0 225 225"
  height="225"
  width="225">
  <defs
   id="defs4" />
  <metadata
   id="metadata7">
  <rdf:RDF>
    <cc:Work
       rdf:about="">
      <dc:format>image/svg+xml</dc:format>
      <dc:type
         rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
      <dc:title></dc:title>
    </cc:Work>
  </rdf:RDF>
  </metadata>
  <g
   style="display:inline"
   transform="translate(-178,-203.56851)"
   id="layer1" />
  <g
   transform="translate(-0.5,0.57940674)"
   style="display:inline;opacity:1"
   id="layer2">
  <circle
     r="110"
     cy="111.92059"
     cx="113"
     id="path3336"
     style="opacity:1;fill:#ffff00;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
  </g>
  <g
   transform="translate(-0.5,0.57940674)"
   id="layer4">
  <path
     d="m 163,173.19968 a 50,21.087877 0 0 1 -25,18.26263 50,21.087877 0 0 1 -50.000001,0 A 50,21.087877 0 0 1 63,173.19968"
     id="path4157"
     style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
  </g>
  <g
   transform="translate(-0.5,0.57940674)"
   style="display:inline"
   id="layer3">
  <g
     id="layer5">
    <circle
       r="20"
       cy="100.36712"
       cx="77.318108"
       id="path3338"
       style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
  </g>
  <g
     style="display:inline"
     id="layer7">
    <circle
       r="20"
       cy="100.36712"
       cx="155.5"
       id="path3338-4"
       style="display:inline;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
  </g>
  </g>
</svg>

変換した結果はこちら。

codepen.io

生成されたCanvasコードは以下です。


var draw = function(ctx) {
  ctx.save();
  ctx.beginPath();
  ctx.moveTo(0,0);
  ctx.lineTo(225,0);
  ctx.lineTo(225,225);
  ctx.lineTo(0,225);
  ctx.closePath();
  ctx.clip();
  ctx.translate(0,0);
  ctx.translate(0,0);
  ctx.scale(1,1);
  ctx.translate(0,0);
  ctx.strokeStyle = 'rgba(0,0,0,0)';
  ctx.lineCap = 'butt';
  ctx.lineJoin = 'miter';
  ctx.miterLimit = 4;
  ctx.save();
  ctx.restore();
  ctx.save();
  ctx.translate(-178,-203.56851);
  ctx.restore();
  ctx.save();
  ctx.translate(-0.5,0.57940674);
  ctx.globalAlpha = 1;
  ctx.save();
  ctx.fillStyle = "#ffff00";
  ctx.strokeStyle = "#000000";
  ctx.lineWidth = 5;
  ctx.miterLimit = 4;
  ctx.globalAlpha = 1;
  ctx.beginPath();
  ctx.arc(113,111.92059,110,0,6.283185307179586,true);
  ctx.closePath();
  ctx.fill();
  ctx.stroke();
  ctx.restore();
  ctx.restore();
  ctx.save();
  ctx.translate(-0.5,0.57940674);
  ctx.save();
  ctx.fillStyle = "rgba(0, 0, 0, 0)";
  ctx.strokeStyle = "#000000";
  ctx.lineWidth = 5;
  ctx.miterLimit = 4;
  ctx.globalAlpha = 1;
  ctx.beginPath();
  ctx.moveTo(163,173.19968);
  ctx.translate(113.0000000000029,173.19967280611772);
  ctx.rotate(0);
  ctx.scale(1,0.42175754);
  ctx.arc(0,0,50,3.4110317058144965e-7,1.0471975511615463,0);
  ctx.scale(1,2.3710305214697525);
  ctx.rotate(0);
  ctx.translate(-113.0000000000029,-173.19967280611772);
  ctx.translate(112.9999995,173.19967292786933);
  ctx.rotate(0);
  ctx.scale(1,0.42175754);
  ctx.arc(0,0,50,1.0471975396495925,2.094395113940201,0);
  ctx.scale(1,2.3710305214697525);
  ctx.rotate(0);
  ctx.translate(-112.9999995,-173.19967292786933);
  ctx.translate(112.99999999999727,173.1996730496196);
  ctx.rotate(0);
  ctx.scale(1,0.42175754);
  ctx.arc(0,0,50,2.0943951254871433,3.1415923239985117,0);
  ctx.scale(1,2.3710305214697525);
  ctx.rotate(0);
  ctx.translate(-112.99999999999727,-173.1996730496196);
  ctx.fill();
  ctx.stroke();
  ctx.restore();
  ctx.restore();
  ctx.save();
  ctx.translate(-0.5,0.57940674);
  ctx.save();
  ctx.save();
  ctx.fillStyle = "#000000";
  ctx.strokeStyle = "rgba(0, 0, 0, 0)";
  ctx.lineWidth = 5;
  ctx.miterLimit = 4;
  ctx.globalAlpha = 1;
  ctx.beginPath();
  ctx.arc(77.318108,100.36712,20,0,6.283185307179586,true);
  ctx.closePath();
  ctx.fill();
  ctx.stroke();
  ctx.restore();
  ctx.restore();
  ctx.save();
  ctx.save();
  ctx.fillStyle = "#000000";
  ctx.strokeStyle = "rgba(0, 0, 0, 0)";
  ctx.lineWidth = 5;
  ctx.miterLimit = 4;
  ctx.globalAlpha = 1;
  ctx.beginPath();
  ctx.arc(155.5,100.36712,20,0,6.283185307179586,true);
  ctx.closePath();
  ctx.fill();
  ctx.stroke();
  ctx.restore();
  ctx.restore();
  ctx.restore();
  ctx.restore();
};

SVGの実際に図形を描いているのは40行で、 それに対して、生成されたCanvasコードでは100行近くあります。。

今回のSVGは顔、目2つでcircle3つ、口でpath1つだったので、 口以外は、Canvasでarc 3つと translate の組み合わせだけでできると思っていたのですが、 予想以上に複雑になりました。 間に入ってくるctx.rotate(0); は冗長のような気もします。 簡単な図形は、SVG見ながら自分で書き換えたほうが良さそうです。 何かトレースしてノードだらけの複雑な図形であればこのツール使っても良さそうです。