How to Resize Image Proportionally using JavaScript

We’re continuing a series of “How-to’s” for JavaScript beginners. In this tutorial we will explain how to proportionally resize images. Most tutorials that we have written utilize JavaScript platforms other than MooTools, so we decided to create this one using Mootools, however the function which will resize image’s size can be used with any framework (i.e. jQuery, ExtJS, script.aculo.us or just plain JavaScript.)
We will just use an <img /> tag to resize the images. The actual task of resizing an image proportionally is quite simple, but the most important thing is to calculate the size properly. At first, you should define the size of the bounding box (the maximum size of your image). Let’s say it will be 200×200 pixels:

And we have a photo with a size larger than the bounding box (size 500×313 pixels):

After the image resize we should get something like this:

So that the width of the image will be 200 pixels and height will proportionally scale and become 125 pixels. The image will look smaller, but it keeps its proportions and will still look good.
Now let’s discuss how we will be implementing this in the code. Since we may want to reuse the code at some point in the future, it is best to create a function. First, it is smart to think of all the ways it could be used, how it will work, how you will call the function and also to determine input and output values. A little thought at this time will make the coding task simpler and ensure a more flexible product.
Input parameters of the function will be: maxW, maxH (these parameters will set the size of the bounding box) and currW, currH (these parameters will contain current or original size of the image. In our sample it’s 500×313 pixels). The function will calculate size and return an array containing two values. Usage of the function will be:
var newSize = scaleSize(200, 200, 500, 313); alert('New Width: ' + newSize[0] + ', New Height: ' + newSize[1]);
Now let’s implement the algorithm of the scaleSize function. The logic is simple. You just determine the widest side (for landscape photos it will be width and for portrait photos it will be height), then set the size of bounding box to it and calculate the size of the opposite side using the following formula:
For width: currH / currH / currW;
For height: currW * currH / currW;
You will notice that currH / currW expression repeats in both calculations. This is a ratio of height to width. So, here is the actual implementation of the function:
function scaleSize(maxW, maxH, currW, currH){ var ratio = currH / currW; if(currW >= maxW && ratio <= 1){ currW = maxW; currH = currW * ratio; } else >if(currH >= maxH){ currH = maxH; currW = currH / ratio; } return [currW, currH]; }
That’s it ;) Click the Demo button to view the code in action.





jared
November 10, 2009
this is a good article i been looking for one like it, but will it work with my jQuery code?
ajaxBlender.com
November 10, 2009
Sure, as mentioned in the tutorial it can be used with any framework since it’s just a plain JavaScript function. We just chose to use the MooTools for the demo script.
karev
December 21, 2009
it is possible to make this script resize all the tag in html page automatically ???
Darren – ajaxBlender
December 22, 2009
Yes, sure here is a quick code. It will adjust size of all images with class “resize-me” to a bounding box of 120×120 pixels:
window.addEvent(’domready’, function(){
$each($$(’IMG.resize-me’), function(imgObj){
var newSize = scaleSize(120, 120, imgObj.width, imgObj.height);
imgObj.width = newSize[0];
imgObj.height = newSize[1];
});
});
Don’t forget to include the code for the ’scaleSize()’ function mentioned in the tutorial.
Karen
February 22, 2010
I feel like an idiot. I am trying to implement the above so that I can use the .resize-me class. I added the class to my image and included the following in the header:
window.addEvent(’domready’, function(){
$each($$(’IMG.resize-me’), function(imgObj){
var newSize = scaleSize(120, 120, imgObj.width, imgObj.height);
imgObj.width = newSize[0];
imgObj.height = newSize[1];
});
});
function scaleSize(maxW, maxH, currW, currH){
var ratio = currH / currW;
if(currW >= maxW){
currW = maxW;
currH = currW * ratio;
} else if(currH >= maxH){
currH = maxH;
currW = currH / ratio;
}
return [currW, currH];
}
Am I missing something?
Darren – ajaxBlender
February 22, 2010
Karen, can you please provide a URL to the above code? We will review and troubleshoot, to provide a fix. Thanks!
gene
April 5, 2010
this code does not seem to work with portrate images
e.g. scaleSize(80,80,225,300) will result in [120,160]
gene
April 5, 2010
should be:
scaleSize(120,120,225,300) will result in [120,160]
sorry for the typo.
gene
April 5, 2010
function scaleSize(maxW, maxH, currW, currH){
var img_ratio = currH / currW;
var box_ratio = maxH /maxW;
if(img_ratio = maxW){
currW = maxW;
currH = currW * img_ratio;
} else if(currH >= maxH){
currH = maxH;
currW = currH / img_ratio;
}
}
else
{
if(currH >= maxH){
currH = maxH;
currW = currH / img_ratio;
} else if(currW >= maxW){
currW = maxW;
currH = currW * img_ratio;
}
}
return [currW, currH];
}
ajaxBlender.com
April 6, 2010
Yes, you are right. Thank you for your comment, however this can be solved much easier:
The condition in ’scaleSize’ function:
if(currW >= maxW){
should be just changed to:
if(currW >= maxW && ratio <= 1){
Thanks,
Alex
gene
April 6, 2010
actually there are other corner cases that this logic does not account for.
for example if container box is 100×400, and image is 400×500 then your function will return 320×400.
i found that it’s needed to compare aspect ratio of the image to the aspect ratio of the container box to properly decide which side to constrain by.
something like
function scaleSize(maxW, maxH, currW, currH){
var img_ratio = currH / currW;
var box_ratio = maxH /maxW;
if(img_ratio
ajaxBlender.com
April 7, 2010
Gene,
Yes you’re right, but there is a shorter, more optimized method for ratio calculation and will work for all cases: ratio = Math.Min(maxW / currW, maxH / currH);
Let us know if any other issues.
Thanks,
Alex
Jeff
July 1, 2010
Hi, I’m trying to convert this to use jQuery but am not having any luck. Can someone tell me what’s missing?
$(document).ready(function() {
var img = $(’image-landscape’);
var initW = img.width, initH = img.height;
$(’.controls LI A’).each(function(el, i){
$(el).click(function(e){
e = new Event(e).stop();
var newW = img.width, newH = 0;
switch(el.rel){
case ‘zoomOut’:
newW -= 20;
break;
case ‘zoomIn’:
newW += 20;
break;
case ‘resizeProportionally’:
var newSize = scaleSize(200, 200, $(el.rev).width, $(el.rev).height);
$(el.rev).width = newSize[0];
$(el.rev).height = newSize[1];
return;
default:
newW = initW;
}
var ratio = initH / initW;
newH = newW * ratio;
img.width = newW;
img.height = newH;
});
});
});
ajaxBlender.com
July 7, 2010
Jeff,
Thanks for your comment. I see several issues with the code.
First, you should change $(’image-landscape’) to $(’.image-landscape’) so that jQuery will search for a proper IMG object with the class ‘image-landscape’.
And code such as ‘img.height’ will not work with jQuery. You may want to change it to img.height()
Thanks,
Alex
Jeff
July 8, 2010
Here’s what I have so far. I’m able to get the initial width and height now (thanks!) but can’t get the click events to fire.
$(document).ready(function() {
var img = $(’#image-landscape’);
var initW = img.width(), initH = img.height();
$(’.controls LI A’).each(function(el, i){
$(el).click(function(e){
alert(’test’);
e = new Event(e).stop();
var newW = img.width(), newH = 0;
switch(el.rel){
case ‘zoomOut’:
alert(’zoomOut’);
newW -= 20;
break;
case ‘zoomIn’:
alert(’zoomIn’);
newW += 20;
break;
default:
newW = initW;
}
var ratio = initH / initW;
newH = newW * ratio;
img.width() = newW;
img.height() = newH;
});
});
});
-
+
Reset
ajaxBlender.com
July 15, 2010
Jeff,
In jQuery, you should process it differently. For example:
$('.controls LI A').click(function(){alert('Link has been clicked.');
return false;
});
Try it and let me know if it is okay.
Thanks,
Alex