JavaScriptで画像のEXIFデータを読み取るには、Javascript EXIF Reader が便利だ。jQuery版も用意されていて、これを使うとサーバにある画像のEXIFデータを、クライアントサイドで抽出することができる。
このプラグインは内部的にbinaryajax.jsで画像を取得している関係上、ブラウザの「クロスドメイン」制約を受ける。すなわち、スクリプトと画像が同じドメインに配置されている場合は問題なく動作するが、今回のように画像ファイルが別ドメインにあるようなケースではうまく動かない。(Picasaなどでは、置いてある画像のEXIFデータを、サーバ側で取り出してクライアントに返すサービスを有している。)
そこで、今回は「ローカルPCにある画像のEXIFデータを抽出する」Webアプリを作る。サーバにある画像を表示する際は、このアプリで予め生成したEXIFデータを使う。すなわち、
(1) ローカルPCにある画像の諸情報(含むEXIFデータ)を抽出し、「画像情報ファイル」を生成 (本記事のテーマ)
(2) 画像情報ファイルとスクリプトをサーバにアップロード
(3) 画像をリモートサーバ((2)とは別)にアップロード
(4) スクリプト実行 – ブラウザが画像と画像情報ファイルを読み込み、両者を合わせて表示
という段取りを想定する。
ここで作るアプリはfirefoxでは動作する(2013年2月時点)が、chromeでは動作しない。これは、chromeはローカルファイルを別ドメインとして認識することが原因。この仕様は一般的になっていくと予想されるので、将来的には、
・画像ファイルとスクリプトを同じドメインに配置する。(いったん画像情報ファイルを作ってしまえば移動してもOK。)
・Picasaのように画像本体とExif情報を個別に返してくれるサービスを利用する。
といった対応が必要。
- 画像ファイルを選択する
- 選択された画像を表示する
読み込んだ画像をブラウザに表示する。画像ごとにイベントハンドラの処理を変えるため、クロージャの記述方法を変更した。具体的には、EXIF抽出処理に備えて、画像ごとに異なる#idを付与している。(以下の例では、固定文字列’xxx’に、ループカウンタ i の値を連結し、各画像に’xxx0′,’xxx1′…というidを付けている。)
reader.onload = function(event){ var tag = '<img src='+ event.target.result+ ' width="100" id="xxx' + i + '">'; $('#imgarea').append(tag); // ... }
EXIFデータの抽出には、$(img).exifLoad(),$(img).exifAll()を使う。MakerNoteはメーカーごとに内容が異なっており、またサイズが大きいため今回は利用しない。
$('#xxx' + num).exifLoad(function(){ // 各画像(異なるidを有する)からEXIFデータをロード var exif = $('#xxx' + num).exifAll(); exif[0].MakerNote = 'MakerNote'; // MakerNoteは解析できないので捨てる imgData.item[num].exif = exif[0]; // 結果を全体のデータ領域にコピー checkExifComplete(); // 画像ごとのEXIF抽出処理完了を確認(非同期処理対応) });
EXIF情報抽出処理は非同期的に行われる(*)。全画像の処理完了を知るために、先の処理の中でcheckExifComplete()をコールしている。この関数で、グローバルのカウンタを+1していき、処理対象となる画像数と一致したタイミングで、画像情報ファイルを作成する。また、ダウンロード用のリンクを有効にする。
(*)非同期処理のため、ループが回り終わったタイミングではEXIFデータは空になっている。
参考にしたサイト:
NihilogicLabs : Javascript EXIF Reader
ピンバック: 画像表示アプリの作成(5) – EXIFデータの表示 | Try Lifelog