HTML5とJavaScriptでローカル画像をドラッグで画像処理する

あむちょです。

HTML5を使ってアップロードなしで、ブラウザー上で画像処理をしてみました。

PR アプリ作ってます

とりあえずやってみるのが手っ取り早いです。

適当な画像をドラッグでブラウザー内にほうりこんだあと、ボタン押すだけです。サンプル画像は友人のハネムーンの時のやつ。パソコン専用です。

bandicam 2013-07-27 20-38-13-301

Processing

Normalをクリックするとリセットされます。

以下やりかた。

まず、ドラッグによるブラウザーのデフォルトの動作を抑制する

<br />
window.addEventListener(&quot;dragover&quot;,function(event){<br />
    event.preventDefault();<br />
},false);</p>
<p>window.addEventListener(&quot;drop&quot;,function(event){<br />
    event.preventDefault();<br />
},false);<br />

次にFile APIを利用して画像データを所得。上記の”drop”イベントに以下を追加。

<br />
var file=event.dataTransfer.files[0];</p>
<p>var fileType = file.type;<br />
if (!fileType.match(/image\/\w+/)){<br />
    alert(&quot;画像ファイル以外は利用できません&quot;);<br />
    return;<br />
}</p>
<p>var reader = new FileReader();<br />
reader.onload = function(){<br />
    image = new Image();<br />
    image.src=reader.result;<br />
};</p>
<p>reader.readAsDataURL(file);<br />

これで、ドラッグによるイメージオブジェクトが生成できます。

次に、画像データをとり出す。今回は、canvas領域に描画されたものをデータに変換しているので、一度描画する必要があります。

<br />
context.drawImage(image,0,0);</p>
<p>imgData=context.getImageData(0,0,image.width,image.height);<br />

あとは、データを直接、1pxづつ操作して加工します。

まずはセピア

sepia

<br />
sepia = function(){</p>
<p>    var data=imgData.data;<br />
    for(var n=0,len=imgData.width*.imgData.height;n&lt;len;n++){<br />
        var r=data[n*4];<br />
        var g=data[n*4+1];<br />
        var b=data[n*4+2];</p>
<p>        data[n*4]=Math.round(0.393*r+0.769*g+0.189*b);<br />
        data[n*4+1]=Math.round(0.349*r+0.686*g+0.168*b);<br />
        data[n*4+2]=Math.round(0.272*r+0.534*g+0.131*b);<br />
    }</p>
<p>}<br />

反転

hanten

<br />
hanten = function(){</p>
<p>    var data=imgData.data;<br />
    for(var n=0,len=imgData.width*imgData.height;n&lt;len;n++){<br />
        var r=data[n*4];<br />
        var g=data[n*4+1];<br />
        var b=data[n*4+2];</p>
<p>        data[n*4]=255-r;<br />
        data[n*4+1]=255-g;<br />
        data[n*4+2]=255-b;<br />
    }</p>
<p>}<br />

各RGBの値を最大値との差をとるだけです。

モノクロ

mono

<br />
mono = function(){</p>
<p>    var data=imgData.data;<br />
    var rRate=0.34;<br />
    var gRate=0.33;<br />
    var bRate=0.33;</p>
<p>    for(var n=0,len=imgData.width*imgData.height;n&lt;len;n++){<br />
        var r=data[n*4];<br />
        var g=data[n*4+1];<br />
        var b=data[n*4+2];</p>
<p>        data[n*4]=Math.round(rRate*r+gRate*g+bRate*b);<br />
        data[n*4+1]=Math.round(rRate*r+gRate*g+bRate*b);<br />
        data[n*4+2]=Math.round(rRate*r+gRate*g+bRate*b);<br />
     }</p>
<p>}<br />

各RGBの値が等しくなるようにすることで、黒色の濃淡だけになります。

二値化

nichika

<br />
nichi = function(){</p>
<p>    var data=imgData.data;<br />
    var rRate=0.34;<br />
    var gRate=0.33;<br />
    var bRate=0.33;</p>
<p>    for(var n=0,len=this.imgData.width*this.imgData.height;n&lt;len;n++){<br />
        var r=data[n*4];<br />
        var g=data[n*4+1];<br />
        var b=data[n*4+2];<br />
        var elem=Math.round(rRate*r+gRate*g+bRate*b);<br />
        if(elem &gt; 127){<br />
            data[n*4]=255;<br />
            data[n*4+1]=255;<br />
            data[n*4+2]=2555;<br />
        }<br />
        else{<br />
            data[n*4]=0;<br />
            data[n*4+1]=0;<br />
            data[n*4+2]=0;<br />
        }<br />
    }</p>
<p>}<br />

モノクロと似ていますが、閾値を境に最小値か最大値のどちらかの値しかとりません。今回は半分の127を閾値としました。

縦×横ピクセル数だけ処理が繰り返されるので、大きい画像ほど時間が掛かります。変数の宣言とかfor文の外でやっといた方がいいです。

実際のソースはこんな感じ

main.js
img.js

ブラウザー上で画像処理ができるなんて技術の進歩はすごいですね。

API様々です

 

コメント