iphone - Resize UIImage by keeping Aspect ratio and width


Translate

I seen in many posts for resizing the image by keeping aspect ratio. These functions uses the fixed points(Width and Height) for RECT while resizing. But in my project, I need to resize the view based on the Width alone, Height should be taken automatically based on the aspect ratio. anyone help me to achieve this.


All Answers
  • Translate

    The method of Srikar works very well, if you know both height and width of your new Size. If you for example know only the width you want to scale to and don't care about the height you first have to calculate the scale factor of the height.

    +(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;
    }
    

  • Translate

    If you don't happen to know if the image will be portrait or landscape (e.g user takes pic with camera), I created another method that takes max width and height parameters.

    Lets say you have a UIImage *myLargeImage which is a 4:3 ratio.

    UIImage *myResizedImage = [ImageUtilities imageWithImage:myLargeImage 
                                            scaledToMaxWidth:1024 
                                                   maxHeight:1024];
    

    The resized UIImage will be 1024x768 if landscape; 768x1024 if portrait. This method will also generate higher res images for retina display.

    + (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)size {
        if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
            UIGraphicsBeginImageContextWithOptions(size, NO, [[UIScreen mainScreen] scale]);
        } else {
            UIGraphicsBeginImageContext(size);
        }
        [image drawInRect:CGRectMake(0, 0, size.width, size.height)];
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();    
        UIGraphicsEndImageContext();
    
        return newImage;
    }
    
    + (UIImage *)imageWithImage:(UIImage *)image scaledToMaxWidth:(CGFloat)width maxHeight:(CGFloat)height {
        CGFloat oldWidth = image.size.width;
        CGFloat oldHeight = image.size.height;
    
        CGFloat scaleFactor = (oldWidth > oldHeight) ? width / oldWidth : height / oldHeight;
    
        CGFloat newHeight = oldHeight * scaleFactor;
        CGFloat newWidth = oldWidth * scaleFactor;
        CGSize newSize = CGSizeMake(newWidth, newHeight);
    
        return [ImageUtilities imageWithImage:image scaledToSize:newSize];
    }
    

  • Translate

    Best answer Maverick 1st's correctly translated to Swift (working with latest swift 3):

    func imageWithImage (sourceImage:UIImage, scaledToWidth: CGFloat) -> UIImage {
        let oldWidth = sourceImage.size.width
        let scaleFactor = scaledToWidth / oldWidth
    
        let newHeight = sourceImage.size.height * scaleFactor
        let newWidth = oldWidth * scaleFactor
    
        UIGraphicsBeginImageContext(CGSize(width:newWidth, height:newHeight))
        sourceImage.draw(in: CGRect(x:0, y:0, width:newWidth, height:newHeight))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage!
    }
    

  • Translate

    thanks @Maverick1st the algorithm, I implemented it to Swift, in my case height is the input parameter

    class func resizeImage(image: UIImage, newHeight: CGFloat) -> UIImage {
    
        let scale = newHeight / image.size.height
        let newWidth = image.size.width * scale
        UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight))
        image.drawInRect(CGRectMake(0, 0, newWidth, newHeight))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
    
        return newImage
    }
    

  • Translate

    This method is a category on UIImage. Does scale to fit in few lines of code using AVFoundation. Don't forget to import #import <AVFoundation/AVFoundation.h>.

    @implementation UIImage (Helper)
    
    - (UIImage *)imageScaledToFitToSize:(CGSize)size
    {
        CGRect scaledRect = AVMakeRectWithAspectRatioInsideRect(self.size, CGRectMake(0, 0, size.width, size.height));
        UIGraphicsBeginImageContextWithOptions(size, NO, 0);
        [self drawInRect:scaledRect];
        UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return scaledImage;
    }
    
    @end
    

  • Translate

    The simplest way is to set the frame of your UIImageView and set the contentMode to one of the resizing options.

    The code goes like this - This can be used as an utility method -

    + (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize
    {
        UIGraphicsBeginImageContext(newSize);
        [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();    
        UIGraphicsEndImageContext();
        return newImage;
    }
    

  • Translate

    Well, we have few good answers here for resizing image, but I just modify as per my need. hope this help someone like me.

    My Requirement was

    1. If image width is more than 1920, resize it with 1920 width and maintaining height with original aspect ratio.
    2. If image height is more than 1080, resize it with 1080 height and maintaining width with original aspect ratio.

     if (originalImage.size.width > 1920)
     {
            CGSize newSize;
            newSize.width = 1920;
            newSize.height = (1920 * originalImage.size.height) / originalImage.size.width;
            originalImage = [ProfileEditExperienceViewController imageWithImage:originalImage scaledToSize:newSize];        
     }
    
     if (originalImage.size.height > 1080)
     {
                CGSize newSize;
                newSize.width = (1080 * originalImage.size.width) / originalImage.size.height;
                newSize.height = 1080;
                originalImage = [ProfileEditExperienceViewController imageWithImage:originalImage scaledToSize:newSize];
    
     }
    
    + (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize
    {
            UIGraphicsBeginImageContext(newSize);
            [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
            UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
            return newImage;
    }
    

    Thanks to @Srikar Appal , for resizing I have used his method.

    You may like to check this as well for resize calculation.


  • Translate

    Programmatically:

    imageView.contentMode = UIViewContentModeScaleAspectFit;
    

    Storyboard:

    enter image description here


  • Translate

    Just import AVFoundation and use AVMakeRectWithAspectRatioInsideRect(CGRectCurrentSize, CGRectMake(0, 0, YOUR_WIDTH, CGFLOAT_MAX)


  • Translate

    To improve on Ryan's answer:

       + (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)size {
    CGFloat oldWidth = image.size.width;
            CGFloat oldHeight = image.size.height;
    
    //You may need to take some retina adjustments into consideration here
            CGFloat scaleFactor = (oldWidth > oldHeight) ? width / oldWidth : height / oldHeight;
    
    return [UIImage imageWithCGImage:image.CGImage scale:scaleFactor orientation:UIImageOrientationUp];
        }
    

  • Translate

    Swift 5 version of aspect-fit-to-height, based on answer by @János

    Uses the modern UIGraphicsImageRenderer API, so a valid UIImage is guaranteed to return.

    extension UIImage
    {
        /// Given a required height, returns a (rasterised) copy
        /// of the image, aspect-fitted to that height.
    
        func aspectFittedToHeight(_ newHeight: CGFloat) -> UIImage
        {
            let scale = newHeight / self.size.height
            let newWidth = self.size.width * scale
            let newSize = CGSize(width: newWidth, height: newHeight)
            let renderer = UIGraphicsImageRenderer(size: newSize)
    
            return renderer.image { _ in
                self.draw(in: CGRect(origin: .zero, size: newSize))
            }
        }
    }
    

    You can use this in conjunction with a (vector-based) PDF image asset, to preserve quality at any render size.


  • Translate

    Ryan's Solution @Ryan in swift code

    use:

     func imageWithSize(image: UIImage,size: CGSize)->UIImage{
        if UIScreen.mainScreen().respondsToSelector("scale"){
            UIGraphicsBeginImageContextWithOptions(size,false,UIScreen.mainScreen().scale);
        }
        else
        {
             UIGraphicsBeginImageContext(size);
        }
    
        image.drawInRect(CGRectMake(0, 0, size.width, size.height));
        var newImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        return newImage;
    }
    
    //Summon this function VVV
    func resizeImageWithAspect(image: UIImage,scaledToMaxWidth width:CGFloat,maxHeight height :CGFloat)->UIImage
    {
        let oldWidth = image.size.width;
        let oldHeight = image.size.height;
    
        let scaleFactor = (oldWidth > oldHeight) ? width / oldWidth : height / oldHeight;
    
        let newHeight = oldHeight * scaleFactor;
        let newWidth = oldWidth * scaleFactor;
        let newSize = CGSizeMake(newWidth, newHeight);
    
        return imageWithSize(image, size: newSize);
    }
    

  • Translate

    In Swift 3 there are some changes. Here is an extension to UIImage:

    public extension UIImage {
        public func resize(height: CGFloat) -> UIImage? {
            let scale = height / self.size.height
            let width = self.size.width * scale
            UIGraphicsBeginImageContext(CGSize(width: width, height: height))
            self.draw(in: CGRect(x:0, y:0, width:width, height:height))
            let resultImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return resultImage
        }
    }
    

  • Translate
    extension UIImage {
    
        /// Returns a image that fills in newSize
        func resizedImage(newSize: CGSize) -> UIImage? {
            guard size != newSize else { return self }
    
        let hasAlpha = false
        let scale: CGFloat = 0.0
        UIGraphicsBeginImageContextWithOptions(newSize, !hasAlpha, scale)
            UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
    
            draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
            let newImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return newImage
        }
    
        /// Returns a resized image that fits in rectSize, keeping it's aspect ratio
        /// Note that the new image size is not rectSize, but within it.
        func resizedImageWithinRect(rectSize: CGSize) -> UIImage? {
            let widthFactor = size.width / rectSize.width
            let heightFactor = size.height / rectSize.height
    
            var resizeFactor = widthFactor
            if size.height > size.width {
                resizeFactor = heightFactor
            }
    
            let newSize = CGSize(width: size.width / resizeFactor, height: size.height / resizeFactor)
            let resized = resizedImage(newSize: newSize)
    
            return resized
        }
    }
    

    When scale is set to 0.0, the scale factor of the main screen is used, which for Retina displays is 2.0 or higher (3.0 on the iPhone 6 Plus).


  • Translate

    This one was perfect for me. Keeps aspect ratio and takes a maxLength. Width or Height will not be more than maxLength

    -(UIImage*)imageWithImage: (UIImage*) sourceImage maxLength: (float) maxLength
    {
        CGFloat scaleFactor = maxLength / MAX(sourceImage.size.width, sourceImage.size.height);
    
        float newHeight = sourceImage.size.height * scaleFactor;
        float newWidth = sourceImage.size.width * scaleFactor;
    
        UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
        [sourceImage drawInRect:CGRectMake(0, 0, newWidth, newHeight)];
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return newImage;
    }
    

  • Translate

    Calculates the best height of the image for available width.

    import Foundation
    
    public extension UIImage {
        public func height(forWidth width: CGFloat) -> CGFloat {
            let boundingRect = CGRect(
                x: 0,
                y: 0,
                width: width,
                height: CGFloat(MAXFLOAT)
            )
            let rect = AVMakeRect(
                aspectRatio: size,
                insideRect: boundingRect
            )
            return rect.size.height
        }
    }
    

  • Translate

    I have solved it in a much simpler way

    UIImage *placeholder = [UIImage imageNamed:@"OriginalImage.png"];
    self.yourImageview.image = [UIImage imageWithCGImage:[placeholder CGImage] scale:(placeholder.scale * 1.5)
                                      orientation:(placeholder.imageOrientation)];
    

    multiplier of the scale will define the scalling of the image,more the multiplier smaller the image. so You can check what fits your screen.

    Or you can also get the multiplire by dividing imagewidth/screenwidth.