Created
February 25, 2022 05:37
-
-
Save yhkaplan/58c94ab5c711a829e9374bc32d3bc76b to your computer and use it in GitHub Desktop.
Downsample images to reduce memory impact
This file contains 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
enum ImageDownsampler { | |
private static let pixelSize = 2_000 | |
/// - URL: https://christianselig.com/2020/09/phpickerviewcontroller-efficiently/ | |
static func downsample(imageAt url: URL) -> Data? { | |
let sourceOptions: [CFString: Any] = [kCGImageSourceShouldCache: false] | |
let downsampleOptions: [CFString: Any] = [ | |
kCGImageSourceCreateThumbnailFromImageAlways: true, | |
kCGImageSourceCreateThumbnailWithTransform: true, | |
kCGImageSourceThumbnailMaxPixelSize: pixelSize | |
] | |
let destinationOptions: [CFString: Any] = [ | |
kCGImageDestinationLossyCompressionQuality: 0.95 | |
] | |
let data = NSMutableData() | |
guard | |
let source = CGImageSourceCreateWithURL(url as CFURL, sourceOptions as CFDictionary), | |
let cgImage = CGImageSourceCreateThumbnailAtIndex(source, 0, downsampleOptions as CFDictionary), | |
let imageDestination = CGImageDestinationCreateWithData(data, kUTTypeJPEG, 1, nil) | |
else { return nil } | |
CGImageDestinationAddImage(imageDestination, cgImage, destinationOptions as CFDictionary) | |
CGImageDestinationFinalize(imageDestination) | |
return data as Data | |
} | |
static func downsample(data sourceData: Data, quality: CGFloat) -> Data? { | |
let sourceOptions: [CFString: Any] = [kCGImageSourceShouldCache: false] | |
let downsampleOptions: [CFString: Any] = [ | |
kCGImageSourceCreateThumbnailFromImageAlways: true, | |
kCGImageSourceCreateThumbnailWithTransform: true, | |
kCGImageSourceThumbnailMaxPixelSize: pixelSize | |
] | |
let destinationOptions: [CFString: Any] = [ | |
kCGImageDestinationLossyCompressionQuality: quality | |
] | |
let targetData = NSMutableData() | |
guard | |
let source = CGImageSourceCreateWithData(sourceData as CFData, sourceOptions as CFDictionary), | |
let cgImage = CGImageSourceCreateThumbnailAtIndex(source, 0, downsampleOptions as CFDictionary), | |
let imageDestination = CGImageDestinationCreateWithData(targetData, kUTTypeJPEG, 1, nil) | |
else { return nil } | |
CGImageDestinationAddImage(imageDestination, cgImage, destinationOptions as CFDictionary) | |
CGImageDestinationFinalize(imageDestination) | |
return targetData as Data | |
} | |
/// - URL: https://developer.apple.com/videos/play/wwdc2018-219/?time=640 | |
static func downsample(imageAt data: Data, toSize size: CGSize, scale: CGFloat) -> UIImage? { | |
let sourceOptions: [CFString: Any] = [kCGImageSourceShouldCache: false] | |
let maxPixelSize: CGFloat = max(size.height, size.width) * scale | |
let downsampleOptions: [CFString: Any] = [ | |
kCGImageSourceCreateThumbnailFromImageAlways: true, | |
kCGImageSourceShouldCacheImmediately: true, | |
kCGImageSourceCreateThumbnailWithTransform: true, | |
kCGImageSourceThumbnailMaxPixelSize: maxPixelSize | |
] | |
guard | |
let imageSource = CGImageSourceCreateWithData(data as CFData, sourceOptions as CFDictionary), | |
let downsampledImage = CGImageSourceCreateThumbnailAtIndex( | |
imageSource, | |
0, | |
downsampleOptions as CFDictionary | |
) | |
else { return nil } | |
return UIImage(cgImage: downsampledImage) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment