2016年3月16日水曜日

JavascriptでBase64方式の画像データを判定する

Three.jsでテクスチャ用の画像ファイルを読み込んだときに、画像ファイルの種類を判定したかったので、そのときに調べたことをまとめる。

Three.jsでテクスチャの画像をローカルにある画像に変更するドラッグ&ドロップでThree.jsのテクスチャ画像を入れ替えるでファイルを読み込むと、FILEオブジェクトを取得できるのでFILE.typeでMIMEタイプがわかる。はじめはこれで判定しようとしたが、どうもこのMIMEタイプは拡張子で判別されているようで心もとない。

読み込んだ画像ファイルをFileReader オブジェクトでデータURI形式として読み込む処理はすでに作成済みで、データURI形式で読み込むと画像ファイルはBase64方式になる。そこで、読み込んだファイルの先頭部分のBase64方式データを比較して画像の種類を判定することにした。

Base64は、バイナリデータを64種類の英数字のみでテキストデータに変換する方式で、3バイトのデータが4文字に変換される。Base63についてはBase64についてを参照。

pngの場合、先頭8バイトは固定の16進数89 50 4E 47 0D 0A 1A 0Aになる。先頭の3バイトをBase64に変換するとiVBOという文字列になるので、Base64方式のデータの先頭4文字を読み込んでiVBOと一致したらpngと判定するような処理をすることで、FILEオブジェクトのMIMEタイプを参照するよりは正確な判定ができる。

実際にpng画像を読み込んだときのデータURI形式の中身を見ると以下のようになっている。iVBO以降が画像データ。カンマ以降を画像データか判定すればよさそう。

data:image/png;base64,iVBORw0KGgoAAAA...

ドラッグ&ドロップでThree.jsのテクスチャ画像を入れ替えるでpng画像しかテクスチャ画像として使えないようにして、png以外のファイルがドロップされたときにアラートメッセージを表示するには、以下のようにtextureSwitchを書き換える。

function textureSwitch( event ){
// 要素内イベントのキャンセル
event.preventDefault();
// 1つ目のファイルのみ読み込む
var file = event.dataTransfer.files[0];

// FileReader オブジェクトの作成
var reader = new FileReader();

reader.onload = function( event ) {
// ファイルデータの先頭位置を取得
var startImg = 1 + event.target.result.indexOf( ',' );
// 先頭4文字分を取得
var buffer = event.target.result.slice( startImg, startImg+4);
// pngの先頭部分と一致するか判定
if( buffer.indexOf( 'iVBO' ) == -1) {
alert( 'Invalid file' );
} else {
// 「img」でエレメントオブジェクト作成
var img = document.createElement( 'img' );
img.src = event.target.result;
// テクスチャの更新
cube.material.map = new THREE.Texture( img );
cube.material.map.needsUpdate = true;
}
};
// データURLとしてファイルを読み込む
reader.readAsDataURL( file );
}
 
 

0 件のコメント:

コメントを投稿