Skip to content

Instantly share code, notes, and snippets.

@haiiro-shimeji
Last active December 18, 2015 21:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save haiiro-shimeji/5848850 to your computer and use it in GitHub Desktop.
Save haiiro-shimeji/5848850 to your computer and use it in GitHub Desktop.
canvas を用いて選択されたローカルファイルをリサイズし、ajaxで送信するまでのサンプル 選択されたのがイメージファイルでなければそのまま送信する
FileUploadForm = function(form) {
this.form = form;
form.find("input[type=file]").change(this._handleFileInputChanged.bind(this));
this.changeCallback = $.Callbacks();
this.disposeCallback = $.Callbacks();
}
FileUploadForm.prototype = {
form: undefined,
changeCallback: undefined,
disposeCallback: undefined,
uploader: undefined,
_uploader: function(file) {
if (file.type.match('image.*')) {
return new ImageFileUploader(this.form, file);
} else {
return new DefaultFileUploader(this.form, file);
}
},
_handleFileInputChanged: function(event) {
this.uploader = this._uploader(event.target.files[0]);
this.change();
},
change: function(f) {
if (f) {
this.changeCallback.add(f.bind(this));
} else {
this.changeCallback.fire();
}
return this;
},
submit: function(f) {
this.form.submit(f.bind(this));
return this;
},
dispose: function(f) {
if (f) {
this.disposeCallback.add(f.bind(this));
} else {
this.disposeCallback.fire();
}
return this;
}
};
ImageFileUploader = function(form, file) {
this.form = form;
this.file = file;
this.imageData = this._readImageData(file);
};
ImageFileUploader.MAX_SIDE_LENGTH = 960;
ImageFileUploader._calcScaledSize = function(width, height) {
var ratio = width / height;
if (1 < ratio) {
width = Math.min(
width,
ImageFileUploader.MAX_SIDE_LENGTH
);
height = width / ratio;
} else {
height = Math.min(
height,
ImageFileUploader.MAX_SIDE_LENGTH
);
width = height * ratio;
}
return {
width: width,
height: height
};
};
ImageFileUploader.prototype = {
form: undefined,
file: undefined,
imageData: undefined, ///<$.Deferred base64 format scaled image
_readImageData: function(file) {
var imageData = $.Deferred();
var reader = new FileReader();
reader.onload = function(e) {
imageData.resolve(e.target.result);
};
reader.readAsDataURL(file);
return imageData
.then(function(data) {
var d = $.Deferred();
var img = new Image();
img.src = data;
img.onload = function() {
d.resolve(this);
};
return d.promise();
})
.then((function(img) {
var dim = ImageFileUploader._calcScaledSize(img.width, img.height);
var canvas = $("<canvas>")
.css({
position: 'absolute',
right: 0,
top: 0
})
.attr("width", dim.width)
.attr("height", dim.height);
this.form.append(canvas);
var d = $.Deferred();
//一旦実行コンテキストを変えてcanvas要素の追加がされた後でないと
//image描画が行えない
setTimeout(function() {
d.resolve(img, canvas, dim);
}, 0);
return d.promise();
}).bind(this))
.then(function(img, canvas, dim) {
var ctx = canvas.get(0).getContext('2d');
ctx.drawImage(img, 0, 0, dim.width, dim.height);
var data = canvas.get(0).toDataURL("image/jpeg");
canvas.remove();
return data;
})
.promise();
},
_base64ToBlob: function(base64Image) {
var barr, bin, i, len;
bin = atob(base64Image.split("base64,")[1]);
len = bin.length;
barr = new Uint8Array(len);
i = 0;
while (i < len) {
barr[i] = bin.charCodeAt(i);
i++;
}
return new Blob([barr], {
type: 'image/jpeg'
});
},
/**
* returns formData
* @return $.Deferred
*/
formData: function() {
return $.when(this.imageData)
.then((function(data) {
return this._base64ToBlob(data);
}).bind(this))
.then((function(data) {
var formData = new FormData();
//firefoxでは第3引数にかかわらずfilename="blob"にされてしまう
formData.append('file', data, this.file.name);
return formData;
}).bind(this));
},
/**
* returns preview img object
* @return $.Deferred
*/
preview: function() {
return $.when(this.imageData)
.then((function(data) {
var img = new Image();
img.src = data;
img.alt = this.file.name;
return img
}).bind(this));
}
};
DefaultFileUploader = function(form, file) {
this.form = form;
this.file = file;
};
DefaultFileUploader.prototype = {
form: undefined,
file: undefined,
/**
* returns formData
* @return $.Deferred
*/
formData: function() {
return $.Deferred().resolve(new FormData(this.form.get(0)));
},
/**
* returns preview img object
* @return $.Deferred
*/
preview: function() {
var img = new Image();
img.src = ''; //ファイルアイコンとか出す
img.alt = this.file.name;
return $.Deferred().resolve(img);
}
}
<html>
<head>
<titile>File upload test</titile>
<script src="http://code.jquery.com/jquery-2.0.0.min.js"></script>
<script type="text/javascript" src="file_uploader.js"></script>
<script type="text/javascript">
$(function() {
new FileUploadForm($("#form"))
.change(function() {
$("#preview").empty();
this.uploader.preview()
.then(function(img) {
$("#preview").append($(img));
});
})
.submit(function() {
this.uploader.formData()
.then(function(formData) {
return $.ajax({
url: './upload.html',
type: 'POST',
processData: false,
contentType: false,
data: formData,
dataType: 'json'
});
})
.then(
function() {
//success
},
function() {
//error
}
);
return false;
});
});
</script>
</head>
<body>
<form id="form" action="#" method="POST">
<input type="file" name="file">
<input type="submit" name="submit" value="Submit">
</form>
<div id="preview">
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment