Hatena::ブログ(Diary)

Webと文字

よければ、はてブしてください。( ´∀`) George.Nagaoka@gmail.com

JavaScript IME:海外からブラウザで日本語を変換 新URL 旧URL:
多言語入力ブックマークレット:ブラウザでロシア語、中国語、アラビア語・・・
【軍曹が】携帯電話開発の現状【語る】をAA化した
AAのデータベース
趣味のページ

2011-07-24

potraceをjavascriptに移植した

生存報告

 ( ^ω^)とりあえず生きてます。

potraceとは

 potraceとはラスター画像からSVG等のベクター画像を作成するソフトです。無料で使えてソースも公開されているオープンソースなソフトです(参考資料1)。元はCで書かれていますが、pythonActionScriptC#に移植されていたりします。

だから何ができるの?

左が元のビットマップ画像、右がそれをpotraceでトレースした画像

f:id:project_the_tower2:20110724103343p:image

C→javascript(´・ω・`)ActionScriptJavaScript(゚∀゚)

 ActionScriptJavaScriptは兄弟みたいなものなので移植はとっても簡単です。今回は参考資料2をパクって参考にしてjavascriptに移植してみました。

処理フロー

  1. imgタグで画像を読み込み
  2. 画像をcanvasに転写
  3. 画像をグレースケールに変換
  4. 画像を二値化
  5. 画像の輪郭の数だけpathを取得(potrace)
  6. よく分からない処理をしてベジェ曲線のポイントリストを作成(potrace)
  7. ベジェ曲線canvasに描画

6のよく分からない処理は参考資料1のTechnical documentationのpdfを見てください。私は見てもさっぱりでした。(;^ω^)

コード

上記の処理フローの6番は参考資料2のActionScriptと全く同じです。

canvasにフィルターをかける

 canvasからイメージのピクセルを取得したり、設定したりする方法は参考資料3に載っています。contextからgetImageDataするとピクセルのrgbaが並んで入った配列が得られます。結果として配列の長さはピクセル数×4となります。

 このピクセルデータに対してactionscriptのColorMatrixFilter(参考資料4)+applyfilterと同様の処理をするスクリプトが以下です。ピクセルデータdataに対してrectの範囲でフィルターfをかけます。

applyFilter:function(rect,pt,f){
	for(var y=rect.y; y < rect.y +rect.height;y++){
		for(var x = rect.x;x < rect.x + rect.width;x++){
			var r =this._data.data[x*4 +y*this.width*4],
				g = this._data.data[x*4 +y*this.width*4+1] ,
				b = this._data.data[x*4 +y*this.width*4+2] ,
				a = this._data.data[x*4 +y*this.width*4+3];
			this._data.data[x*4 +y*this.width*4] = r*f[0] + g*f[1] + b*f[2] +a*f[3]+f[4]; //Rnew
			this._data.data[x*4 +y*this.width*4+1] = r*f[5] + g*f[6] + b*f[7] +a*f[8]+f[9]; //Gnew
			this._data.data[x*4 +y*this.width*4+2] = r*f[10] + g*f[11] + b*f[12] +a*f[13]+f[14]; //Bnew
			this._data.data[x*4 +y*this.width*4+3] = r*f[15] + g*f[16] + b*f[17] +a*f[18]+f[19]; //Anew
		}
	}
},
画像のグレースケールと二値化

 上記のapplyfilterに以下のフィルターをかけます。

var filter = [
	0.298912, 0.586611, 0.114478, 0, 0,
	0.298912 ,0.586611, 0.114478 ,0 ,0,
	0.298912 ,0.586611, 0.114478 ,0 ,0,
	0 , 0, 0, 1, 0
];

 この後、rgbのいずれかのピクセル値に対してしきい値をとると画像を二値化できます。

XOR

 画像を二値化すると色は白と黒だけになり、この状態で反転させるとお互いの領域が逆転します。これをパスのぐるりでやると以下のようにパスで囲まれた黒の領域が消滅します。この時、パスで囲まれた白の領域は反転して黒となり、パス化されるのを待ちます。

□■■■□
□□■■□
□□■■□
□■■■□

■■■■□
■■■■□ ↓
□□■■□
□■■■□

■■■■□
■■■■□
■■■■□
■■■■□ ↓

■■■■□
■■■■□
□□□□□ ↑
□□□□□ 

□□□□□ ↑
□□□□□
□□□□□ 
□□□□□ 

実際のサンプル

 以下の画像のようにトレースすることが出来ました。対応ブラウザFireFoxchromesafari、IE9です。

f:id:project_the_tower2:20110724103344p:image

URL:http://www28095u.sakura.ne.jp/jstrace/(追記 2013/06/28 Chromeで動かなくなってしまいました。サンプルは下記の追記を参照してください)

実際のサンプルの注意点

もっさりしているのは仕様です。おそらくこれ以上劇的には早くなりません。画像は最低でも1pxの白い枠取りがされている必要があります。ローカルに保存しても動きません。画像はインターネットから拝借いたしました。コードはnitoyon氏とPeter Selinger.氏がすべての権利を有します。

追記 2013/06/28 サンプルコード

defghi1977氏によりコードの高速化とサンプルの補充が行われました。感謝。

 http://www.h2.dion.ne.jp/~defghi/img2svg/potraceHtml.htm

参考資料

  1. http://potrace.sourceforge.net/
  2. nitoyon/PotrAs - Spark project
  3. createImageData, getImageData, putImageData メソッド - Canvasリファレンス - HTML5.JP
  4. voglia.jp - AS3:ColorMatrixFilterを使いこなす

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証