angularjsクライアントで画像ファイルを圧縮してアップロード


主にhtml 5のcanvasを利用して画像の圧縮を行い、dataURLに変換し、dataURLをBlobファイルに変換することで、Blobオブジェクトを直接Formdataに付与することができる.
app.service('Util', function($q) {
   var dataURItoBlob = function(dataURI) {
        // convert base64/URLEncoded data component to raw binary data held in a string
        var byteString;
        if (dataURI.split(',')[0].indexOf('base64') >= 0)
            byteString = atob(dataURI.split(',')[1]);
        else
            byteString = unescape(dataURI.split(',')[1]);

        // separate out the mime component
        var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];

        // write the bytes of the string to a typed array
        var ia = new Uint8Array(byteString.length);
        for (var i = 0; i < byteString.length; i++) {
            ia[i] = byteString.charCodeAt(i);
        }

        return new Blob([ia], {
            type: mimeString
        });
    };

    var resizeFile = function(file) {
        var deferred = $q.defer();
        var img = document.createElement("img");
        try {
            var reader = new FileReader();
            reader.onload = function(e) {
                img.src = e.target.result;

                //resize the image using canvas
                var canvas = document.createElement("canvas");
                var ctx = canvas.getContext("2d");
                ctx.drawImage(img, 0, 0);
                var MAX_WIDTH = 800;
                var MAX_HEIGHT = 800;
                var width = img.width;
                var height = img.height;
                if (width > height) {
                    if (width > MAX_WIDTH) {
                        height *= MAX_WIDTH / width;
                        width = MAX_WIDTH;
                    }
                } else {
                    if (height > MAX_HEIGHT) {
                        width *= MAX_HEIGHT / height;
                        height = MAX_HEIGHT;
                    }
                }
                canvas.width = width;
                canvas.height = height;
                var ctx = canvas.getContext("2d");
                ctx.drawImage(img, 0, 0, width, height);

                //change the dataUrl to blob data for uploading to server
                var dataURL = canvas.toDataURL('image/jpeg');
                var blob = dataURItoBlob(dataURL);

                deferred.resolve(blob);
            };
            reader.readAsDataURL(file);
        } catch (e) {
            deferred.resolve(e);
        }
        return deferred.promise;

    };
    return {
        resizeFile: resizeFile
    };

});

現在angualrjsではmultiform dataによるファイルのアップロードはしばらくサポートされていないため、formdataのファイルをアップロードするには以下のコードを利用します.
app.controller('CompanyCtrl', function($http, Util) {

        Util.resizeFile(input.files[0]).then(function(blob_data) {
            var fd = new FormData();
            fd.append("imageFile", blob_data);
            $http.post('http://your.domain.com/upload', fd, {
                headers: {'Content-Type': undefined },
                transformRequest: angular.identity
            })
                .success(function(data) {
                    $scope.model.company_pict = data[0];
                })
                .error(function() {
                    console.log("uploaded error...")
                });
        }, function(err_reason) {
            console.log(err_reason);
        });


}