JavascriptでJPEG画像からEXIFのOrientation情報のみを取得する

2015-08-10

Javascriptを使ってクライアントサイドで画像を縮小する場合に必要となるOrientation情報を、最小のコードと処理でJPEG画像から取得する関数を作りました。

クライアントサイドで画像を縮小してプレビューし、アップロードすることで通信帯域やサーバの負荷を抑えるJavascriptは比較的簡単に作れます。しかしiPhoneで試してみるとなんか変な状態になってしまいました。調べてみるとiOS6でメガピクセル画像をCanvasに描画するとおかしくなってしまう件と、その対処というページを見つけて、iPhone側に問題がありそうで、解決策も提示されているようです。

そこで必要となるのが、画像の正しい方向(回転とか鏡像とか)なのですが、JPEG内のEXIF情報に書き込まれているっぽいです。EXIF情報を取得するためのJavascriptコードもいろいろあるのですが、EXIF全体を読むため汎用的に作られていて、コードが大きくて処理も冗長な感じです。必要なのはOrientationのみなので、それに特化した関数を作ってみました。

EXIFのOrientationのみを取得するJavascript関数

function getOrientation(imgDataURL){
   var byteString = atob(imgDataURL.split(',')[1]);
   var orientaion = byteStringToOrientation(byteString);
   return orientaion;

   function byteStringToOrientation(img){
      var head = 0;
      var orientation;
      while (1){
         if (img.charCodeAt(head) == 255 & img.charCodeAt(head + 1) == 218) {break;}
         if (img.charCodeAt(head) == 255 & img.charCodeAt(head + 1) == 216) {
            head += 2;
         }
         else {
            var length = img.charCodeAt(head + 2) * 256 + img.charCodeAt(head + 3);
            var endPoint = head + length + 2;
            if (img.charCodeAt(head) == 255 & img.charCodeAt(head + 1) == 225) {
               var segment = img.slice(head, endPoint);
               var bigEndian = segment.charCodeAt(10) == 77;
               var count;
               if (bigEndian) {
                  count = segment.charCodeAt(18) * 256 + segment.charCodeAt(19);
               } else {
                  count = segment.charCodeAt(18) + segment.charCodeAt(19) * 256;
               }
               for (i=0; i < count; i++){
                  var field = segment.slice(20 + 12 * i, 32 + 12 * i);
                  if ((bigEndian && field.charCodeAt(1) == 18) || (!bigEndian && field.charCodeAt(0) == 18)) {
                     orientation = bigEndian ? field.charCodeAt(9) : field.charCodeAt(8);
                  }
               }
               break;
            }
            head = endPoint;
         }
         if (head > img.length){break;}
      }
      return orientation;
   }
}

この関数の入力値は、JPEGファイルをbase64エンコードしたDataURL形式にしています。これはHTML5のFileReaderでローカルファイルを読み出すときに一番使いやすい形式です。

JavaScript