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

# どんな感じになるのか

なぜか、縦で撮った画像が、横になってしまう...
![image](https://qiita-image-store.s3.amazonaws.com/0/60690/2baf00d7-a696-a024-7320-d312a39d05d3.png)


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


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

## 使用したライブラリ

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>`タグ内でライブラリを読み込みます。

```html

<!-- 省略 -->
<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>`が書いてあります。

```html


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

```

### CSS部分

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

```css


canvas {
  width: 300px;
}

```

### Script部分

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

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


```js


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に限らず、デジカメなどで撮った写真でも発生する現象だと思います。

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