--- title: アップロード画像のプレビュー表示をキレイにする tags: jQuery JavaScript HTML CSS author: enta0701 slide: false --- 最近Webアプリを作成したときにググった、画像表示についての備忘録です。 実現したかったのは2つ。 1. アップロード画像を指定領域(px)内いっぱいに表示(プレビュー) 2. iPhone/iPad で発生する画像の傾きを修正(EXIF情報とどう向き合うか) ###最低限のHTML ```index.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], //画像1つのみ選択 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で撮影したものはすべて横向きで表示されてしまいます。 アップロードするのみであればPHP等で処理してもいいのですが、今回はプレビューでも表示させたかったのでそのあたりもJSでどうにかします。 ###exif-js 画像のEXIF情報にある撮影方向の向きを調べます。[exif-js](https://github.com/exif-js/exif-js)が便利です。 ```select-image.js --- var file = this.files[0], //画像1つのみ選択 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 `には1から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` に直接、回転を修正した画像があたるように変更しました。 ##まとめ コードは汚いですが実現したいものは一応出来たので、これでよしとします。 ツッコミ大歓迎です!