204

I have images that will be quite big in dimension and I want to shrink them down with jQuery while keeping the proportions constrained, i.e. the same aspect ratio.

Can someone point me to some code, or explain the logic?

Moin Zaman
  • 25,281
  • 6
  • 70
  • 74
kobe
  • 15,671
  • 15
  • 64
  • 91
  • 4
    Can you elaborate why jQuery must be used? There's a CSS-only solution (see [my answer](http://stackoverflow.com/a/12222956/1269037)): set its `max-width` and `max-height` to `100%`. – Dan Dascalescu Aug 31 '12 at 21:59
  • 14
    Just in case anyone doesn't know, if you set only one dimension of the image (either width or height) it's resized proportionaly. It's been this way since the dawn of the web. For example: `` – GetFree Jun 06 '13 at 07:21
  • 2
    Also, you might consider using something like [slimmage.js](http://github.com/imazen/slimmage) to save bandwidth and mobile device RAM. – Lilith River Jul 08 '13 at 16:18

20 Answers20

565

I think this is a really cool method:

 /**
  * Conserve aspect ratio of the original region. Useful when shrinking/enlarging
  * images to fit into a certain area.
  *
  * @param {Number} srcWidth width of source image
  * @param {Number} srcHeight height of source image
  * @param {Number} maxWidth maximum available width
  * @param {Number} maxHeight maximum available height
  * @return {Object} { width, height }
  */
function calculateAspectRatioFit(srcWidth, srcHeight, maxWidth, maxHeight) {

    var ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight);

    return { width: srcWidth*ratio, height: srcHeight*ratio };
 }
Pang
  • 9,564
  • 146
  • 81
  • 122
Jason J. Nathan
  • 7,422
  • 2
  • 26
  • 37
  • 46
    Vastly superior answer! The correct answer falls flat on its face if the height AND the width are both larger. Really, good, also nice moustache. – Starkers Nov 18 '13 at 09:31
  • +1 it's pretty neat. What about declaring the function such as `function calculateAspectRatioFit(dimensions) { /* then use such as dimensions.maxWidth , dimensions.srcWidth ...*/ }`, and then call it such as `function({ maxWidth: someWidth, srcWidth: someOtherWith, maxHeight: someHeight, srcHeight: someOtherHeight });` ? this can be useful to avoid issues with parameters order. – Adriano Nov 04 '14 at 08:07
  • That would be ideal @AdrienBe but this question was answered more than a year ago and I think it is simple enough to adapt to personal customisations. :) – Jason J. Nathan Nov 05 '14 at 17:18
  • How would one use this with a big image? – Riskbreaker Jan 14 '15 at 19:30
  • @Riskbreaker, assuming your max width available is 300px and max height is 400px. I'm just gonna choose random dimensions for the image itself, `var dimensions = calculateAspectRatioFit(3240, 2500, 300, 400);` This way you get an object with the final width and height, simply set the dimensions! if using jquery: `$("#myImage").css({width:dimensions.width, height:dimensions.height})` – Jason J. Nathan Jan 14 '15 at 23:18
  • Great method! Maybe even better if you returned the values rounded: return { width: Math.round(srcWidth*ratio), height: Math.round(srcHeight*ratio) } – sstauross Feb 04 '15 at 10:23
  • @sstauross, I think that the actual number returned would be a better fit since this is going to be visually apparent. Rounding might have unexpected results visually... Still, that would be pretty simple to implement per use case... :) – Jason J. Nathan Feb 24 '15 at 00:50
  • @JasonNathan i agree.. but what about when resize happens in pixels, e.g. having 4.3 px ? – sstauross Mar 03 '15 at 13:24
  • 1
    You're right about that @sstauross, decimal pixels can have slightly [unexpected results](http://jsfiddle.net/q5BQs/3/). In my use case however, it was negligible. I suppose `Math.floor` will really help with a _pixel_ _perfect_ design :-) – Jason J. Nathan Mar 03 '15 at 22:49
  • 10
    This is fantastic way of handling this issue! I tweaked it a bit for img elements + prevent enlarging the image: `function imgSizeFit(img, maxWidth, maxHeight){ var ratio = Math.min(1, maxWidth / img.naturalWidth, maxHeight / img.naturalHeight); img.style.width = img.naturalWidth * ratio + 'px'; img.style.height = img.naturalHeight * ratio + 'px'; }` – oriadam Oct 16 '18 at 06:51
  • 2
    The beauty of this algorithm is that it can be so easily reused in other programming languages. – Queeg May 23 '22 at 10:49
  • Indeed @HiranChaudhuri, I myself have used it in various languages :) – Jason J. Nathan Jun 06 '22 at 05:42
203

Have a look at this piece of code from http://ericjuden.com/2009/07/jquery-image-resize/

$(document).ready(function() {
    $('.story-small img').each(function() {
        var maxWidth = 100; // Max width for the image
        var maxHeight = 100;    // Max height for the image
        var ratio = 0;  // Used for aspect ratio
        var width = $(this).width();    // Current image width
        var height = $(this).height();  // Current image height

        // Check if the current width is larger than the max
        if(width > maxWidth){
            ratio = maxWidth / width;   // get ratio for scaling image
            $(this).css("width", maxWidth); // Set new width
            $(this).css("height", height * ratio);  // Scale height based on ratio
            height = height * ratio;    // Reset height to match scaled image
            width = width * ratio;    // Reset width to match scaled image
        }

        // Check if current height is larger than max
        if(height > maxHeight){
            ratio = maxHeight / height; // get ratio for scaling image
            $(this).css("height", maxHeight);   // Set new height
            $(this).css("width", width * ratio);    // Scale width based on ratio
            width = width * ratio;    // Reset width to match scaled image
            height = height * ratio;    // Reset height to match scaled image
        }
    });
});
Mehdiway
  • 10,337
  • 8
  • 36
  • 68
Moin Zaman
  • 25,281
  • 6
  • 70
  • 74
  • 1
    Sorry, missing some mathematician logic… what's up when you need to increase it all (let's say, you're increasing maxHeight) ? – Ben Aug 25 '11 at 10:12
  • 4
    Can this be done with CSS alone? (max-width, height:auto, etc?) – Tronathan Nov 07 '11 at 20:01
  • 11
    Not sure why jQuery is needed for this. Shrinking the image proportionally on the client can be done with CSS, and it's trivial: just set its `max-width` and `max-height` to `100%`. http://jsfiddle.net/9EQ5c/ – Dan Dascalescu Aug 31 '12 at 21:54
  • 10
    This can not be done with CSS because of the IF STATEMENT. I believe the point is to fill in the thumbnail image. If the image is too tall, it has to be max width, if the image is too wide, it has to be max height. If you do CSS max-width, max-height, you will get thumbnails with whitespace instead of fully filled in – ntgCleaner Mar 14 '13 at 21:38
  • Is this code can cause problems in browsers, crashes or slowed?? – Déjà Bond May 20 '13 at 05:09
  • @Tronathan yes it can be done with CSS alone but there are many older browsers that do not support max-width, max-height – Christopher Tokar Mar 17 '16 at 11:42
  • can the code be optimized? Inside the `if statements` one can just calculate the new `width` and `height` and at the end resizing the image just once – Carlo Mar 31 '16 at 10:36
79

If I understand the question correctly, you don't even need jQuery for this. Shrinking the image proportionally on the client can be done with CSS alone: just set its max-width and max-height to 100%.

<div style="height: 100px">
  <img src="http://www.getdigital.de/images/produkte/t4/t4_css_sucks2.jpg" 
  style="max-height: 100%; max-width: 100%">
</div>​

Here's the fiddle: http://jsfiddle.net/9EQ5c/

Rifky Niyas
  • 1,737
  • 10
  • 25
Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
17

In order to determine the aspect ratio, you need to have a ratio to aim for.

Height

function getHeight(length, ratio) {
  var height = ((length)/(Math.sqrt((Math.pow(ratio, 2)+1))));
  return Math.round(height);
}

Width

function getWidth(length, ratio) {
  var width = ((length)/(Math.sqrt((1)/(Math.pow(ratio, 2)+1))));
  return Math.round(width);
}

In this example I use 16:10 since this the typical monitor aspect ratio.

var ratio = (16/10);
var height = getHeight(300,ratio);
var width = getWidth(height,ratio);

console.log(height);
console.log(width);

Results from above would be 147 and 300

Rick
  • 12,606
  • 2
  • 43
  • 41
7

There are 4 parameters to this problem

  1. current image width iX
  2. current image height iY
  3. target viewport width cX
  4. target viewport height cY

And there are 3 different conditional parameters

  1. cX > cY ?
  2. iX > cX ?
  3. iY > cY ?

solution

  1. Find the smaller side of the target view port F
  2. Find the larger side of the current view port L
  3. Find the factor of both F/L = factor
  4. Multiply both sides of the current port with the factor ie, fX = iX * factor; fY = iY * factor

that's all you need to do.

//Pseudo code


iX;//current width of image in the client
iY;//current height of image in the client
cX;//configured width
cY;//configured height
fX;//final width
fY;//final height

1. check if iX,iY,cX,cY values are >0 and all values are not empty or not junk

2. lE = iX > iY ? iX: iY; //long edge

3. if ( cX < cY )
   then
4.      factor = cX/lE;     
   else
5.      factor = cY/lE;

6. fX = iX * factor ; fY = iY * factor ; 

This is a mature forum, I am not giving you code for that :)

6

actually i have just run into this problem and the solution I found was strangely simple and weird

$("#someimage").css({height:<some new height>})

and miraculously the image is resized to the new height and conserving the same ratio!

WindowsMaker
  • 3,132
  • 7
  • 29
  • 46
4

Does <img src="/path/to/pic.jpg" style="max-width:XXXpx; max-height:YYYpx;" > help?

Browser will take care of keeping aspect ratio intact.

i.e max-width kicks in when image width is greater than height and its height will be calculated proportionally. Similarly max-height will be in effect when height is greater than width.

You don't need any jQuery or javascript for this.

Supported by ie7+ and other browsers (http://caniuse.com/minmaxwh).

sojin
  • 4,527
  • 2
  • 37
  • 40
  • Great tip! Just would put the CSS in a CSS file and not directly in the html code. – Mark Jul 11 '14 at 12:58
  • I think the problem with this is that it won't work when you don't know what the max width and max height is until the page loads. Which is why a JS solution is needed. This is normally the case for responsive sites. – Jason J. Nathan Feb 04 '15 at 07:50
2

Without additional temp-vars or brackets.

    var width= $(this).width(), height= $(this).height()
      , maxWidth=100, maxHeight= 100;

    if(width > maxWidth){
      height = Math.floor( maxWidth * height / width );
      width = maxWidth
      }
    if(height > maxHeight){
      width = Math.floor( maxHeight * width / height );
      height = maxHeight;
      }

Keep in Mind: Search engines don't like it, if width and height attribute does not fit the image, but they don't know JS.

B.F.
  • 477
  • 6
  • 9
2

This should work for images with all possible proportions

$(document).ready(function() {
    $('.list img').each(function() {
        var maxWidth = 100;
        var maxHeight = 100;
        var width = $(this).width();
        var height = $(this).height();
        var ratioW = maxWidth / width;  // Width ratio
        var ratioH = maxHeight / height;  // Height ratio

        // If height ratio is bigger then we need to scale height
        if(ratioH > ratioW){
            $(this).css("width", maxWidth);
            $(this).css("height", height * ratioW);  // Scale height according to width ratio
        }
        else{ // otherwise we scale width
            $(this).css("height", maxHeight);
            $(this).css("width", height * ratioH);  // according to height ratio
        }
    });
});
Ajjaah
  • 141
  • 1
  • 5
2

Here's a correction to Mehdiway's answer. The new width and/or height were not being set to the max value. A good test case is the following (1768 x 1075 pixels): http://spacecoastsports.com/wp-content/uploads/2014/06/sportsballs1.png. (I wasn't able to comment on it above due to lack of reputation points.)

  // Make sure image doesn't exceed 100x100 pixels
  // note: takes jQuery img object not HTML: so width is a function
  // not a property.
  function resize_image (image) {
      var maxWidth = 100;           // Max width for the image
      var maxHeight = 100;          // Max height for the image
      var ratio = 0;                // Used for aspect ratio

      // Get current dimensions
      var width = image.width()
      var height = image.height(); 
      console.log("dimensions: " + width + "x" + height);

      // If the current width is larger than the max, scale height
      // to ratio of max width to current and then set width to max.
      if (width > maxWidth) {
          console.log("Shrinking width (and scaling height)")
          ratio = maxWidth / width;
          height = height * ratio;
          width = maxWidth;
          image.css("width", width);
          image.css("height", height);
          console.log("new dimensions: " + width + "x" + height);
      }

      // If the current height is larger than the max, scale width
      // to ratio of max height to current and then set height to max.
      if (height > maxHeight) {
          console.log("Shrinking height (and scaling width)")
          ratio = maxHeight / height;
          width = width * ratio;
          height = maxHeight;
          image.css("width", width);
          image.css("height", height);
          console.log("new dimensions: " + width + "x" + height);
      }
  }
Tom O'Hara
  • 71
  • 5
2

2 Steps:

Step 1) calculate the ratio of the original width / original height of Image.

Step 2) multiply the original_width/original_height ratio by the new desired height to get the new width corresponding to the new height.

Hitesh Ranaut
  • 751
  • 6
  • 12
2

If the image is proportionate then this code will fill the wrapper with image. If image is not in proportion then extra width/height will get cropped.

    <script type="text/javascript">
        $(function(){
            $('#slider img').each(function(){
                var ReqWidth = 1000; // Max width for the image
                var ReqHeight = 300; // Max height for the image
                var width = $(this).width(); // Current image width
                var height = $(this).height(); // Current image height
                // Check if the current width is larger than the max
                if (width > height && height < ReqHeight) {

                    $(this).css("min-height", ReqHeight); // Set new height
                }
                else 
                    if (width > height && width < ReqWidth) {

                        $(this).css("min-width", ReqWidth); // Set new width
                    }
                    else 
                        if (width > height && width > ReqWidth) {

                            $(this).css("max-width", ReqWidth); // Set new width
                        }
                        else 
                            (height > width && width < ReqWidth)
                {

                    $(this).css("min-width", ReqWidth); // Set new width
                }
            });
        });
    </script>
Anu
  • 37
  • 1
2
$('#productThumb img').each(function() {
    var maxWidth = 140; // Max width for the image
    var maxHeight = 140;    // Max height for the image
    var ratio = 0;  // Used for aspect ratio
    var width = $(this).width();    // Current image width
    var height = $(this).height();  // Current image height
    // Check if the current width is larger than the max
    if(width > height){
        height = ( height / width ) * maxHeight;

    } else if(height > width){
        maxWidth = (width/height)* maxWidth;
    }
    $(this).css("width", maxWidth); // Set new width
    $(this).css("height", maxHeight);  // Scale height based on ratio
});
Pang
  • 9,564
  • 146
  • 81
  • 122
1

After some trial and error I came to this solution:

function center(img) {
    var div = img.parentNode;
    var divW = parseInt(div.style.width);
    var divH = parseInt(div.style.height);
    var srcW = img.width;
    var srcH = img.height;
    var ratio = Math.min(divW/srcW, divH/srcH);
    var newW = img.width * ratio;
    var newH = img.height * ratio;
    img.style.width  = newW + "px";
    img.style.height = newH + "px";
    img.style.marginTop = (divH-newH)/2 + "px";
    img.style.marginLeft = (divW-newW)/2 + "px";
}
dwitvliet
  • 7,242
  • 7
  • 36
  • 62
1

The resize can be achieved(maintaining aspect ratio) using CSS. This is a further simplified answer inspired by Dan Dascalescu's post.

http://jsbin.com/viqare

img{
     max-width:200px;
 /*Or define max-height*/
  }
<img src="http://e1.365dm.com/13/07/4-3/20/alastair-cook-ashes-profile_2967773.jpg"  alt="Alastair Cook" />

<img src="http://e1.365dm.com/13/07/4-3/20/usman-khawaja-australia-profile_2974601.jpg" alt="Usman Khawaja"/>
rush dee
  • 304
  • 1
  • 4
  • 13
0

This issue can be solved by CSS.

.image{
 max-width:*px;
}
banoth ravinder
  • 1,314
  • 15
  • 18
0

Resize to fit the container, get scale factor, scale down percentage control

 $(function () {
            let ParentHeight = 200;
            let ParentWidth = 300;
            $("#Parent").width(ParentWidth).height(ParentHeight);
            $("#ParentHeight").html(ParentHeight);
            $("#ParentWidth").html(ParentWidth);

            var RatioOfParent = ParentHeight / ParentWidth;
            $("#ParentAspectRatio").html(RatioOfParent);

            let ChildHeight = 2000;
            let ChildWidth = 4000;
            var RatioOfChild = ChildHeight / ChildWidth;
            $("#ChildAspectRatio").html(RatioOfChild);

            let ScaleHeight = ParentHeight / ChildHeight;
            let ScaleWidth = ParentWidth / ChildWidth;
            let Scale = Math.min(ScaleHeight, ScaleWidth);

            $("#ScaleFactor").html(Scale);
            // old scale
            //ChildHeight = ChildHeight * Scale;
            //ChildWidth = ChildWidth * Scale;

            // reduce scale by 10%, you can change the percentage
            let ScaleDownPercentage = 10;
            let CalculatedScaleValue = Scale * (ScaleDownPercentage / 100);
            $("#CalculatedScaleValue").html(CalculatedScaleValue);

            // new scale
            let NewScale = (Scale - CalculatedScaleValue);
            ChildHeight = ChildHeight * NewScale;
            ChildWidth = ChildWidth * NewScale;

            $("#Child").width(ChildWidth).height(ChildHeight);
            $("#ChildHeight").html(ChildHeight);
            $("#ChildWidth").html(ChildWidth);

        });
        #Parent {
            background-color: grey;
        }

        #Child {
            background-color: red;
        }
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="Parent">
    <div id="Child"></div>
</div>

<table>
    <tr>
        <td>Parent Aspect Ratio</td>
        <td id="ParentAspectRatio"></td>
    </tr>
    <tr>
        <td>Child Aspect Ratio</td>
        <td id="ChildAspectRatio"></td>
    </tr>
    <tr>
        <td>Scale Factor</td>
        <td id="ScaleFactor"></td>
    </tr>
    <tr>
        <td>Calculated Scale Value</td>
        <td id="CalculatedScaleValue"></td>
    </tr>
    <tr>
        <td>Parent Height</td>
        <td id="ParentHeight"></td>
    </tr>
    <tr>
        <td>Parent Width</td>
        <td id="ParentWidth"></td>
    </tr>
    <tr>
        <td>Child Height</td>
        <td id="ChildHeight"></td>
    </tr>
    <tr>
        <td>Child Width</td>
        <td id="ChildWidth"></td>
    </tr>
</table>
Arun Prasad E S
  • 9,489
  • 8
  • 74
  • 87
0

Resizing an image to a certain percentage

// scale can be 0.40, 0.80, etc.
function imageScaler(originalHeight, originalWidth, scale) {
  const scaledWidth = originalWidth * scale;
  const scaledHeight = (originalHeight / originalWidth) * scaledWidth;
  return [scaledHeight, scaledWidth];
}
Amrit
  • 1,964
  • 19
  • 25
0

You can determine width height if you want a particular aspect ratio to do so, Let you have a picture of 3264×2448 Pictures aspect ratio is => 2448 ÷ 3264 =0.75 Now just check number which gives 0.75 on division. Like: for 16:9 => 9÷16 =0.5625 (wrong it is not 0.75) Now 4:3 =>3÷4=0.75 (we get it ) So the original aspect ratio is 4:3 now to resize the image just do Width=3264 ÷/× 4 Height=2448 ÷/× 3 ÷ for reducing × for increasing Hope you can understand and code yourself this is very effective because we just need to do very basic arithmetic just division or multiplication so simple. Let me know if i am wrong.

Somen Das
  • 366
  • 2
  • 7
  • I cannot format this document so please someone edit this and make it readable. I don't know how to do it sorry for that – Somen Das Feb 12 '22 at 16:40
-4

This totally worked for me for a draggable item - aspectRatio:true

.appendTo(divwrapper).resizable({
    aspectRatio: true,
    handles: 'se',
    stop: resizestop 
})
Catherine
  • 103
  • 4