Sfoglia il codice sorgente

Merge pull request #3708 from dreampiggy/bugfix/sdanimatedimage_check

Fix some regression when SDAnimatedImage created with static format like JPEG
DreamPiggy 1 anno fa
parent
commit
cb75c084c0

+ 13 - 3
SDWebImage/Core/SDAnimatedImage.m

@@ -335,7 +335,7 @@ static CGFloat SDImageScaleFromPath(NSString *string) {
 @implementation SDAnimatedImage (Metadata)
 
 - (BOOL)sd_isAnimated {
-    return YES;
+    return self.animatedImageFrameCount > 1;
 }
 
 - (NSUInteger)sd_imageLoopCount {
@@ -347,11 +347,21 @@ static CGFloat SDImageScaleFromPath(NSString *string) {
 }
 
 - (NSUInteger)sd_imageFrameCount {
-    return self.animatedImageFrameCount;
+    NSUInteger frameCount = self.animatedImageFrameCount;
+    if (frameCount > 1) {
+        return frameCount;
+    } else {
+        return 1;
+    }
 }
 
 - (SDImageFormat)sd_imageFormat {
-    return self.animatedImageFormat;
+    NSData *animatedImageData = self.animatedImageData;
+    if (animatedImageData) {
+        return [NSData sd_imageFormatForImageData:animatedImageData];
+    } else {
+        return [super sd_imageFormat];
+    }
 }
 
 - (void)setSd_imageFormat:(SDImageFormat)sd_imageFormat {

+ 2 - 2
SDWebImage/Core/SDAnimatedImageView.m

@@ -129,12 +129,12 @@
     
     // We need call super method to keep function. This will impliedly call `setNeedsDisplay`. But we have no way to avoid this when using animated image. So we call `setNeedsDisplay` again at the end.
     super.image = image;
-    if ([image.class conformsToProtocol:@protocol(SDAnimatedImage)]) {
+    if ([image.class conformsToProtocol:@protocol(SDAnimatedImage)] && [(id<SDAnimatedImage>)image animatedImageFrameCount] > 1) {
         if (!self.player) {
             id<SDAnimatedImageProvider> provider;
             // Check progressive loading
             if (self.isProgressive) {
-                provider = [self progressiveAnimatedCoderForImage:image];
+                provider = [(id<SDAnimatedImage>)image animatedCoder];
             } else {
                 provider = (id<SDAnimatedImage>)image;
             }

+ 9 - 6
SDWebImage/Core/SDWebImageDefine.m

@@ -83,9 +83,10 @@ inline UIImage * _Nullable SDScaledImageForScaleFactor(CGFloat scale, UIImage *
                 scaledImage = [[image.class alloc] initWithData:data scale:scale];
             }
         }
-        if (scaledImage) {
-            return scaledImage;
-        }
+    }
+    if (scaledImage) {
+        SDImageCopyAssociatedObject(image, scaledImage);
+        return scaledImage;
     }
     if (image.sd_isAnimated) {
         UIImage *animatedImage;
@@ -100,7 +101,6 @@ inline UIImage * _Nullable SDScaledImageForScaleFactor(CGFloat scale, UIImage *
         }
         
         animatedImage = [UIImage animatedImageWithImages:scaledImages duration:image.duration];
-        animatedImage.sd_imageLoopCount = image.sd_imageLoopCount;
 #else
         // Animated GIF for `NSImage` need to grab `NSBitmapImageRep`;
         NSRect imageRect = NSMakeRect(0, 0, image.size.width, image.size.height);
@@ -124,9 +124,12 @@ inline UIImage * _Nullable SDScaledImageForScaleFactor(CGFloat scale, UIImage *
         scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:kCGImagePropertyOrientationUp];
 #endif
     }
-    SDImageCopyAssociatedObject(image, scaledImage);
+    if (scaledImage) {
+        SDImageCopyAssociatedObject(image, scaledImage);
+        return scaledImage;
+    }
     
-    return scaledImage;
+    return nil;
 }
 
 #pragma mark - Context option

+ 10 - 1
SDWebImage/Core/UIImage+Metadata.h

@@ -24,6 +24,8 @@
  * NSImage currently only support animated via `NSBitmapImageRep`(GIF) or `SDAnimatedImageRep`(APNG/GIF/WebP) unlike UIImage.
  * The getter of this property will get the loop count from animated imageRep
  * The setter of this property will set the loop count from animated imageRep
+ * SDAnimatedImage:
+ * Returns `animatedImageLoopCount`
  */
 @property (nonatomic, assign) NSUInteger sd_imageLoopCount;
 
@@ -35,6 +37,8 @@
  * AppKit:
  * Returns the underlaying `NSBitmapImageRep` or `SDAnimatedImageRep` frame count.
  * Returns 1 for static image.
+ * SDAnimatedImage:
+ * Returns `animatedImageFrameCount` for animated image, 1 for static image.
  */
 @property (nonatomic, assign, readonly) NSUInteger sd_imageFrameCount;
 
@@ -42,7 +46,9 @@
  * UIKit:
  * Check the `images` array property.
  * AppKit:
- * NSImage currently only support animated via GIF imageRep unlike UIImage. It will check the imageRep's frame count.
+ * NSImage currently only support animated via GIF imageRep unlike UIImage. It will check the imageRep's frame count > 1.
+ * SDAnimatedImage:
+ * Check `animatedImageFrameCount` > 1
  */
 @property (nonatomic, assign, readonly) BOOL sd_isAnimated;
 
@@ -51,6 +57,8 @@
  * Check the `isSymbolImage` property. Also check the system PDF(iOS 11+) && SVG(iOS 13+) support.
  * AppKit:
  * NSImage supports PDF && SVG && EPS imageRep, check the imageRep class.
+ * SDAnimatedImage:
+ * Returns `NO`
  */
 @property (nonatomic, assign, readonly) BOOL sd_isVector;
 
@@ -58,6 +66,7 @@
  * The image format represent the original compressed image data format.
  * If you don't manually specify a format, this information is retrieve from CGImage using `CGImageGetUTType`, which may return nil for non-CG based image. At this time it will return `SDImageFormatUndefined` as default value.
  * @note Note that because of the limitations of categories this property can get out of sync if you create another instance with CGImage or other methods.
+ * @note For `SDAnimatedImage`, returns `animatedImageFormat` when animated, or fallback when static.
  */
 @property (nonatomic, assign) SDImageFormat sd_imageFormat;
 

+ 16 - 0
Tests/Tests/SDAnimatedImageTest.m

@@ -786,6 +786,22 @@ static BOOL _isCalled;
 }
 #endif
 
+- (void)test37AnimatedImageWithStaticDataBehavior {
+    UIImage *image = [[SDAnimatedImage alloc] initWithData:[self testJPEGData]];
+    // UIImage+Metadata.h
+    expect(image).notTo.beNil();
+    expect(image.sd_isAnimated).beFalsy();
+    expect(image.sd_imageFormat).equal(SDImageFormatJPEG);
+    expect(image.sd_imageFrameCount).equal(1);
+    expect(image.sd_imageLoopCount).equal(0);
+    // SDImageCoderHelper.h
+    UIImage *decodedImage = [SDImageCoderHelper decodedImageWithImage:image policy:SDImageForceDecodePolicyAutomatic];
+    expect(decodedImage).notTo.equal(image);
+    // SDWebImageDefine.h
+    UIImage *scaledImage = SDScaledImageForScaleFactor(2.0, image);
+    expect(scaledImage).notTo.equal(image);
+}
+
 #pragma mark - Helper
 
 - (NSString *)testGIFPath {

+ 1 - 1
Tests/Tests/SDWebCacheCategoriesTests.m

@@ -644,7 +644,7 @@
     SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:@"Test"];
     cache.config.shouldUseWeakMemoryCache = YES;
     SDWebImageManager *imageManager = [[SDWebImageManager alloc] initWithCache:cache loader:[SDWebImageDownloader sharedDownloader]];
-    [imageView sd_setImageWithURL:kTestJPEGURL placeholderImage:nil options:0 context:@{SDWebImageContextCustomManager:imageManager} progress:nil completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
+    [imageView sd_setImageWithURL:(NSURL *)kTestJPEGURL placeholderImage:nil options:0 context:@{SDWebImageContextCustomManager:imageManager} progress:nil completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
         expect(image).notTo.beNil();
         [expectation fulfill];
     }];