Skip to content

Commit

Permalink
avoid recreating animated image representation if reloaded with same …
Browse files Browse the repository at this point in the history
…options
  • Loading branch information
yeatse committed Jan 18, 2025
1 parent 8769e7c commit d729a94
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Sources/General/KingfisherManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ public class KingfisherManager: @unchecked Sendable {
// TODO: Optimize it when we can use async across all the project.
@Sendable func checkResultImageAndCallback(_ inputImage: KFCrossPlatformImage) {
var image = inputImage
if image.kf.imageFrameCount != nil && image.kf.imageFrameCount != 1, let data = image.kf.animatedImageData {
if image.kf.imageFrameCount != nil && image.kf.imageFrameCount != 1, options.imageCreatingOptions != image.kf.imageCreatingOptions, let data = image.kf.animatedImageData {
// Always recreate animated image representation since it is possible to be loaded in different options.
// https://github.com/onevcat/Kingfisher/issues/1923
image = options.processor.process(item: .data(data), options: options) ?? .init()
Expand Down
2 changes: 1 addition & 1 deletion Sources/Image/GIFAnimatedImage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import Foundation
import ImageIO

/// Represents a set of image creation options used in Kingfisher.
public struct ImageCreatingOptions {
public struct ImageCreatingOptions: Equatable {

/// The target scale of the image that needs to be created.
public var scale: CGFloat
Expand Down
9 changes: 9 additions & 0 deletions Sources/Image/Image.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import UniformTypeIdentifiers
nonisolated(unsafe) private let animatedImageDataKey = malloc(1)!
nonisolated(unsafe) private let imageFrameCountKey = malloc(1)!
nonisolated(unsafe) private let imageSourceKey = malloc(1)!
nonisolated(unsafe) private let imageCreatingOptionsKey = malloc(1)!
#if os(macOS)
nonisolated(unsafe) private let imagesKey = malloc(1)!
nonisolated(unsafe) private let durationKey = malloc(1)!
Expand All @@ -55,6 +56,7 @@ nonisolated(unsafe) private let durationKey = malloc(1)!
private let animatedImageDataKey = malloc(1)!
private let imageFrameCountKey = malloc(1)!
private let imageSourceKey = malloc(1)!
private let imageCreatingOptionsKey = malloc(1)!
#if os(macOS)
private let imagesKey = malloc(1)!
private let durationKey = malloc(1)!
Expand All @@ -68,6 +70,11 @@ extension KingfisherWrapper where Base: KFCrossPlatformImage {
set { setRetainedAssociatedObject(base, animatedImageDataKey, newValue) }
}

private(set) var imageCreatingOptions: ImageCreatingOptions? {
get { return getAssociatedObject(base, imageCreatingOptionsKey) }
set { setRetainedAssociatedObject(base, imageCreatingOptionsKey, newValue) }
}

public var imageFrameCount: Int? {
get { return getAssociatedObject(base, imageFrameCountKey) }
set { setRetainedAssociatedObject(base, imageFrameCountKey, newValue) }
Expand Down Expand Up @@ -359,6 +366,7 @@ extension KingfisherWrapper where Base: KFCrossPlatformImage {
image?.kf.animatedImageData = source.data
image?.kf.imageFrameCount = source.frameCount
image?.kf.frameSource = source
image?.kf.imageCreatingOptions = options
return image
#else

Expand Down Expand Up @@ -390,6 +398,7 @@ extension KingfisherWrapper where Base: KFCrossPlatformImage {
}

image?.kf.imageFrameCount = source.frameCount
image?.kf.imageCreatingOptions = options
return image
#endif
}
Expand Down
19 changes: 19 additions & 0 deletions Tests/KingfisherTests/KingfisherManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1352,6 +1352,25 @@ class KingfisherManagerTests: XCTestCase {
waitForExpectations(timeout: 3, handler: nil)
}

func testAnimatedImageShouldNotRecreateWithSameOptions() {
let exp = expectation(description: #function)
let url = testURLs[0]
let data = testImageGIFData
stub(url, data: data)
let p = SimpleProcessor()
manager.retrieveImage(with: url, options: [.processor(p), .onlyLoadFirstFrame]) { result in
XCTAssertTrue(p.processed)
XCTAssertTrue(result.value!.image.creatingOptions!.onlyFirstFrame)
p.processed = false
self.manager.retrieveImage(with: url, options: [.processor(p), .onlyLoadFirstFrame]) { result in
XCTAssertFalse(p.processed)
XCTAssertTrue(result.value!.image.creatingOptions!.onlyFirstFrame)
exp.fulfill()
}
}
waitForExpectations(timeout: 3, handler: nil)
}

func testMissingResourceOfLivePhotoFound() {
let resource = KF.ImageResource(downloadURL: LivePhotoURL.mov)
let source = LivePhotoSource(resources: [resource])
Expand Down

0 comments on commit d729a94

Please sign in to comment.