فهرست منبع

feat: add `maxSize` parameter when extracting image frames

Yang Chao 2 سال پیش
والد
کامیت
b3872aba78
2فایلهای تغییر یافته به همراه23 افزوده شده و 22 حذف شده
  1. 20 3
      Sources/Image/GIFAnimatedImage.swift
  2. 3 19
      Sources/Views/AnimatedImageView.swift

+ 20 - 3
Sources/Image/GIFAnimatedImage.swift

@@ -133,13 +133,21 @@ public protocol ImageFrameSource {
     /// Count of total frames in this frame source.
     var frameCount: Int { get }
     
-    /// Retrieves the frame at a specific index. If the index is invalid, implementors should return `nil`.
-    func frame(at index: Int) -> CGImage?
+    /// Retrieves the frame at a specific index. The result image is expected to be
+    /// no larger than `maxSize`. If the index is invalid, implementors should return `nil`.
+    func frame(at index: Int, maxSize: CGSize?) -> CGImage?
     
     /// Retrieves the duration at a specific index. If the index is invalid, implementors should return `0.0`.
     func duration(at index: Int) -> TimeInterval
 }
 
+public extension ImageFrameSource {
+    /// Retrieves the frame at a specific index. If the index is invalid, implementors should return `nil`.
+    func frame(at index: Int) -> CGImage? {
+        return frame(at: index, maxSize: nil)
+    }
+}
+
 struct CGImageFrameSource: ImageFrameSource {
     let data: Data?
     let imageSource: CGImageSource
@@ -149,7 +157,16 @@ struct CGImageFrameSource: ImageFrameSource {
         return CGImageSourceGetCount(imageSource)
     }
 
-    func frame(at index: Int) -> CGImage? {
+    func frame(at index: Int, maxSize: CGSize?) -> CGImage? {
+        var options = self.options as? [CFString: Any]
+        if let maxSize = maxSize, maxSize != .zero {
+            options = (options ?? [:]).merging([
+                kCGImageSourceCreateThumbnailFromImageIfAbsent: true,
+                kCGImageSourceCreateThumbnailWithTransform: true,
+                kCGImageSourceShouldCacheImmediately: true,
+                kCGImageSourceThumbnailMaxPixelSize: max(maxSize.width, maxSize.height)
+            ], uniquingKeysWith: { $1 })
+        }
         return CGImageSourceCreateImageAtIndex(imageSource, index, options as CFDictionary?)
     }
 

+ 3 - 19
Sources/Views/AnimatedImageView.swift

@@ -575,25 +575,9 @@ extension AnimatedImageView {
         }
 
         private func loadFrame(at index: Int) -> UIImage? {
-            let cgImage: CGImage?
-            if let imageSource = frameSource as? CGImageFrameSource {
-                let resize = needsPrescaling && size != .zero
-                let options: [CFString: Any]?
-                if resize {
-                    options = [
-                        kCGImageSourceCreateThumbnailFromImageIfAbsent: true,
-                        kCGImageSourceCreateThumbnailWithTransform: true,
-                        kCGImageSourceShouldCacheImmediately: true,
-                        kCGImageSourceThumbnailMaxPixelSize: max(size.width, size.height)
-                    ]
-                } else {
-                    options = nil
-                }
-                cgImage = CGImageSourceCreateImageAtIndex(imageSource.imageSource, index, options as CFDictionary?)
-            } else {
-                cgImage = frameSource.frame(at: index)
-            }
-            guard let cgImage = cgImage else {
+            let resize = needsPrescaling && size != .zero
+            let maxSize = resize ? size : nil
+            guard let cgImage = frameSource.frame(at: index, maxSize: maxSize) else {
                 return nil
             }