I was trying to create a thumbnail from a shared image via extension and saw that when loading an UIImage
from url provided by NSItemProvider
and then creating a thumbnail via:
UIGraphicsImageRenderer(bounds: thumbnailBounds).image { context in
image.draw(in: thumbnailBounds)
}
Would cause memory overflow on the extension (>120mb) for larger images. The solution for me was to downsample the image before creating an UIImage
directly from the url to a reasonable size in pixels for my app so it was manageable by the share extension without causing a memory overflow.
private func resizeForUpload(_ imageURL: URL) -> UIImage? {
let imageSourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary
let maxDimensionInPixels: CGFloat = 2000
let downsampleOptions = [kCGImageSourceCreateThumbnailFromImageAlways: true,
kCGImageSourceShouldCacheImmediately: true,
kCGImageSourceCreateThumbnailWithTransform: true,
kCGImageSourceThumbnailMaxPixelSize: maxDimensionInPixels] as CFDictionary
guard let imageSource = CGImageSourceCreateWithURL(imageURL as CFURL, imageSourceOptions), let downsampledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, downsampleOptions) else {
return nil
}
return UIImage(cgImage: downsampledImage)
}
This is the way to use private func resizeForUpload(_ imageURL: URL) -> UIImage?
if itemProvider.hasItemConformingToTypeIdentifier(SystemUTType.image) {
itemProvider.loadItem(forTypeIdentifier: SystemUTType.image, options: nil) { secureCoding, error in
if let url = secureCoding as? URL,
let image = self.resizeForUpload(url) {
// The iOS Photos app comes here.
completion(image, nil)
} else if let image = secureCoding as? UIImage {
// The iOS screenshot editor comes here.
// The iOS Notes app comes here.
completion(image, nil)
} else if let data = secureCoding as? Data,
let image = UIImage(data: data) {
completion(image, nil)
} else {
completion(nil, error)
}
}