I'm a server-side dev learning the ropes of client side manipulation, starting with pure JS.
Currently I'm using pure JS to resize the dimensions of images uploaded via the browser.
I'm running into a situation where downsizing a 1018 x 1529 .jpg
file to a 400 x 601 .jpeg
is producing a file with a bigger size (in bytes). It goes from 70013
bytes to 74823
bytes.
My expectation is that there ought to be a size reduction, not inflation. What is going on, and is there any way to patch this kind of a situation?
Note: one point that especially perplexes me is that each image's compression starts without any prior knowledge of the target's previous compressions. Thus, any quality level below 100 should further degrade the image. This should accordingly always decrease the file size. But that strangely doesn't happen?
If required, my relevant JS code is:
var max_img_width = 400;
var wranges = [max_img_width, Math.round(0.8*max_img_width), Math.round(0.6*max_img_width),Math.round(0.4*max_img_width),Math.round(0.2*max_img_width)];
function prep_image(img_src, text, img_name, target_action, callback) {
var img = document.createElement('img');
var fr = new FileReader();
fr.onload = function(){
var dataURL = fr.result;
img.onload = function() {
img_width = this.width;
img_height = this.height;
img_to_send = resize_and_compress(this, img_width, img_height, "image/jpeg");
callback(text, img_name, target_action, img_to_send);
}
img.src = dataURL;
};
fr.readAsDataURL(img_src);
}
function resize_and_compress(source_img, img_width, img_height, mime_type){
var new_width;
switch (true) {
case img_width < wranges[4]:
new_width = wranges[4];
break;
case img_width < wranges[3]:
new_width = wranges[4];
break;
case img_width < wranges[2]:
new_width = wranges[3];
break;
case img_width < wranges[1]:
new_width = wranges[2];
break;
case img_width < wranges[0]:
new_width = wranges[1];
break;
default:
new_width = wranges[0];
break;
}
var wpercent = (new_width/img_width);
var new_height = Math.round(img_height*wpercent);
var canvas = document.createElement('canvas');//supported
canvas.width = new_width;
canvas.height = new_height;
var ctx = canvas.getContext("2d");
ctx.drawImage(source_img, 0, 0, new_width, new_height);
return dataURItoBlob(canvas.toDataURL(mime_type),mime_type);
}
// converting image data uri to a blob object
function dataURItoBlob(dataURI,mime_type) {
var byteString = atob(dataURI.split(',')[1]);
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);//supported
for (var i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); }
return new Blob([ab], { type: mime_type });
}
If warranted, here's the test image I've used:
Here's the image's original location.
Note that for several other images I tried, the code did behave as expected. It doesn't always screw up the results, but now I can't be sure that it'll always work. Let's stick to pure JS solutions for the scope of this question.