[JavaScript]iPhoneで撮った写真を投稿すると回転してしまうのをサクッと直す

  • 16
    いいね
  • 0
    コメント

どんな感じになるのか

なぜか、縦で撮った画像が、横になってしまう...
image

ここから、iPhoneで撮った写真を選択してみてください。
http://runstant.com/simiraaaa/projects/e9efe5c7
縦で撮った写真だと90度回転します。

回転しないようにするサンプル

使用したライブラリ

https://github.com/blueimp/JavaScript-Load-Image
このライブラリのv2.6.2をrawgit.comのcdn化サービスを使って下記のURLから読み込みます。
https://cdn.rawgit.com/blueimp/JavaScript-Load-Image/v2.6.2/js/load-image.all.min.js

サンプル

http://runstant.com/simiraaaa/projects/loadImageExifOrientation
ここから、iPhoneで撮った写真を選択してみてください。
回転せずに、表示されると思います。

コードの説明

HTML部分

<head>タグ内でライブラリを読み込みます。


<!-- 省略 -->
<script src="https://cdn.rawgit.com/blueimp/JavaScript-Load-Image/v2.6.2/js/load-image.all.min.js"></script>
<!-- 省略 -->

<body>タグ内は、ファイル選択用の<input type="file">と、表示用の<div>が書いてあります。



<div>
  <label>iPhoneで縦向きに撮った写真を選択してください。
    <input type="file" name="file" id="file" />
  </label>
</div>
<div id="dst">
  <p>画像クリックで別ウィンドウで開く</p>

</div>

CSS部分

あんまり関係ないですが、大きい画像がそのまま表示されると見えないので、widthを300pxになるようにしてます。



canvas {
  width: 300px;
}

Script部分

コメントに細かく書いてあるので、ザックリ流れを説明します。

  1. まず、window.onload の中で処理をしています。
  2. input[file]onchange で画像ファイルが選択された時、3へ
  3. load 関数に画像が読み込み終わったら、div#dstcanvas を追加する関数を渡します。
  4. load 関数では、まず、回転してるか調べるために loadImage.parseMetaData を実行します。
  5. 回転に関する情報は、 exif というデータの中に格納されているので、 exif がある場合だけ、回転させるオプションをセットします。
  6. loadImage 関数を呼び出して、画像の読み込みが完了すると、3.の canvas を追加する関数が呼び出されます。


onload = function() {
  var input = document.getElementById('file');
  var dst = document.getElementById('dst');

  input.onchange = function() {
    // 選択中のファイルの一つ目
    var file = this.files[0];
    // ファイルを選択しなかった場合
    if(!file) return;
    // ファイル形式
    console.log(file.type);
    // ファイル形式の中にimageが含まれない場合
    if(!/image/.test(file.type)) {
      alert('画像を選択してください。');
      return;
    }

    // 読み込み用の関数で読み込み完了時に、HTMLにcanvas追加
    load(file, function(canvas) {
      dst.appendChild(canvas);

      // canvas がクリックされた時に、別ウィンドウで画像を開く
      canvas.onclick = function() {
        open(this.toDataURL('image/png'));
      };
    });

  };

  function load(file, callback) {
    // canvas: true にすると canvas に画像を描画する(回転させる場合は必須オプション)
    var options = {canvas: true};

    loadImage.parseMetaData(file, function (data) {
      if (data.exif) {
        console.log("exifに格納されている情報:\n", data.exif.getAll());

        // options の orientation は小文字。 exif.getの 'Orientation' は先頭大文字
        // ここでcanvasの回転を指定している
        options.orientation = data.exif.get('Orientation');
        console.log('Orientation: ' + options.orientation);
      }
      // 画像の読み込み。完了時に callback が呼び出される
      loadImage(file, callback, options);
    });
  }
};

canvasで出てきてるので、サーバに送るときは、FormData APIや、canvas.toDataURL()などで、画像データを送ってやれば、回転してない画像が登録できると思います。(サーバ側での処理に合わせて、適切な方法で送信してください)

回転する原因

Script部分の説明でも出てきたexifに含まれる、Orientationという回転を表すデータが原因です。
exifについては、私も詳しくは理解できていませんが、jpeg画像の最初の方のバイト列に格納されているようです。
画像を表示できるアプリの多くは、このexifによって、表示の仕方が変わっていて、Orientationがあれば、自動的に指定された角度で回転して表示しているのではないかと思います。

ブラウザだとiPhoneの<img>タグを除いては、基本的にOrientationによる回転は自動的にはされないので、そこを自分で実装する必要があるということだと思っています。

また、exifのOrientationに回転の指定があれば、iPhoneに限らず、デジカメなどで撮った写真でも発生する現象だと思います。

この辺りは曖昧なので、間違ってる部分があれば、指摘していただけるとありがたいです。