2012年6月28日木曜日

ブラウザ上でラスタ画像をsvgに変換する

ラスタ形式の画像を単色のベクタ画像に変換するアプリケーションとしてはpotraceがお手軽だけれど,これをjavascriptに移植している方がいた.動作サンプルを見るに抽出した輪郭データをcanvas要素に描いていたが,これをsvgに応用するスクリプトを書いてみた.

つづき

面倒なので,サンプルページは作らないけれど,potrace.jsを読み込ませた環境で下記のスクリプトを実行すると,img要素の内容がsvg要素に変換されてブラウザに表示されるというもの.


from http://commons.nicovideo.jp/material/nc943
  • 画像に1pxの枠線をつけるようにcanvas要素に描画する.(これを忘れると無限ループに陥る)
  • Potraceにこのcanvas要素を渡してパス情報文字列を取得する.
  • パス情報文字列にはベジェ曲線を描くための頂点・制御点情報が含まれているので,これをsvgのd操作文字列に変換する.
canvas要素にはorigin-cleanフラグに関わる動作制限が存在するため,利用できる環境は限られてしまうかもしれないけれど,割合簡単に変換できるので結構便利だと思う.それよりも元のコードがGPLってところがネックかもしれない.

※元のコードをチューニングしたら実行速度が凡そ半分にできてしまった.
※元のコードにバグを発見してしまった・・・
    window.onload = function(){
     
     //img要素を取得する.
     var img = document.getElementById("img");
     var width = img.width;
     var height = img.height;
     var margin = 1;
     
     //canvas要素を生成する.
     var canvas = document.createElement("canvas");
     canvas.width = width + margin * 2;
     canvas.height = height + margin * 2;
     
     //canvas要素にimg要素の画像を描画する.
     var ctx = canvas.getContext("2d");
     ctx.fillStyle = "white";
     ctx.fillRect(0,0, canvas.width, canvas.height);//白い枠線を引く
     ctx.drawImage(img, margin, margin, width, height);
     
     //Potraceにパラメータを設定する.
     //※パラメータの詳細な意味はよく判っていない…
     Potrace.setParam({
      threshold:0.5,
      turdSize:3,
      turnPolicy:1,
      alphamax:0.9
     });
     
     //パス文字列を取得する.
     var pathStr = Potrace.traceCanvas(canvas).outpath();
    
     //svgのd操作文字列に変換する.
     pathStr = pathStr.replace(/m/g,"M");
     pathStr = pathStr.replace(/\sm/g," Z M");
     pathStr = pathStr.replace(/l/g,"L");
     pathStr = pathStr.replace(/q/g,"Q");
     pathStr = pathStr.replace(/b/g,"C");
     pathStr += " Z";
     
     //svg要素を生成する.
     var SVG_NS = "http://www.w3.org/2000/svg";
     var svg = document.createElementNS(SVG_NS, "svg");
     svg.setAttribute("width", width);
     svg.setAttribute("height", height);
     //枠線の分だけviewBoxをずらす.
     svg.setAttribute("viewBox", [-margin, -margin, width, height].join(" "));
     var path = document.createElementNS(SVG_NS, "path");
     path.setAttribute("d", pathStr);
     path.setAttribute("fill", "orange");
     svg.appendChild(path);
     
     //img要素の前にsvg要素を挿入する.
     img.parentNode.insertBefore(svg, img);
    };

    0 件のコメント:

    コメントを投稿