Canvas + File API + Drag&Drop API で Instagram みたいな画像フィルターを作ってみた
Instagram の画像フィルターみたいことを HTML5 (Canvas + File API + Drag&Drop API) で実装してみました。
Instagram みたいなの - jsdo.it - Share JavaScript, HTML5 and CSS
動作するブラウザは FireFox 3.6、Chrome 8 開発版です。(Chrome 7 は File API はサポートしていますが、どうやら iframe 内では動作しないため、上記 jsdo.it 上では動作しません。)
やっていること
解説
Drag & Drop
dragover, drop イベントに対してイベントリスナーを設定します。
ファイルデータは drop イベントの event.dataTranfer.files 配列から取り出します。1つしかファイルをドロップしなくても、配列で戻ってくる点だけ注意。
window.addEventListener('dragover', function(event) { event.preventDefault(); // ブラウザのデフォルトの画像表示処理をOFF }, false); window.addEventListener('drop', function(event) { event.preventDefault(); // ブラウザのデフォルトの画像表示処理をOFF // 先頭のファイルを取り出します。 var file = event.dataTransfer.files[0]; // ファイルタイプ(MIME)で対応しているファイルか判定 var fileType = file.type; if (!fileType.match(/image\/\w+/)){ alert('画像ファイル以外は利用できません'); return; } }
File API を利用して、DATA URL 形式に変換する
個々のファイルは FileReader オブジェクトを利用して読み込みます。readAsDataURL メソッドを利用して読み込むことで、ファイルを DATA URL 形式に変換することをができます。変換結果は、FileReader の onload メソッド中で result プロパティから取得することができます。
var reader = new FileReader(); reader.onload = function() { currentImage = new Image(); currentImage.onload = function() { var normal = document.getElementById('normal'); normal.click(); drawImage(this, imageWidth, imageHeight); }; currentImage.src = reader.result; // 画像を DATA URL 経由で表示 }; reader.readAsDataURL(file); }, false);
Canvas でピクセルデータを取得、変換、設定
getImageData でピクセルデータを管理する ImageData オブジェクトが取得できます。各ピクセルのデータ配列は、ImageData の data プロパティから取得します。RGBA の4バイトの配列から構成されるので、配列長は width * height * 4 になります。
createImageData で画像処理したデータの出力先 ImageData を作成し、画像フィルターで ImageData の data プロパティにデータを書き込みます。
画像処理した ImageData を、putImageData で Canvas に書き戻すことで、画像処理結果を表示することができます。
var canvas = document.getElementById('canvas'); var context = canvas.getContext('2d'); var cw = canvas.width; var ch = canvas.height; // Canvas から ImageData オブジェクトの取得 var inputData = context.getImageData(0, 0, cw, ch); // 出力バッファの作成 var outputData = context.createImageData(cw, ch); // ピクセルデータは ImageData の data プロパティから取得 var src = inputData.data; var dest = outputData.data; // フィルターによる画像処理 filter(src, dest, cw, ch); // 加工データを Canvas に書き出し context.putImageData(outputData, 0, 0); };
画像フィルターの例(反転フィルター)
var invertFilter = function(src, dest, width, height) { var size = width * height * 4; for (var i=0; i<size; i+=4) { dest[i+0] = 255 - src[i+0]; dest[i+1] = 255 - src[i+1]; dest[i+2] = 255 - src[i+2]; dest[i+3] = src[i+3]; } };