From 2498f984a96c38498c07e0887ee41f4a161eb986 Mon Sep 17 00:00:00 2001 From: Ido Zaltzberg Date: Thu, 18 Feb 2021 17:28:11 +0200 Subject: [PATCH 1/2] This PR adds two additional methods: `resolveImageData` for a single `Image` and for an array of `Image`s. These will extract the Asset's metadata and will return it as a parameter to the completion block, in addition to the actual UIImage. Also cleaned up the `Image` class and fixed documentation. --- Sources/Gallery/Images/Image.swift | 73 ++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 10 deletions(-) diff --git a/Sources/Gallery/Images/Image.swift b/Sources/Gallery/Images/Image.swift index 61f73f09..afa714ff 100644 --- a/Sources/Gallery/Images/Image.swift +++ b/Sources/Gallery/Images/Image.swift @@ -13,14 +13,43 @@ public class Image: Equatable { } } +// MARK: - UIImage with metadata typealias +public typealias UIImageData = (UIImage, CGImageMetadata) + // MARK: - UIImage extension Image { - /// Resolve UIImage synchronously - /// - /// - Parameter size: The target size - /// - Returns: The resolved UIImage, otherwise nil + /// Resolve UIImage and it's metadata asynchronously + /// - Parameters: + /// - completion: A block to be called when the process is complete. The block takes the resolved UIImage and its CGImageMetadata + /// as parameters. + public func resolveImageData(completion: @escaping (UIImageData) -> Void) { + let options = PHImageRequestOptions() + options.isNetworkAccessAllowed = true + options.deliveryMode = .highQualityFormat + PHImageManager.default().requestImageData(for: asset, options: options) { imageData, dataUTI, _, _ in + var destData = NSMutableData() as CFMutableData + guard let imageData = imageData, + let dataUTI = dataUTI, + let imageSource = CGImageSourceCreateWithData(imageData as CFData, nil), + let imageDestination = CGImageDestinationCreateWithData(destData, dataUTI as CFString, 1, nil), + let imageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) else { + return + } + CGImageDestinationAddImage(imageDestination, imageRef, nil) + CGImageDestinationFinalize(imageDestination) + guard let imageMetadata = CGImageSourceCopyMetadataAtIndex(imageSource, 0, nil), + let image = UIImage(data: destData as Data) else { + return + } + completion(UIImageData(image, imageMetadata)) + } + } + + /// Resolve UIImage asynchronously + /// - Parameters: + /// - completion: A block to be called when image resolving is complete. The block takes the resolved UIImage as a parameter. public func resolve(completion: @escaping (UIImage?) -> Void) { let options = PHImageRequestOptions() options.isNetworkAccessAllowed = true @@ -31,16 +60,40 @@ extension Image { targetSize: PHImageManagerMaximumSize, contentMode: .default, options: options) { (image, _) in - completion(image) + completion(image) } } - /// Resolve an array of Image - /// + /// Resolve an array of Images and their metadata + /// - Parameters: + /// - images: The array of Images + /// - completion: A block to be called when the process is complete. The block takes the array of resolved UIImages and their + /// CGImageMetadata as parameters. + public static func resolveImageData(images: [Image], completion: @escaping ([UIImageData]) -> Void) { + let dispatchGroup = DispatchGroup() + var convertedImages = [Int: UIImageData]() + + for (index, image) in images.enumerated() { + dispatchGroup.enter() + + image.resolveImageData(completion: { resolvedImage, metadata in + convertedImages[index] = (resolvedImage, metadata) + dispatchGroup.leave() + }) + } + + dispatchGroup.notify(queue: .main, execute: { + let sortedImages = convertedImages + .sorted(by: { $0.key < $1.key }) + .map({ $0.value }) + completion(sortedImages) + }) + } + + /// Resolve an array of Images /// - Parameters: - /// - images: The array of Image - /// - size: The target size for all images - /// - completion: Called when operations completion + /// - images: The array of Images + /// - completion: A block to be called when the process is complete. The block takes the array of resolved UIImages as a parameter. public static func resolve(images: [Image], completion: @escaping ([UIImage?]) -> Void) { let dispatchGroup = DispatchGroup() var convertedImages = [Int: UIImage]() From 09f80b8758869717665f6aa02eb99419a1286971 Mon Sep 17 00:00:00 2001 From: Ido Zaltzberg Date: Sun, 21 Feb 2021 18:20:16 +0200 Subject: [PATCH 2/2] tweaks --- Sources/Gallery/Images/Image.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Gallery/Images/Image.swift b/Sources/Gallery/Images/Image.swift index afa714ff..4c657f63 100644 --- a/Sources/Gallery/Images/Image.swift +++ b/Sources/Gallery/Images/Image.swift @@ -14,7 +14,7 @@ public class Image: Equatable { } // MARK: - UIImage with metadata typealias -public typealias UIImageData = (UIImage, CGImageMetadata) +public typealias UIImageData = (image: UIImage, metadata: CGImageMetadata) // MARK: - UIImage @@ -29,7 +29,7 @@ extension Image { options.isNetworkAccessAllowed = true options.deliveryMode = .highQualityFormat PHImageManager.default().requestImageData(for: asset, options: options) { imageData, dataUTI, _, _ in - var destData = NSMutableData() as CFMutableData + let destData = NSMutableData() as CFMutableData guard let imageData = imageData, let dataUTI = dataUTI, let imageSource = CGImageSourceCreateWithData(imageData as CFData, nil),