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