The task is to resize an image.
I have read this post and adopted CGBitmapContextCreate & CGContextDrawImage approach. That is how my resizing function looks like:
extension UIImage {
func with(maxHeight: CGFloat, maxWidth: CGFloat) -> UIImage? {
guard let image = self.cgImage else {
return nil
}
var height = CGFloat(image.height)
var width = CGFloat(image.width)
guard height > 0 && width > 0 else {
return nil
}
let maxHeight = round(maxHeight)
let maxWidth = round(maxWidth)
guard height > maxHeight || width > maxWidth else {
return nil
}
let heightProportions = height / maxHeight
let widthProportions = width / maxWidth
height = heightProportions > widthProportions ? maxHeight : round(height / widthProportions)
width = widthProportions > heightProportions ? maxWidth : round(width / heightProportions)
let size = CGSize(width: width, height: height)
let bitmapInfo = image.bitmapInfo.rawValue
let bitsPerComponent = image.bitsPerComponent
let bytesPerRow = image.bytesPerRow
let space = image.colorSpace ?? CGColorSpaceCreateDeviceRGB()
let context = CGContext(data: nil, width: Int(width), height: Int(height), bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: space, bitmapInfo: bitmapInfo)
context?.interpolationQuality = .high
context?.draw(image, in: CGRect.init(origin: .zero, size: size))
guard let newImage = context?.makeImage() else {
return nil
}
return UIImage(cgImage: newImage)
}
}
This function did work well during testing but I've got a crash in production at line:
context?.draw(image, in: CGRect.init(origin: .zero, size: size))
Stacktrace:
#11. Crashed: com.apple.root.utility-qos
0 CoreGraphics 0x184d9a59c ERROR_CGDataProvider_BufferIsNotReadable + 12
1 CoreGraphics 0x184d9a2c0 CGDataProviderRetainBytePtr + 216
2 CoreGraphics 0x184e8d06c get_image_pointer + 64
3 CoreGraphics 0x184e8d2c8 img_raw_access + 52
4 CoreGraphics 0x184e88000 img_interpolate_read + 708
5 CoreGraphics 0x184e8c14c img_data_lock + 7048
6 CoreGraphics 0x184e8a56c CGSImageDataLock + 184
7 CoreGraphics 0x184caa628 ripc_AcquireRIPImageData + 308
8 CoreGraphics 0x184e9f1b0 ripc_DrawImage + 644
9 CoreGraphics 0x184e8efac CGContextDrawImageWithOptions + 632
10 libswiftCoreGraphics.dylib 0x104781638 (Missing)
So, I have two questions:
I use this simpler extension to wrap UIImage's draw(in:)
. I have found it to be high quality and reasonably fast.
extension UIImage {
public func resized(maxSize: CGSize) -> UIImage? {
let imageSize = self.size
guard imageSize.height > 0, imageSize.width > 0 else { return nil }
let ratio = min(maxSize.width/imageSize.width, maxSize.height/imageSize.height)
let newSize = CGSize(width: imageSize.width*ratio, height: imageSize.height*ratio)
let renderer = UIGraphicsImageRenderer(size: newSize)
return renderer.image(actions: { (ctx) in
self.draw(in: CGRect(origin: .zero, size: newSize))
})
}
}
Usage:
let resizedImage = myImage.resized(maxSize: CGSize(width: maxWidth, height: maxHeight))
Note that the size here is measured in points, meaning that the underlying number of pixels will be automatically multiplied by the device's scale factor (e.g. 2x for retina displays). In other words, this method is designed for situations where the resulting UIImage will be shown on screen.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With