فهرست منبع

Downloader support for live photo

Ignores processor since only file representation is required
onevcat 1 سال پیش
والد
کامیت
fd37da7481
3فایلهای تغییر یافته به همراه122 افزوده شده و 0 حذف شده
  1. 4 0
      Kingfisher.xcodeproj/project.pbxproj
  2. 19 0
      Sources/Image/ImageProcessor.swift
  3. 99 0
      Sources/Networking/ImageDownloader+LivePhoto.swift

+ 4 - 0
Kingfisher.xcodeproj/project.pbxproj

@@ -66,6 +66,7 @@
 		D12E0C571C47F23500AC98AD /* KingfisherTestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D12E0C4C1C47F23500AC98AD /* KingfisherTestHelper.swift */; };
 		D12E0C581C47F23500AC98AD /* UIButtonExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D12E0C4E1C47F23500AC98AD /* UIButtonExtensionTests.swift */; };
 		D12EB83C24DD8EFC00329EE1 /* NSTextAttachment+Kingfisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = D12EB83B24DD8EFC00329EE1 /* NSTextAttachment+Kingfisher.swift */; };
+		D12F67602CAC2DBF00AB63AB /* ImageDownloader+LivePhoto.swift in Sources */ = {isa = PBXBuildFile; fileRef = D12F675F2CAC2DB700AB63AB /* ImageDownloader+LivePhoto.swift */; };
 		D13646742165A1A100A33652 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = D13646732165A1A100A33652 /* Result.swift */; };
 		D16CC3D624E02E9500F1A515 /* AVAssetImageDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = D16CC3D524E02E9500F1A515 /* AVAssetImageDataProvider.swift */; };
 		D16FEA3A23078C63006E67D5 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = D16FE9F623078C63006E67D5 /* LICENSE */; };
@@ -213,6 +214,7 @@
 		D12E0C4D1C47F23500AC98AD /* KingfisherTests-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "KingfisherTests-Bridging-Header.h"; sourceTree = "<group>"; };
 		D12E0C4E1C47F23500AC98AD /* UIButtonExtensionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIButtonExtensionTests.swift; sourceTree = "<group>"; };
 		D12EB83B24DD8EFC00329EE1 /* NSTextAttachment+Kingfisher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSTextAttachment+Kingfisher.swift"; sourceTree = "<group>"; };
+		D12F675F2CAC2DB700AB63AB /* ImageDownloader+LivePhoto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ImageDownloader+LivePhoto.swift"; sourceTree = "<group>"; };
 		D1356CEA2B273AEC009554C8 /* Documentation.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = Documentation.docc; sourceTree = "<group>"; };
 		D13646732165A1A100A33652 /* Result.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Result.swift; sourceTree = "<group>"; };
 		D16CC3D524E02E9500F1A515 /* AVAssetImageDataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVAssetImageDataProvider.swift; sourceTree = "<group>"; };
@@ -361,6 +363,7 @@
 				D12AB69D215D2BB50013BA68 /* RequestModifier.swift */,
 				D8FCF6A721C5A0E500F9ABC0 /* RedirectHandler.swift */,
 				D12AB69F215D2BB50013BA68 /* ImageDownloader.swift */,
+				D12F675F2CAC2DB700AB63AB /* ImageDownloader+LivePhoto.swift */,
 				4BD821612189FC0C0084CC21 /* SessionDelegate.swift */,
 				4BD821662189FD330084CC21 /* SessionDataTask.swift */,
 				4B8E2916216F3F7F0095FAD1 /* ImageDownloaderDelegate.swift */,
@@ -857,6 +860,7 @@
 				388F37382B4D9CDB0089705C /* DisplayLink.swift in Sources */,
 				D12AB6F4215D2BB50013BA68 /* ImageView+Kingfisher.swift in Sources */,
 				D12AB6FC215D2BB50013BA68 /* UIButton+Kingfisher.swift in Sources */,
+				D12F67602CAC2DBF00AB63AB /* ImageDownloader+LivePhoto.swift in Sources */,
 				D12AB6E8215D2BB50013BA68 /* GIFAnimatedImage.swift in Sources */,
 				22FDCE0E2700078B0044D11E /* CPListItem+Kingfisher.swift in Sources */,
 				D13646742165A1A100A33652 /* Result.swift in Sources */,

+ 19 - 0
Sources/Image/ImageProcessor.swift

@@ -818,6 +818,25 @@ public struct DownsamplingImageProcessor: ImageProcessor {
     }
 }
 
+// This is an internal processor to provide the same interface for Live Photos.
+// It is not intended to be open and used from external.
+struct LivePhotoImageProcessor: ImageProcessor {
+    
+    public static let `default` = LivePhotoImageProcessor()
+    private init() { }
+    
+    public let identifier = "com.onevcat.Kingfisher.LivePhotoImageProcessor"
+    
+    public func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? {
+        switch item {
+        case .image(let image):
+            return image
+        case .data:
+            return KFCrossPlatformImage()
+        }
+    }
+}
+
 infix operator |>: AdditionPrecedence
 
 /// Concatenates two `ImageProcessor`s to create a new one, in which the `left` and `right` are combined in order to 

+ 99 - 0
Sources/Networking/ImageDownloader+LivePhoto.swift

@@ -0,0 +1,99 @@
+//
+//  ImageDownloader+LivePhoto.swift
+//  Kingfisher
+//
+//  Created by onevcat on 2024/10/01.
+//
+//  Copyright (c) 2024 Wei Wang <onevcat@gmail.com>
+//
+//  Permission is hereby granted, free of charge, to any person obtaining a copy
+//  of this software and associated documentation files (the "Software"), to deal
+//  in the Software without restriction, including without limitation the rights
+//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+//  copies of the Software, and to permit persons to whom the Software is
+//  furnished to do so, subject to the following conditions:
+//
+//  The above copyright notice and this permission notice shall be included in
+//  all copies or substantial portions of the Software.
+//
+//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+//  THE SOFTWARE.
+
+#if os(macOS)
+import AppKit
+#else
+import UIKit
+#endif
+
+public struct LivePhotoResourceLoadingResult: Sendable {
+    
+    /// The original URL of the image request.
+    public let url: URL?
+
+    /// The raw data received from the downloader.
+    public let originalData: Data
+
+    /// Creates an `ImageDownloadResult` object.
+    ///
+    /// - Parameters:
+    ///   - image: The image of the download result.
+    ///   - url: The URL from which the image was downloaded.
+    ///   - originalData: The binary data of the image.
+    public init(originalData: Data, url: URL? = nil) {
+        self.url = url
+        self.originalData = originalData
+    }
+}
+
+extension ImageDownloader {
+    
+    public func downloadLivePhotoResource(
+        with url: URL,
+        options: KingfisherParsedOptionsInfo
+    ) async throws -> LivePhotoResourceLoadingResult {
+        let task = CancellationDownloadTask()
+        return try await withTaskCancellationHandler {
+            try await withCheckedThrowingContinuation { continuation in
+                let downloadTask = downloadLivePhotoResource(with: url, options: options) { result in
+                    continuation.resume(with: result)
+                }
+                if Task.isCancelled {
+                    downloadTask.cancel()
+                } else {
+                    Task {
+                        await task.setTask(downloadTask)
+                    }
+                }
+            }
+        } onCancel: {
+            Task {
+                await task.task?.cancel()
+            }
+        }
+    }
+    
+    @discardableResult
+    public func downloadLivePhotoResource(
+        with url: URL,
+        options: KingfisherParsedOptionsInfo,
+        completionHandler: (@Sendable (Result<LivePhotoResourceLoadingResult, KingfisherError>) -> Void)? = nil
+    ) -> DownloadTask {
+        var checkedOptions = options
+        if options.processor != LivePhotoImageProcessor.default {
+            assertionFailure("[Kingfisher] Using of custom processors during loading of live photo resource is not supported.")
+            checkedOptions.processor = LivePhotoImageProcessor.default
+        }
+        return downloadImage(with: url, options: checkedOptions) { result in
+            guard let completionHandler else {
+                return
+            }
+            let newResult = result.map { LivePhotoResourceLoadingResult(originalData: $0.originalData, url: $0.url) }
+            completionHandler(newResult)
+        }
+    }
+}