LoginSignup
12
10

More than 5 years have passed since last update.

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

Last updated at Posted at 2016-09-17

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

  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 を使用してファイルを読み取る

指定領域内に画像を表示させるときは、imgLiquid が一番楽そうでした。
imgLiquidの使い方は、こちらこちらを参考にしてみてください。

画像プレビュー

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

2. iPhone/iPad 使用時に発生する画像の傾きを修正

スマートフォンではファイルを選択をタップすると、カメラを直接起動して撮ったものを反映することも出来ます。
が、iPhone/iPadで撮影したものはすべて横向きで表示されてしまいます。

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

exif-js

画像のEXIF情報にある撮影方向の向きを調べます。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を使います(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はこんな感じです。

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

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

まとめ

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

12
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
10