By Nithin


2011-06-08 12:45:19 8 Comments

I am loading an image to an imageview with mode as 'Aspect Fit'. I need to know the size to which my image is being scaled to. Please help.

19 comments

@Darshit Shah 2017-03-30 10:18:54

This single line can do this job

CGSize sizeInView = AVMakeRectWithAspectRatioInsideRect(imgViewFake.image.size, imgViewFake.bounds).size;

@fewlinesofcode 2018-09-24 10:06:16

Swift 4 version

extension CGSize {
   enum AspectMode {
       case fit
       case fill
   }

   enum Orientation {
       case portrait
       case landscape
   }

   func aspectCorrectSizeToFit(targetSize: CGSize, aspectMode: AspectMode = .fill) -> CGSize {
        switch aspectMode {
        case .fill: return aspectFill(targetSize: targetSize)
        case .fit: return aspectFit(targetSize: targetSize)
        }
    }

    var orientation: Orientation {
        if height >= width { return .portrait }
        else { return .landscape }
    }

    func aspectFit(targetSize: CGSize) -> CGSize {
        let wRatio = targetSize.width / width
        let hRatio = targetSize.height / height
        let scale = min(wRatio, hRatio)
        return applying(CGAffineTransform(scaleX: scale, y: scale))
    }

    func aspectFill(targetSize: CGSize) -> CGSize {
        let wRatio = targetSize.width / width
        let hRatio = targetSize.height / height
        let scale = max(wRatio, hRatio)
        return applying(CGAffineTransform(scaleX: scale, y: scale))
    }
}

@Paul de Lange 2013-01-02 09:01:08

Why not use the OS function AVMakeRectWithAspectRatioInsideRect?

@greg 2013-01-02 19:53:55

This is exactly what is needed -- [imageView setFrame:AVMakeRectWithAspectRatioInsideRect(image.size, imageView.frame)])

@Popara 2013-07-29 12:01:12

Good and clean option. Here is the docs link developer.apple.com/library/ios/#documentation/AVFoundation/‌​…

@Timo 2013-07-30 13:29:09

Don't want to include the AVFoundation framework? I'm posting two alternative utility functions to AVMakeRectWithAspectRatioInsideRect() in a separate answer.

@jjpp 2015-08-23 12:09:05

This should be the accepted answer. The accepted answer above is not correct and wont work in different cases.

@Akshit Zaveri 2015-11-14 09:54:19

Fantastic. Excellent.

@Ben Sullivan 2016-06-21 12:14:07

For swifters: import AVFoundation let height = AVMakeRectWithAspectRatioInsideRect((image?.size)!, imageView.frame).height

@Jack 2017-11-29 10:07:41

Swift 4: Frame for .aspectFit image is -

import AVFoundation

let x: CGRect = AVMakeRect(aspectRatio: myImage.size, insideRect: sampleImageView.frame)

@Kishore Kumar 2018-06-28 08:23:06

its returning a wrong size

@Jack 2018-06-28 08:27:57

Have u done aspectFit?

@Kishore Kumar 2018-06-28 08:30:14

yes I done , but I don't have any space on y but it is returning as 40

@Jack 2018-06-28 08:47:31

That’s unexpected, have you tried with fresh view controller with single imageView with no constraints?

@Kishore Kumar 2018-06-28 09:12:55

I tried on uiview xib , in that image view was there , origin x value is going to y and orgin y value is going to x . and I am using constraints.

@Kishore Kumar 2018-06-28 10:12:03

like you said it was a issue because of the constraints @Jack

@Russian 2017-06-20 04:47:58

Here's my AVFoundation-less solution.

First here's a CGSize extension for calculating a size that would fit another size:

extension CGSize
{
    func sizeThatFitsSize(_ aSize: CGSize) -> CGSize
    {
        let width = min(self.width * aSize.height / self.height, aSize.width)
        return CGSize(width: width, height: self.height * width / self.width)
    }
}

So the solution to OP's problem gets down to:

let resultSize = image.size.sizeThatFitsSize(imageView.bounds.size)

Also here's another extension for fitting a rect within another rect (it utilizes the above CGSize extension):

extension CGRect
{
    func rectThatFitsRect(_ aRect:CGRect) -> CGRect
    {
        let sizeThatFits = self.size.sizeThatFitsSize(aRect.size)

        let xPos = (aRect.size.width - sizeThatFits.width) / 2
        let yPos = (aRect.size.height - sizeThatFits.height) / 2

        let ret = CGRect(x: xPos, y: yPos, width: sizeThatFits.width, height: sizeThatFits.height)
        return ret
    }
}

@Md Rais 2017-06-01 08:22:07

If you know only the width of the imageview and when the height of the image is dynamic then you need to scale the image's height according to the given width to remove the white spaces above and below your image. Use the following method from here to scale the height of the image according to the standard width of your screen.

-(UIImage*)imageWithImage: (UIImage*) sourceImage scaledToWidth: (float) i_width
{
    float oldWidth = sourceImage.size.width;
    float scaleFactor = i_width / oldWidth;

    float newHeight = sourceImage.size.height * scaleFactor;
    float newWidth = oldWidth * scaleFactor;

    UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
    [sourceImage drawInRect:CGRectMake(0, 0, newWidth, newHeight)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();    
    UIGraphicsEndImageContext();
    return newImage;
}

And call it from your cellForRowAtIndexPath: method like this:

UIImage *img = [dictImages objectForKey:yourImageKey]; // loaded the image
cell.imgView.image = [self imageWithImage:img scaledToWidth:self.view.frame.size.width];

@Paul King 2017-05-24 14:24:18

Swift 3 UIImageView extension:

import AVFoundation

extension UIImageView {
  var imageSize: CGSize {
    if let image = image {
      return AVMakeRect(aspectRatio: image.size, insideRect: bounds).size
    }
    return CGSize.zero
  }  
}

@topLayoutGuide 2017-05-09 05:12:38

Swift 3 Human Readable Version

extension UIImageView {

    /// Find the size of the image, once the parent imageView has been given a contentMode of .scaleAspectFit
    /// Querying the image.size returns the non-scaled size. This helper property is needed for accurate results.
    var aspectFitSize: CGSize {
        guard let image = image else { return CGSize.zero }

        var aspectFitSize = CGSize(width: frame.size.width, height: frame.size.height)
        let newWidth: CGFloat = frame.size.width / image.size.width
        let newHeight: CGFloat = frame.size.height / image.size.height

        if newHeight < newWidth {
            aspectFitSize.width = newHeight * image.size.width
        } else if newWidth < newHeight {
            aspectFitSize.height = newWidth * image.size.height
        }

        return aspectFitSize
    }

    /// Find the size of the image, once the parent imageView has been given a contentMode of .scaleAspectFill
    /// Querying the image.size returns the non-scaled, vastly too large size. This helper property is needed for accurate results.
    var aspectFillSize: CGSize {
        guard let image = image else { return CGSize.zero }

        var aspectFillSize = CGSize(width: frame.size.width, height: frame.size.height)
        let newWidth: CGFloat = frame.size.width / image.size.width
        let newHeight: CGFloat = frame.size.height / image.size.height

        if newHeight > newWidth {
            aspectFillSize.width = newHeight * image.size.width
        } else if newWidth > newHeight {
            aspectFillSize.height = newWidth * image.size.height
        }

        return aspectFillSize
    }

}

@Rayfleck 2011-06-08 20:00:06

Please see @Paul-de-Lange's answer instead of this one


I couldn't find anything in an easily accessible variable that had this, so here is the brute force way:

- (CGSize) aspectScaledImageSizeForImageView:(UIImageView *)iv image:(UIImage *)im {

float x,y;
float a,b;
x = iv.frame.size.width;
y = iv.frame.size.height;
a = im.size.width;
b = im.size.height;

if ( x == a && y == b ) {           // image fits exactly, no scaling required
    // return iv.frame.size;
}
else if ( x > a && y > b ) {         // image fits completely within the imageview frame
    if ( x-a > y-b ) {              // image height is limiting factor, scale by height
        a = y/b * a;
        b = y;
    } else {
        b = x/a * b;                // image width is limiting factor, scale by width
        a = x;
    }
} 
else if ( x < a && y < b ) {        // image is wider and taller than image view
    if ( a - x > b - y ) {          // height is limiting factor, scale by height
        a = y/b * a;
        b = y;
    } else {                        // width is limiting factor, scale by width
        b = x/a * b;
        a = x;
    }
}
else if ( x < a && y > b ) {        // image is wider than view, scale by width
    b = x/a * b;
    a = x;
}
else if ( x > a && y < b ) {        // image is taller than view, scale by height
    a = y/b * a;
    b = y;
}
else if ( x == a ) {
    a = y/b * a;
    b = y;
} else if ( y == b ) {
    b = x/a * b;
    a = x;
}
return CGSizeMake(a,b);

}

@renaun 2014-01-04 21:33:27

This code is not accurate. It doesn't handle all cases. For example if you have a 2048 x 1536 image and try and fit into 514 x 402. It will return the scaled size of 402 (height) when it should scale it to the width. I changed if ( a - x > b - y ) { to if ( a - x > b - y && (y/b * a) < x) { to fix it. They other statements should be checked too.

@Mrug 2014-03-29 07:28:27

Hello Sir, I found this Anser Helpful but can you pls help me in my Question : stackoverflow.com/questions/22727615/…

@Hardik Thakkar 2016-06-18 07:22:33

For Swift use below code

func imageSizeAspectFit(imgview: UIImageView) -> CGSize {
        var newwidth: CGFloat
        var newheight: CGFloat
        let image: UIImage = imgFeed.image!

        if image.size.height >= image.size.width {
            newheight = imgview.frame.size.height;
            newwidth = (image.size.width / image.size.height) * newheight
            if newwidth > imgview.frame.size.width {
                let diff: CGFloat = imgview.frame.size.width - newwidth
                newheight = newheight + diff / newheight * newheight
                newwidth = imgview.frame.size.width
            }
        }
        else {
            newwidth = imgview.frame.size.width
            newheight = (image.size.height / image.size.width) * newwidth
            if newheight > imgview.frame.size.height {
                let diff: CGFloat = imgview.frame.size.height - newheight
                newwidth = newwidth + diff / newwidth * newwidth
                newheight = imgview.frame.size.height
            }
        }

       print(newwidth, newheight)
        //adapt UIImageView size to image size
        return CGSizeMake(newwidth, newheight)
    }

And Call Function

imgFeed.sd_setImageWithURL(NSURL(string:"Your image URL")))
self.imageSizeAfterAspectFit(imgFeed)

@Suryanarayan Sahu 2016-05-18 05:53:02

The above mentioned methods never give the required values.As aspect fit maintains the same aspect ratio we just need simple maths to calculate the values

Detect the aspect ratio

CGFloat imageViewAspectRatio = backgroundImageView.bounds.size.width / backgroundImageView.bounds.size.height;
CGFloat imageAspectRatio =  backgroundImageView.image.size.width / backgroundImageView.image.size.height;
CGFloat mulFactor = imageViewAspectRatio/imageAspectRatio;

Get the new values

CGFloat newImageWidth = mulFactor * backgroundImageView.bounds.size.width;
CGFloat newImageHeight = mulFactor * backgroundImageView.bounds.size.height;

@JollyJinx 2016-04-14 08:59:06

I'm using the following in Swift:

private func CGSizeAspectFit(aspectRatio:CGSize,boundingSize:CGSize) -> CGSize
{
    var aspectFitSize = boundingSize
    let mW = boundingSize.width / aspectRatio.width
    let mH = boundingSize.height / aspectRatio.height
    if( mH < mW )
    {
        aspectFitSize.width = mH * aspectRatio.width
    }
    else if( mW < mH )
    {
        aspectFitSize.height = mW * aspectRatio.height
    }
    return aspectFitSize
}

private func CGSizeAspectFill(aspectRatio:CGSize,minimumSize:CGSize) -> CGSize
{
    var aspectFillSize = minimumSize
    let mW = minimumSize.width / aspectRatio.width
    let mH = minimumSize.height / aspectRatio.height
    if( mH > mW )
    {
        aspectFillSize.width = mH * aspectRatio.width
    }
    else if( mW > mH )
    {
        aspectFillSize.height = mW * aspectRatio.height
    }
    return aspectFillSize
}

I'm using it like this:

let aspectSize  = contentMode == .ScaleAspectFill ? CGSizeAspectFill(oldSize,minimumSize: newSize) : CGSizeAspectFit(oldSize, boundingSize: newSize)

let newRect = CGRect( x: (newSize.width - aspectSize.width)/2, y: (newSize.height - aspectSize.height)/2, width: aspectSize.width, height: aspectSize.height)

CGContextSetFillColorWithColor(context,IOSXColor.whiteColor().CGColor)
CGContextFillRect(context, CGRect(origin: CGPointZero,size: newSize))
CGContextDrawImage(context, newRect, cgImage)

@oyalhi 2016-05-20 07:08:33

Perfect. Thanks.

@Timo 2013-07-30 13:43:41

I wanted to use AVMakeRectWithAspectRatioInsideRect() without including the AVFoundation framework.

So I've implemented the following two utility functions:

CGSize CGSizeAspectFit(CGSize aspectRatio, CGSize boundingSize)
{
    float mW = boundingSize.width / aspectRatio.width;
    float mH = boundingSize.height / aspectRatio.height;
    if( mH < mW )
        boundingSize.width = boundingSize.height / aspectRatio.height * aspectRatio.width;
    else if( mW < mH )
        boundingSize.height = boundingSize.width / aspectRatio.width * aspectRatio.height;
    return boundingSize;
}

CGSize CGSizeAspectFill(CGSize aspectRatio, CGSize minimumSize)
{
    float mW = minimumSize.width / aspectRatio.width;
    float mH = minimumSize.height / aspectRatio.height;
    if( mH > mW )
        minimumSize.width = minimumSize.height / aspectRatio.height * aspectRatio.width;
    else if( mW > mH )
        minimumSize.height = minimumSize.width / aspectRatio.width * aspectRatio.height;
    return minimumSize;
}

Edit: Optimized below by removing duplicate divisions.

CGSize CGSizeAspectFit(const CGSize aspectRatio, const CGSize boundingSize)
{
    CGSize aspectFitSize = CGSizeMake(boundingSize.width, boundingSize.height);
    float mW = boundingSize.width / aspectRatio.width;
    float mH = boundingSize.height / aspectRatio.height;
    if( mH < mW )
        aspectFitSize.width = mH * aspectRatio.width;
    else if( mW < mH )
        aspectFitSize.height = mW * aspectRatio.height;
    return aspectFitSize;
}

CGSize CGSizeAspectFill(const CGSize aspectRatio, const CGSize minimumSize)
{
    CGSize aspectFillSize = CGSizeMake(minimumSize.width, minimumSize.height);
    float mW = minimumSize.width / aspectRatio.width;
    float mH = minimumSize.height / aspectRatio.height;
    if( mH > mW )
        aspectFillSize.width = mH * aspectRatio.width;
    else if( mW > mH )
        aspectFillSize.height = mW * aspectRatio.height;
    return aspectFillSize;
}

End of edit

This takes a given size (first parameter) and maintains its aspect ratio. It then fills the given bounds (second parameter) as much as possible without violating the aspect ratio.

Using this to answer the original question:

// Using aspect fit, scale the image (size) to the image view's size.
CGSize sizeBeingScaledTo = CGSizeAspectFit(theImage.size, theImageView.frame.size);

Note how the image determines the aspect ratio, while the image view determines the size to be filled.

Feedback is very welcome.

@Timo 2013-07-30 14:00:42

This can be adjusted to use CGFloats if you're into that sort of thing.

@LilDwarf 2014-07-12 23:46:24

Excellent answer. You can also adjust it to center on a certain view, to get the actual CGRect of an image inside a UIImageView with AspectFit. I did something like this: <code> CGSize imageSize = CGSizeAspectFit(imageView.image.size, imageView.frame.size); CGRect actualImageRect = CGRectMake(0, 0, imageSize.width, imageSize.height); actualImageRect.origin.x = imageView.center.x - imageSize.width / 2; actualImageRect.origin.y = imageView.center.y - imageSize.height / 2; </code>

@EralpB 2015-06-16 06:39:56

Thank you, this is a great utility function.

@Timo 2015-12-08 11:46:24

I have included an optimized version that removes the duplicate divisions. Now a branchless equivalent might be a fun challenge to come up with. :)

@zeeawan 2015-10-30 21:08:19

I also wanted to calculate height after the aspect ratio is applied to be able to calculate the height of table view's cell. So, I achieved via little math

ratio = width / height

and height would become

height = width / ratio

So code snippet would be

UIImage *img = [UIImage imageNamed:@"anImage"];
float aspectRatio = img.size.width/img.size.height;
float requiredHeight = self.view.bounds.size.width / aspectRatio;

@oyalhi 2016-05-20 07:13:55

Elegant. I use it inside UITableViewCell class, so the requiredHeight becomes float requiredHeight = self.bounds.size.width / aspectRatio;.

@Marian Petrisor 2018-09-19 20:29:33

You are brilliant! This should have been the accepted answer!

@Aleksey 2015-01-16 21:45:44

Here is my solution for same problem: https://github.com/alexgarbarev/UIImageView-ImageFrame

Advantages:

  • UIViewContentMode modes supported
  • Can query for scales and for rect separately
  • Can ask about image frame right from UIImageView

@blkhp19 2014-08-01 18:19:52

The accepted answer is incredibly complicated and fails for some edge cases. I think this solution is much more elegant:

- (CGSize) sizeOfImage:(UIImage*)image inAspectFitImageView:(UIImageView*)imageView
{
    UKAssert(imageView.contentMode == UIViewContentModeScaleAspectFit, @"Image View must use contentMode = UIViewContentModeScaleAspectFit");

    CGFloat imageViewWidth = imageView.bounds.size.width;
    CGFloat imageViewHeight = imageView.bounds.size.height;

    CGFloat imageWidth = image.size.width;
    CGFloat imageHeight = image.size.height;

    CGFloat scaleFactor = MIN(imageViewWidth / imageWidth, imageViewHeight / imageHeight);

    return CGSizeMake(image.size.width*scaleFactor, image.size.height*scaleFactor);
}

@PakitoV 2013-04-13 09:26:31

Maybe does not fit your case, but this simple approach solve my problem in a similar case:

    UIImageView *imageView = [[UIImageView alloc] initWithImage:bigSizeImage];
    [imageView sizeToFit];

After image view executes sizeToFit if you query the imageView.frame.size you will get the new image view size that fits the new image size.

@Aklesh Rathaur 2015-05-27 11:01:48

it really works

@Oleh Kudinov 2013-01-24 10:23:29

This simple function will calculate size of image after aspect fit:

    -(CGSize)imageSizeAfterAspectFit:(UIImageView*)imgview{


    float newwidth;
    float newheight;

    UIImage *image=imgview.image;

    if (image.size.height>=image.size.width){
        newheight=imgview.frame.size.height;
        newwidth=(image.size.width/image.size.height)*newheight;

        if(newwidth>imgview.frame.size.width){
            float diff=imgview.frame.size.width-newwidth;
            newheight=newheight+diff/newheight*newheight;
            newwidth=imgview.frame.size.width;
        }

    }
    else{
        newwidth=imgview.frame.size.width;
        newheight=(image.size.height/image.size.width)*newwidth;

        if(newheight>imgview.frame.size.height){
            float diff=imgview.frame.size.height-newheight;
            newwidth=newwidth+diff/newwidth*newwidth;
            newheight=imgview.frame.size.height;
        }
    }

    NSLog(@"image after aspect fit: width=%f height=%f",newwidth,newheight);


    //adapt UIImageView size to image size
    //imgview.frame=CGRectMake(imgview.frame.origin.x+(imgview.frame.size.width-newwidth)/2,imgview.frame.origin.y+(imgview.frame.size.height-newheight)/2,newwidth,newheight);

    return CGSizeMake(newwidth, newheight);

}

@Ayan Sengupta 2013-11-12 20:59:02

The accepted answer did not work for me. But this answer did. And the real beauty of this answer is that it does not need to pass any explicit reference of the UIImage, instead, it takes it from the image content of the UIImageView. It works with orientation change either. Thanks.

@Timo 2014-09-01 09:28:59

Since this is always done on a UIImageView, it might be worth shaping it into a category method UIImageView.

@sohil 2015-12-11 06:21:52

superbbbbb work bro.......

@v_1 2012-06-12 06:38:48

+(UIImage *)CreateAResizeImage:(UIImage *)Img ThumbSize:(CGSize)ThumbSize 
{
    float actualHeight = Img.size.height;
    float actualWidth = Img.size.width;

    if(actualWidth==actualHeight) 
    {
        actualWidth = ThumbSize.width; 
        actualHeight = ThumbSize.height;
    }

    float imgRatio = actualWidth/actualHeight;
    float maxRatio = ThumbSize.width/ThumbSize.height; //320.0/480.0;


    if(imgRatio!=maxRatio)
    {
        if(imgRatio < maxRatio)
        {
            imgRatio = ThumbSize.height / actualHeight; //480.0 / actualHeight;
            actualWidth = imgRatio * actualWidth;
            actualHeight = ThumbSize.height; //480.0;
        }
        else
        {
            imgRatio = ThumbSize.width / actualWidth; //320.0 / actualWidth;
            actualHeight = imgRatio * actualHeight;
            actualWidth = ThumbSize.width; //320.0;
        }
    } 
    else 
    {
        actualWidth = ThumbSize.width;
        actualHeight = ThumbSize.height; 
    }


    CGRect rect = CGRectMake(0, 0, (int)actualWidth, (int)actualHeight);
    UIGraphicsBeginImageContext(rect.size);
    [Img drawInRect:rect];
    UIImage *NewImg = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return NewImg;
}

Related Questions

Sponsored Content

18 Answered Questions

[SOLVED] CSS force image resize and keep aspect ratio

35 Answered Questions

10 Answered Questions

[SOLVED] UIImageView aspect fit and center

2 Answered Questions

[SOLVED] How to make UIImageView fit scaled image

  • 2016-09-20 01:13:50
  • zorro2b
  • 140 View
  • 0 Score
  • 2 Answer
  • Tags:   ios uiimageview

5 Answered Questions

[SOLVED] Resizing image to fit UIImageView

1 Answered Questions

[SOLVED] Resize UIImageView after Scale Aspect Fit

2 Answered Questions

[SOLVED] Scaling any image to fit UIImageView

1 Answered Questions

4 Answered Questions

[SOLVED] UIImageView: Change size to image size?

  • 2012-01-02 14:01:37
  • dhrm
  • 36381 View
  • 15 Score
  • 4 Answer
  • Tags:   ios uiimageview

1 Answered Questions

[SOLVED] UIimageview drawInRect with aspect to fit mode

Sponsored Content