Subscribe to our RSS

How to Resize Image Proportionally using JavaScript

Tags: , , ,

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:

bounding-box

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

sample-image

After the image resize we should get something like this:

resized-image

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 &amp;&amp; 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

Leave a comment

Your name

September 3, 2010

Spam protection. Enter letters you see in the box below.