I have this extension and it works perfect in app target but crash in share extension when trying to rotate image captured on camera. How to rotate image in share extension? Or maybe it possible to load image from Photo Library already in right orientation.
extension UIImage {
func fixOrientation() -> UIImage {
switch imageOrientation {
case .up:
return self
default:
UIGraphicsBeginImageContextWithOptions(size, false, scale)
draw(in: CGRect(origin: .zero, size: size)) //Thread 1: EXC_RESOURCE RESOURCE_TYPE_MEMORY (limit=120 MB, unused=0x0)
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return result!
}
}
}
Crash screenshots:
First of all it is clear that you have a memory crash. According to App Extension Programming Guide:
Memory limits for running app extensions are significantly lower than the memory limits imposed on a foreground app. On both platforms, the system may aggressively terminate extensions because users want to return to their main goal in the host app.
And from error it is clear that you exceed 120 mb. But you might wonder what is took so much memory.
According to Optimizing Images Written by Jordan Morgan:
iOS essentially derives its memory hit from an image’s dimensions - whereas the actual file size has much less to do with it.
So if we calculate size or 4032 x 3024 photo it will be... 46mb for 4 bit color and 79mb for 8 bit color. Pretty big, but still less that a limit...
Thing is - you have two copies of your image. One is original and second one - rotated.
To solve this issue you need load only rotated image into memory, without original. This can be done with Image I/O Framework:
extension UIImage {
static func imageWithFixedOrientation(at url: URL) -> UIImage? {
guard let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil) else { return nil }
guard let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? Dictionary<CFString, Any> else { return nil }
guard
let width = imageProperties[kCGImagePropertyPixelWidth] as? CGFloat,
let height = imageProperties[kCGImagePropertyPixelHeight] as? CGFloat
else { return nil }
let options: [NSString: Any] = [
kCGImageSourceThumbnailMaxPixelSize: max(width, height),
kCGImageSourceCreateThumbnailFromImageAlways: true,
kCGImageSourceCreateThumbnailWithTransform: true
]
guard let cgImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary) else { return nil }
return UIImage(cgImage: cgImage)
}
}
In sample app:
extension ViewController: UIImagePickerControllerDelegate & UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true)
guard let url = info[.imageURL] as? URL else { return }
let image = UIImage.imageWithFixedOrientation(at: url)
}
}
it reduced memory peaks from 180+mb to just 80mb.
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