Image resizing client-side with JavaScript before upload to the server
I am looking for a way to resize an image client-side with JavaScript (really resize, not just change width开发者_开发知识库 and height).
I know it's possible to do it in Flash but I would like to avoid it if possible.Is there any open source algorithm somewhere on the web?
Here's a gist which does this: https://gist.github.com/dcollien/312bce1270a5f511bf4a
(an es6 version, and a .js version which can be included in a script tag)
You can use it as follows:
<input type="file" id="select">
<img id="preview">
<script>
document.getElementById('select').onchange = function(evt) {
ImageTools.resize(this.files[0], {
width: 320, // maximum width
height: 240 // maximum height
}, function(blob, didItResize) {
// didItResize will be true if it managed to resize it, otherwise false (and will return the original file as 'blob')
document.getElementById('preview').src = window.URL.createObjectURL(blob);
// you can also now upload this blob using an XHR.
});
};
</script>
It includes a bunch of support detection and polyfills to make sure it works on as many browsers as I could manage.
(it also ignores gif images - in case they're animated)
The answer to this is yes - in HTML 5 you can resize images client-side using the canvas element. You can also take the new data and send it to a server. See this tutorial:
http://hacks.mozilla.org/2011/01/how-to-develop-a-html5-image-uploader/
If you were resizing before uploading I just found out this http://www.plupload.com/
It does all the magic for you in any imaginable method.
Unfortunately HTML5 resize only is supported with Mozilla browser, but you can redirect other browsers to Flash and Silverlight.
I just tried it and it worked with my android!
I was using http://swfupload.org/ in flash, it does the job very well, but the resize size is very small. (cannot remember the limit) and does not go back to html4 when flash is not available.
http://nodeca.github.io/pica/demo/
In modern browser you can use canvas to load/save image data. But you should keep in mind several things if you resize image on the client:
- You will have only 8bits per channel (jpeg can have better dynamic range, about 12 bits). If you don't upload professional photos, that should not be a problem.
- Be careful about resize algorithm. The most of client side resizers use trivial math, and result is worse than it could be.
- You may need to sharpen downscaled image.
- If you wish do reuse metadata (exif and other) from original - don't forget to strip color profile info. Because it's applied when you load image to canvas.
Perhaps with the canvas tag (though it's not portable). There's a blog about how to rotate an image with canvas here, I suppose if you can rotate it, you can resize it. Maybe it can be a starting point.
See this library also.
You can use a javascript image processing framework for client-side image processing before uploading the image to the server.
Below I used MarvinJ to create a runnable code based on the example in the following page: "Processing images in client-side before uploading it to a server"
Basically I use the method Marvin.scale(...) to resize the image. Then, I upload the image as a blob (using the method image.toBlob()). The server answers back providing a URL of the received image.
/***********************************************
* GLOBAL VARS
**********************************************/
var image = new MarvinImage();
/***********************************************
* FILE CHOOSER AND UPLOAD
**********************************************/
$('#fileUpload').change(function (event) {
form = new FormData();
form.append('name', event.target.files[0].name);
reader = new FileReader();
reader.readAsDataURL(event.target.files[0]);
reader.onload = function(){
image.load(reader.result, imageLoaded);
};
});
function resizeAndSendToServer(){
$("#divServerResponse").html("uploading...");
$.ajax({
method: 'POST',
url: 'https://www.marvinj.org/backoffice/imageUpload.php',
data: form,
enctype: 'multipart/form-data',
contentType: false,
processData: false,
success: function (resp) {
$("#divServerResponse").html("SERVER RESPONSE (NEW IMAGE):<br/><img src='"+resp+"' style='max-width:400px'></img>");
},
error: function (data) {
console.log("error:"+error);
console.log(data);
},
});
};
/***********************************************
* IMAGE MANIPULATION
**********************************************/
function imageLoaded(){
Marvin.scale(image.clone(), image, 120);
form.append("blob", image.toBlob());
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://www.marvinj.org/releases/marvinj-0.8.js"></script>
<form id="form" action='/backoffice/imageUpload.php' style='margin:auto;' method='post' enctype='multipart/form-data'>
<input type='file' id='fileUpload' class='upload' name='userfile'/>
</form><br/>
<button type="button" onclick="resizeAndSendToServer()">Resize and Send to Server</button><br/><br/>
<div id="divServerResponse">
</div>
In my experience, this example has been the best solution for uploading a resized picture: https://zocada.com/compress-resize-images-javascript-browser/
It uses the HTML5 Canvas feature.
The code is as 'simple' as this:
compress(e) {
const fileName = e.target.files[0].name;
const reader = new FileReader();
reader.readAsDataURL(e.target.files[0]);
reader.onload = event => {
const img = new Image();
img.src = event.target.result;
img.onload = () => {
const elem = document.createElement('canvas');
const width = Math.min(800, img.width);
const scaleFactor = width / img.width;
elem.width = width;
elem.height = img.height * scaleFactor;
const ctx = elem.getContext('2d');
// img.width and img.height will contain the original dimensions
ctx.drawImage(img, 0, 0, width, img.height * scaleFactor);
ctx.canvas.toBlob((blob) => {
const file = new File([blob], fileName, {
type: 'image/jpeg',
lastModified: Date.now()
});
}, 'image/jpeg', 1);
},
reader.onerror = error => console.log(error);
};
}
There are two downsides with this solution.
The first one is related with the image rotation, due to ignoring EXIF data. I couldn't tackle this issue, and wasn't so important in my use case, but will be glad to hear any feedback.
The second downside is the lack of support foe IE/Edge (not the Chrome based version though), and I won't put any time on that.
Yes, with modern browsers this is totally doable. Even doable to the point of uploading the file specifically as a binary file having done any number of canvas alterations.
http://jsfiddle.net/bo40drmv/
(this answer is a improvement of the accepted answer here)
Keeping in mind to catch process the result submission in the PHP with something akin to:
//File destination
$destination = "/folder/cropped_image.png";
//Get uploaded image file it's temporary name
$image_tmp_name = $_FILES["cropped_image"]["tmp_name"][0];
//Move temporary file to final destination
move_uploaded_file($image_tmp_name, $destination);
If one worries about Vitaly's point, you can try some of the cropping and resizing on the working jfiddle.
精彩评论