Search code examples
iosswiftxcodeswift3uiimage

Why is my image quality decreasing when setting the radius and size?


I am using the following methods in a UIImage extension to use an image from a URL and displaying it as a UIBarButtonItem. However, when I use the following to adjust the corner radius and size, the quality of the image gets significantly worse. What needs to change to prevent it from decreasing in quality?

extension UIImage {

    public func withRoundedCornersAndSetSize(radius: CGFloat? = nil, size: CGSize) -> UIImage? {
        let maxRadius = min(size.width, size.height) / 2
        let cornerRadius: CGFloat
        if let radius = radius, radius > 0 && radius <= maxRadius {
            cornerRadius = radius
        } else {
            cornerRadius = maxRadius
        }
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        let rect = CGRect(origin: .zero, size: size)
        UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius).addClip()
        draw(in: rect)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

Solution

  • I figured out that I could resize the UIImage without losing quality using the resize() method in the following code. Then, I just used this in the withRoundedCornersAndSetSize() method that I had initially asked about.

    extension UIImage {
       func withRoundedCornersAndSetSize(radius: CGFloat? = nil, targetSize: CGSize) -> UIImage? {
            let resizedImage = self.resize(targetSize: targetSize)
            
            let maxRadius = min(resizedImage.size.width, resizedImage.size.height) / 2
            let cornerRadius: CGFloat
            if let radius = radius, radius > 0 && radius <= maxRadius {
                cornerRadius = radius
            } else {
                cornerRadius = maxRadius
            }
    
            UIGraphicsBeginImageContextWithOptions(resizedImage.size, false, resizedImage.scale)
            let rect = CGRect(origin: .zero, size: resizedImage.size)
            UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius).addClip()
            draw(in: rect)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return image!
        }
        
        func resize(targetSize: CGSize) -> UIImage {
            return UIGraphicsImageRenderer(size:targetSize).image { _ in
                self.draw(in: CGRect(origin: .zero, size: targetSize))
            }
        }
    }