Image resizing client-side with JavaScript before upload to the server

JavascriptImageResizeClient Side

Javascript Problem Overview


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?

Javascript Solutions


Solution 1 - Javascript

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)

Solution 2 - Javascript

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/

Solution 3 - Javascript

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.

Solution 4 - Javascript

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:

  1. 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.
  2. Be careful about resize algorithm. The most of client side resizers use trivial math, and result is worse than it could be.
  3. You may need to sharpen downscaled image.
  4. 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.

Solution 5 - Javascript

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.

Solution 6 - Javascript

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>

Solution 7 - Javascript

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.

Solution 8 - Javascript

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiongeraudView Question on Stackoverflow
Solution 1 - JavascriptdcollienView Answer on Stackoverflow
Solution 2 - JavascriptJeremy UsherView Answer on Stackoverflow
Solution 3 - JavascriptignacioView Answer on Stackoverflow
Solution 4 - JavascriptVitalyView Answer on Stackoverflow
Solution 5 - JavascriptDavid V.View Answer on Stackoverflow
Solution 6 - JavascriptGabriel Ambrósio ArchanjoView Answer on Stackoverflow
Solution 7 - Javascriptxarlymg89View Answer on Stackoverflow
Solution 8 - JavascriptTatarizeView Answer on Stackoverflow