アップロード画像のプレビュー表示をキレイにする

最近Webアプリを作成したときにググった、画像表示についての備忘録です。
実現したかったのは２つ。

1. アップロード画像を指定領域（px）内いっぱいに表示（プレビュー）
2. iPhone/iPad で発生する画像の傾きを修正（EXIF情報とどう向き合うか）


###最低限のHTML
```index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <title>タイトル</title>
    <meta charset="UTF-8">
    <script type="text/javascript"  src="js/jquery-1.12.1.min.js" ></script>
    <script type="text/javascript"  src="js/exif.js" ></script>
    <script type="text/javascript"  src="js/megapix-image.js" ></script>
    <script type="text/javascript"  src="js/imgLiquid-min.js" ></script>
    <script type="text/javascript"  src="js/select-image.js" ></script>
</head>
<body>
    <form enctype="multipart/form-data">
        <input id="file-btn" type="file" name="image" accept="image/*">
    </form>

    <!-- プレビュー表示 -->
    <p class="image-box" style="width:300px; height:200px;">
        <img src="" alt=""/>
    </p>
</body>
</html>
```



##1. アップロード画像を指定領域内いっぱいに表示

ローカルにあるファイルを選択してブラウザに表示させるには、File API と FileReader APIが便利です。

参考；[JavaScript で File API を使用してファイルを読み取る](http://www.html5rocks.com/ja/tutorials/file/dndfiles/#toc-reading-files)

指定領域内に画像を表示させるときは、[imgLiquid](https://github.com/karacas/imgLiquid/blob/master/js/imgLiquid.js) が一番楽そうでした。
imgLiquidの使い方は、[こちら](http://qiita.com/stk2k/items/abb4924741f4fff7249a)や[こちら](http://kwski.net/jquery/1077/)を参考にしてみてください。




###画像プレビュー
```select-image.js
$(function(){
    $('#file-btn').change(function(){
        if (!this.files.length) {
            return;
        }
        var file = this.files[0],           //画像１つのみ選択
            image = $('.image-box'),
            fileReader = new FileReader();

        // 読み込みが完了した際のイベントハンドラ。imgのsrcにデータセット
        fileReader.onload = function(event) {
            // 読み込んだデータをimgに設定
            image.children('img').attr('src', event.target.result);
            // imgLiquid - imgの親要素に指定
			image.imgLiquid();
        };

        // 画像読み込み
        fileReader.readAsDataURL(file);
        
    });
});
```

これでどんな画像のサイズでも、`.image-box` に指定したサイズ内いっぱい(300×200)に画像が表示されるはずです。
※分かりやすいよう赤枠で囲みました

[![https://gyazo.com/d266dbf52489d4e2eb560141afec6453](https://i.gyazo.com/d266dbf52489d4e2eb560141afec6453.png)](https://gyazo.com/d266dbf52489d4e2eb560141afec6453)



##2. iPhone/iPad 使用時に発生する画像の傾きを修正
スマートフォンでは`ファイルを選択`をタップすると、カメラを直接起動して撮ったものを反映することも出来ます。
が、iPhone/iPadで撮影したものはすべて横向きで表示されてしまいます。

<img src="https://i.gyazo.com/3209684b788fe8d6834d3913ebbf7427.png" width="400">

アップロードするのみであればPHP等で処理してもいいのですが、今回はプレビューでも表示させたかったのでそのあたりもJSでどうにかします。

###exif-js
画像のEXIF情報にある撮影方向の向きを調べます。[exif-js](https://github.com/exif-js/exif-js)が便利です。

```select-image.js
---

var file = this.files[0],           //画像１つのみ選択
    image = $('.image-box img'),
    fileReader = new FileReader();

/* 追加 ここから */
var orientation = 0;
EXIF.getData(file, function(){
    orientation = file.exifdata.Orientation;
    if(orientation === undefined){
        orientation = 1;
    }
});
/* 追加 ここまで */

// 読み込みが完了した際のイベントハンドラ。imgのsrcにデータセット
fileReader.onload = function(event) {

---
```

`orientation `には１から8までの数字が入ってきます。
どの数字がどんな意味を表すかは、下の表を参考にしてください。


| Orientation | 修正方法                      |
|-------------|-------------------------------|
| 1           | そのまま                      |
| 2           | 上下反転                   |
| 3           | 180度回転                     |
| 4           | 左右反転                      |
| 5           | 上下反転、時計周りに270度回転 |
| 6           | 時計周りに90度回転            |
| 7           | 上下反転、時計周りに90度回転  |
| 8           | 時計周りに270度回転           |


####ごまかしたところ
たまに`orientation `が上手く取れないことがあるそうなので、そのときは強制的に1（そのまま）にしました


修正方法が分かったものの、自分でcanvas使って回転させて…なんてことする気力はないので、[ios-imagefile-megapixel](https://github.com/stomita/ios-imagefile-megapixel)を使います（iOSとか入ってますが特に意味はないそうです）

select-image.jsを編集します

```select-image.js
---

// 読み込みが完了した際のイベントハンドラ。imgのsrcにデータセット
fileReader.onload = function(event) {
    // 読み込んだデータをimgに設定
    // image.attr('src', event.target.result); 　// 削除

    /*　追加 ここから */
    var mpImg = new MegaPixImage(file);
	mpImg.render(image.children('img')[0], { orientation: orientation });
    /*　追加 ここまで */

    // imgLiquid - imgの親要素に指定
    image.parent().imgLiquid();

};

---
```

これでOK！と思ったのですが、`imgLiquid` が上手く効いてくれなかったので、荒業ですが `megapix-image.js` の236行目辺りを編集します。

```megapix-image.js
---

var tagName = target.tagName.toLowerCase();
    if (tagName === 'img') {
      target.src = renderImageToDataURL(this.srcImage, opt, doSquash);
      /* 追加 ここから */
      target.parentNode.style.backgroundImage = 'url(' + target.getAttribute("src") + ')';
      /* 追加 ここまで */
    } else if (tagName === 'canvas') {
      renderImageToCanvas(this.srcImage, target, opt, doSquash);
    }
    if (typeof this.onrender === 'function') {
    
---
```



`imgLiquid` では、imgタグの画像を指定したセレクタ（.image-box）のスタイルに当てることで、指定領域いっぱいに表示していました。CSSはこんな感じです。

```css
	background-size: cover;
	background-position: center center;
	background-repeat: no-repeat;
	background-image: url(imgの画像);
```

`megapix-image.js`を使うと、imgタグから画像パスの取得が上手くいかないみたいなので、`.image-box`の `background-image` に直接、回転を修正した画像があたるように変更しました。

<img src="https://i.gyazo.com/a6096eac9f0b4da9fc19c360d23187dd.png" width="400"> 

##まとめ
コードは汚いですが実現したいものは一応出来たので、これでよしとします。
ツッコミ大歓迎です！