Resize Image to fit in bounding box

34,235

Solution 1

Find which is smaller: MaxWidth / w or MaxHeight / h Then multiply w and h by that number

Explanation:

You need to find the scaling factor which makes the image fit.

To find the scaling factor, s, for the width, then s must be such that: s * w = MaxWidth. Therefore, the scaling factor is MaxWidth / w.

Similarly for height.

The one that requires the most scaling (smaller s) is the factor by which you must scale the whole image.

Solution 2

Based on Eric's suggestion I'd do something like this:

private static Size ExpandToBound(Size image, Size boundingBox)
{       
    double widthScale = 0, heightScale = 0;
    if (image.Width != 0)
        widthScale = (double)boundingBox.Width / (double)image.Width;
    if (image.Height != 0)
        heightScale = (double)boundingBox.Height / (double)image.Height;                

    double scale = Math.Min(widthScale, heightScale);

    Size result = new Size((int)(image.Width * scale), 
                        (int)(image.Height * scale));
    return result;
}

I might have gone a bit overboard on the casts, but I was just trying to preserve precision in the calculations.

Solution 3

Tried Mr. Warren's code, but it didn't produce reliable results.

For example,

ExpandToBound(new Size(640,480), new Size(66, 999)).Dump();
// {Width=66, Height=49}

ExpandToBound(new Size(640,480), new Size(999,50)).Dump();
// {Width=66, Height=50}

You can see, height = 49 and height = 50 in another.

Here's mine (based version of Mr. Warren's code) without the discrepancy and a slight refactor:

// Passing null for either maxWidth or maxHeight maintains aspect ratio while
//        the other non-null parameter is guaranteed to be constrained to
//        its maximum value.
//
//  Example: maxHeight = 50, maxWidth = null
//    Constrain the height to a maximum value of 50, respecting the aspect
//    ratio, to any width.
//
//  Example: maxHeight = 100, maxWidth = 90
//    Constrain the height to a maximum of 100 and width to a maximum of 90
//    whichever comes first.
//
private static Size ScaleSize( Size from, int? maxWidth, int? maxHeight )
{
   if ( !maxWidth.HasValue && !maxHeight.HasValue ) throw new ArgumentException( "At least one scale factor (toWidth or toHeight) must not be null." );
   if ( from.Height == 0 || from.Width == 0 ) throw new ArgumentException( "Cannot scale size from zero." );

   double? widthScale = null;
   double? heightScale = null;

   if ( maxWidth.HasValue )
   {
       widthScale = maxWidth.Value / (double)from.Width;
   }
   if ( maxHeight.HasValue )
   {
       heightScale = maxHeight.Value / (double)from.Height;
   }

   double scale = Math.Min( (double)(widthScale ?? heightScale),
                            (double)(heightScale ?? widthScale) );

   return new Size( (int)Math.Floor( from.Width * scale ), (int)Math.Ceiling( from.Height * scale ) );
}

Solution 4

To perform an aspect fill instead of an aspect fit, use the larger ratio instead. That is, change Matt's code from Math.Min to Math.Max.

(An aspect fill leaves none of the bounding box empty but may put some of the image outside the bounds, while an aspect fit leaves none of the image outside the bounds but may leave some of the bounding box empty.)

Solution 5

Following code produces more accurate results:

    public static Size CalculateResizeToFit(Size imageSize, Size boxSize)
    {
        // TODO: Check for arguments (for null and <=0)
        var widthScale = boxSize.Width / (double)imageSize.Width;
        var heightScale = boxSize.Height / (double)imageSize.Height;
        var scale = Math.Min(widthScale, heightScale);
        return new Size(
            (int)Math.Round((imageSize.Width * scale)),
            (int)Math.Round((imageSize.Height * scale))
            );
    }
Share:
34,235
Eric Petroelje
Author by

Eric Petroelje

I've been doing software development for about 14 years in a variety of languages from C,C++, Java/J2EE, PHP, and more recently C# and ASP.NET.

Updated on July 09, 2022

Comments

  • Eric Petroelje
    Eric Petroelje almost 2 years

    An easy problem, but for some reason I just can't figure this out today.

    I need to resize an image to the maximum possible size that will fit in a bounding box while maintaining the aspect ratio.

    Basicly I'm looking for the code to fill in this function:

    void CalcNewDimensions(ref int w, ref int h, int MaxWidth, int MaxHeight);
    

    Where w & h are the original height and width (in) and the new height and width (out) and MaxWidth and MaxHeight define the bounding box that the image must fit in.

  • Marcus Downing
    Marcus Downing over 14 years
    If you do that with float you might probably find that the dimension which matches the bounding box is slightly off (sometimes, in an unpredictable way). When you've identified which dimension doesn't match, might it be best to simply assume the other one is exactly what it should be?
  • Brian Chavez
    Brian Chavez about 13 years
    don't forget to return result;
  • Nicolas Le Thierry d'Ennequin
    Nicolas Le Thierry d'Ennequin about 12 years
    Your code works if the image must be shrinked, not if it must be expanded to fit the container. I think you should update your conditionals like this: if new_width > box_width or new_height < box_height: And: if new_height > box_height or new_width < box_width:
  • chaosTechnician
    chaosTechnician almost 12 years
    +1 Three years later sitting at the top of my Google results. No muss, no fuss. Thanks!
  • Luke Taylor
    Luke Taylor almost 9 years
    Like how your response isn't written in c, so I can apply it to python
  • delrocco
    delrocco over 6 years
    Thank you for supplying an algorithm and explanation instead of just code! I wish more solutions were written like this.
  • Thomas
    Thomas over 6 years
    You shoud use Math.Round in both cases in the last line as in your code we get wrong results.
  • J-Cake
    J-Cake over 4 years
    Thanks, this works well. the explanation really helped too
  • Felipe
    Felipe over 4 years
    Excellent information. It wasn't intuitive to me looking at the other answers
  • Dominic
    Dominic about 2 years
    What if the x,y of the image in the box can be anything not just 0,0?