diff --git a/SDWebImage/Core/SDAnimatedImageView.m b/SDWebImage/Core/SDAnimatedImageView.m index 78f1cb8b..f0b811c4 100644 --- a/SDWebImage/Core/SDAnimatedImageView.m +++ b/SDWebImage/Core/SDAnimatedImageView.m @@ -166,12 +166,13 @@ }; self.player.animationLoopHandler = ^(NSUInteger loopCount) { @strongify(self); - self.currentLoopCount = loopCount; // Progressive image reach the current last frame index. Keep the state and pause animating. Wait for later restart if (self.isProgressive) { - NSUInteger lastFrameIndex = self.player.totalFrameCount; + NSUInteger lastFrameIndex = self.player.totalFrameCount - 1; [self.player seekToFrameAtIndex:lastFrameIndex loopCount:0]; [self.player pausePlaying]; + } else { + self.currentLoopCount = loopCount; } }; diff --git a/Tests/Tests/SDAnimatedImageTest.m b/Tests/Tests/SDAnimatedImageTest.m index b3fb53f2..0640e3dc 100644 --- a/Tests/Tests/SDAnimatedImageTest.m +++ b/Tests/Tests/SDAnimatedImageTest.m @@ -8,6 +8,7 @@ */ #import "SDTestCase.h" +#import "SDInternalMacros.h" #import static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop count @@ -397,6 +398,76 @@ static const NSUInteger kTestGIFFrameCount = 5; // local TestImage.gif loop coun [self waitForExpectationsWithCommonTimeout]; } +- (void)test27AnimatedImageProgressiveAnimation { + XCTestExpectation *expectation = [self expectationWithDescription:@"test SDAnimatedImageView progressive animation rendering"]; + + // Simulate progressive download + NSData *fullData = [self testAPNGPData]; + NSUInteger length = fullData.length; + + SDAnimatedImageView *imageView = [SDAnimatedImageView new]; +#if SD_UIKIT + [self.window addSubview:imageView]; +#else + [self.window.contentView addSubview:imageView]; +#endif + + __block NSUInteger previousFrameIndex = 0; + @weakify(imageView); + // Observe to check rendering behavior using frame index + [self.KVOController observe:imageView keyPath:NSStringFromSelector(@selector(currentFrameIndex)) options:NSKeyValueObservingOptionNew block:^(id _Nullable observer, id _Nonnull object, NSDictionary * _Nonnull change) { + @strongify(imageView); + NSUInteger currentFrameIndex = [change[NSKeyValueChangeNewKey] unsignedIntegerValue]; + printf("Animation Frame Index: %lu\n", (unsigned long)currentFrameIndex); + + // The last time should not be progressive + if (currentFrameIndex == 0 && !imageView.isProgressive) { + [self.KVOController unobserve:imageView]; + [expectation fulfill]; + } else { + // Each progressive rendering should render new frame index, no backward and should stop at last frame index + expect(currentFrameIndex - previousFrameIndex).beGreaterThanOrEqualTo(0); + previousFrameIndex = currentFrameIndex; + } + }]; + + SDImageAPNGCoder *coder = [[SDImageAPNGCoder alloc] initIncrementalWithOptions:nil]; + // Setup Data + NSData *setupData = [fullData subdataWithRange:NSMakeRange(0, length / 3.0)]; + [coder updateIncrementalData:setupData finished:NO]; + imageView.shouldIncrementalLoad = YES; + __block SDAnimatedImage *progressiveImage = [[SDAnimatedImage alloc] initWithAnimatedCoder:coder scale:1]; + progressiveImage.sd_isIncremental = YES; + imageView.image = progressiveImage; + expect(imageView.isProgressive).beTruthy(); + + __block NSUInteger partialFrameCount; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + // Partial Data + NSData *partialData = [fullData subdataWithRange:NSMakeRange(0, length * 2.0 / 3.0)]; + [coder updateIncrementalData:partialData finished:NO]; + partialFrameCount = [coder animatedImageFrameCount]; + expect(partialFrameCount).beGreaterThan(1); + progressiveImage = [[SDAnimatedImage alloc] initWithAnimatedCoder:coder scale:1]; + progressiveImage.sd_isIncremental = YES; + imageView.image = progressiveImage; + expect(imageView.isProgressive).beTruthy(); + }); + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + // Full Data + [coder updateIncrementalData:fullData finished:YES]; + progressiveImage = [[SDAnimatedImage alloc] initWithAnimatedCoder:coder scale:1]; + progressiveImage.sd_isIncremental = NO; + imageView.image = progressiveImage; + NSUInteger fullFrameCount = [coder animatedImageFrameCount]; + expect(fullFrameCount).beGreaterThan(partialFrameCount); + expect(imageView.isProgressive).beFalsy(); + }); + + [self waitForExpectationsWithCommonTimeout]; +} + #pragma mark - Helper - (UIWindow *)window { if (!_window) {