views:

1266

answers:

5

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.

A: 

I'd similar problem and I've found that very helpful: http://www.codeproject.com/KB/GDI-plus/imgresizoutperfgdiplus.aspx. As I understood correctly you need to resize the image?

bezieur
+13  A: 

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, x, for the width, x must be such that: x*w=MaxWidth. Therefore, the scaling factor is MaxWidth/w.

Similarly for height.

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

Shawn J. Goff
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?
Marcus Downing
+1  A: 

Python code, but maybe it will point you in the right direction:

def fit_within_box(box_width, box_height, width, height):
    """
    Returns a tuple (new_width, new_height) which has the property
    that it fits within box_width and box_height and has (close to)
    the same aspect ratio as the original size
    """
    new_width, new_height = width, height
    aspect_ratio = float(width) / float(height)

    if new_width > box_width:
     new_width = box_width
     new_height = int(new_width / aspect_ratio)

    if new_height > box_height:
     new_height = box_height
     new_width = int(new_height * aspect_ratio)

    return (new_width, new_height)
Jason Creighton
A: 

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));
}

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

Matt Warren
A: 

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.)

vocaro