LoginSignup
8
12

More than 5 years have passed since last update.

アップロード画像をjsで圧縮してEXIFを見て回転して表示・POSTする

Last updated at Posted at 2016-05-16

概要

フォームで画像をアップロードする際,圧縮・EXIF-Orientationを見て回転したうえで,送信・プレビューしたい場合がある。
input-fileで画像を受け取り,圧縮したdataUrlに変換することを考える。
また画像は,今回はただ圧縮するのではなく,正方形になるようにcropしてる。(この辺は,canvasをいじればいろいろできる)

依存

jquery https://github.com/jquery/jquery
exif-js https://github.com/exif-js/exif-js

要点

1.formObjectをBlobURLに変換
2.BlobURLをimageObjectに変換
3.imageObjectを圧縮して回転してcropしてdataUrlにて出力(canvas利用)

ソース

sample.html
<!DOCTYPE html>
<html lang="ja">
<head>
<script type="text/javascript" src="jquery-1.12.3.min.js"></script>
<script type="text/javascript" src="exif.js"></script>
<script type="text/javascript">
(function($) {

    $.fileImageViewer = function() {

        // base64dataURLから圧縮したbase64dataURLを生成
        function resizeImage(src, size, callback) {
            var img = new Image();
            img.onload = function() {
                EXIF.getData(img, function() {
                    var dst = _resize(img, size)
                    callback(dst);
                    img = null; // for leak
                });
            };
            img.src = src;
            return;
        }

        // imageObjectから圧縮したbase64dataURLを生成
        function _resize(img, compressSize) {
            var exif = img.exifdata.Orientation
            var raw_width = img.width;
            var raw_height = img.height;
            var canvas = document.createElement('canvas');
            canvas.width = compressSize;
            canvas.height = compressSize;
            var ctx = canvas.getContext('2d');
            ctx.translate(canvas.width / 2, canvas.height / 2);
            switch (exif) {
            case 1:
                break;
            case 2: // vertical flip
                ctx.scale(-1, 1);
                break;
            case 3: // 180 rotate left
                ctx.rotate(Math.PI);
                break;
            case 4: // horizontal flip
                ctx.scale(1, -1);
                break;
            case 5: // vertical flip + 90 rotate right
                ctx.rotate(0.5 * Math.PI);
                ctx.scale(1, -1);
                break;
            case 6: // 90 rotate right
                ctx.rotate(0.5 * Math.PI);
                break;
            case 7: // horizontal flip + 90 rotate right
                ctx.rotate(0.5 * Math.PI);
                ctx.scale(-1, 1);
                break;
            case 8: // 90 rotate left
                ctx.rotate(-0.5 * Math.PI);
                break;
            default:
                break;
            }
            var dx = -canvas.width / 2;
            var dy = -canvas.height / 2;
            var dw = canvas.width;
            var dh = canvas.height;
            var sx = Math.max((raw_width - raw_height) / 2, 0);
            var sy = Math.max((raw_height - raw_width) / 2, 0);
            var sw = Math.min(raw_height, raw_width);
            var sh = Math.min(raw_height, raw_width);
            ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh);
            var url = canvas.toDataURL('image/jpeg');
            ctx = null;
            canvas = null;
            return url;
        }

        return {
            resizeImage : resizeImage
        }
    };

})(jQuery);
</script>
<script type="text/javascript">
    $(function() {
        var $viewer = $('#picture');
        var $file   = $('#file');

        $file.change(function(){
            var file = $file[0].files[0];
            if(!file) return;
            var src = window.URL.createObjectURL(file); // blob file
            $.fileImageViewer().resizeImage(src, 100, function(dst){
                $viewer.attr("src", dst);
            });
        });
    });
</script>
</head>
<body>
    <img src="" id="picture">
    <input type="file" accept="image/*" id="file">
</body>
</html>

改善点

・formObject->BlobURL->imageObject->dataURLと変換を何度も挟んで非効率ではないか?
・スマホでやるとメモリ不足で落ちる時がある。なにか対処法はないか?

ご指摘あればぜひ宜しくお願いします。

8
12
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
8
12