Last active
          February 1, 2024 19:04 
        
      - 
      
- 
        Save tomasbasham/10533743 to your computer and use it in GitHub Desktop. 
    Scale a UIImage to any given rect keeping the aspect ratio
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | @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 | 
Swift 4
extension UIImage {
  func scale(with size: CGSize) -> UIImage? {
    var scaledImageRect = CGRect.zero
    
    let aspectWidth:CGFloat = size.width / self.size.width
    let aspectHeight:CGFloat = size.height / self.size.height
    let aspectRatio:CGFloat = min(aspectWidth, aspectHeight)
    
    scaledImageRect.size.width = self.size.width * aspectRatio
    scaledImageRect.size.height = self.size.height * aspectRatio
    scaledImageRect.origin.x = (size.width - scaledImageRect.size.width) / 2.0
    scaledImageRect.origin.y = (size.height - scaledImageRect.size.height) / 2.0
    
    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    
    self.draw(in: scaledImageRect)
    
    let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    
    return scaledImage
  }
}@shinrikiken - your code is not giving me the perfect image which should fits to the image size.
@lee-ho, perhaps you can replace this line
UIGraphicsBeginImageContext(newSize)
with this
UIGraphicsBeginImageContextWithOptions(newSize, false, UIScreen.main.scale)
and try?
Does anyone have the version of this to work in NSImage (for MacOS)?
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
  
            
Thank you for your work, guys!
@akshaynhegde, @Oyvindkg, the method returns a blurry version of the original image, it is scaled, but blurry. Any idea how to fix it?