Skip to content

Instantly share code, notes, and snippets.

@tomasbasham
Last active February 1, 2024 19:04
Show Gist options
  • Star 89 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save tomasbasham/10533743 to your computer and use it in GitHub Desktop.
Save tomasbasham/10533743 to your computer and use it in GitHub Desktop.
Scale a UIImage to any given rect keeping the aspect ratio
@implementation UIImage (scale)
/**
* Scales an image to fit within a bounds with a size governed by
* the passed size. Also keeps the aspect ratio.
*
* Switch MIN to MAX for aspect fill instead of fit.
*
* @param newSize the size of the bounds the image must fit within.
* @return a new scaled image.
*/
- (UIImage *)scaleImageToSize:(CGSize)newSize {
CGRect scaledImageRect = CGRectZero;
CGFloat aspectWidth = newSize.width / self.size.width;
CGFloat aspectHeight = newSize.height / self.size.height;
CGFloat aspectRatio = MIN ( aspectWidth, aspectHeight );
scaledImageRect.size.width = self.size.width * aspectRatio;
scaledImageRect.size.height = self.size.height * aspectRatio;
scaledImageRect.origin.x = (newSize.width - scaledImageRect.size.width) / 2.0f;
scaledImageRect.origin.y = (newSize.height - scaledImageRect.size.height) / 2.0f;
UIGraphicsBeginImageContextWithOptions( newSize, NO, 0 );
[self drawInRect:scaledImageRect];
UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return scaledImage;
}
@end
@fenixkim
Copy link

Swift 5 (Mac Os)

This working for me but I'm sure if is the best approach

extension NSImage {
    
    /// Represents a scaling mode
    enum ScalingMode {
        case aspectFill
        case aspectFit
        
        /// Calculates the aspect ratio between two sizes
        ///
        /// - parameters:
        ///     - size:      the first size used to calculate the ratio
        ///     - otherSize: the second size used to calculate the ratio
        ///
        /// - return: the aspect ratio between the two sizes
        func aspectRatio(between size: CGSize, and otherSize: CGSize) -> CGFloat {
            let aspectWidth  = size.width/otherSize.width
            let aspectHeight = size.height/otherSize.height
            
            switch self {
            case .aspectFill:
                return max(aspectWidth, aspectHeight)
            case .aspectFit:
                return min(aspectWidth, aspectHeight)
            }
        }
    }
    
    /// Scales an image to fit within a bounds with a size governed by the passed size. Also keeps the aspect ratio.
    ///
    /// - parameter:
    ///     - newSize:     the size of the bounds the image must fit within.
    ///     - scalingMode: the desired scaling mode
    ///
    /// - returns: a new scaled image.
    func scaled(to newSize: CGSize, scalingMode: ScalingMode = .aspectFill) -> NSImage {
        
        let aspectRatio = scalingMode.aspectRatio(between: newSize, and: size)
        
        /* Build the rectangle representing the area to be drawn */
        var scaledImageRect = CGRect.zero
        
        scaledImageRect.size.width  = size.width * aspectRatio
        scaledImageRect.size.height = size.height * aspectRatio
        scaledImageRect.origin.x    = (newSize.width - size.width * aspectRatio) / 2.0
        scaledImageRect.origin.y    = (newSize.height - size.height * aspectRatio) / 2.0
        
        let scaledImage = NSImage(size: newSize)
        scaledImage.lockFocus()
        draw(in: scaledImageRect)
        scaledImage.unlockFocus()
        
        return scaledImage
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment