Skip to content

Commit 95ef882

Browse files
staufmankelset
authored andcommitted
Fixes animated gifs incorrectly looping/not stopping on last frame (#21999)
Summary: Currently, if you load an animated gif using the standard `Image` component, it will not correctly respect the loop count property found in the Netscape App Extension block of the file. The issues are as follows: 1) If the App Extension isn't present, the animated gif loops indefinitely when it should not loop at all. 2) If the App Extension is present, the animated gif loops one less time than it should. The other issue is that once the looping completes, the image doesn't pause at the last frame but instead, loops back to the beginning of the animation e.g. frame 1. The fix does a few things: 1) If there is _no_ App Extension present, the image doesn't loop at all 2) If there _is_ an App Extension present, it loops the correct amount of times. For instance, if the loop count is 1, it means the gif should loop _once_ after it finishes playing, for a total of _two_ total loops. 3) Once the number of loops completes (assuming loop count isn't set to 0 which means infinite), the animation pauses on the last frame. Pull Request resolved: #21999 Differential Revision: D13287005 Pulled By: hramos fbshipit-source-id: f7210ad40e0e76c9ec454953b8a067569d3feaaa
1 parent 1b169fc commit 95ef882

File tree

1 file changed

+14
-3
lines changed

1 file changed

+14
-3
lines changed

Libraries/Image/RCTGIFImageDecoder.m

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,18 @@ - (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData
3232
{
3333
CGImageSourceRef imageSource = CGImageSourceCreateWithData((CFDataRef)imageData, NULL);
3434
NSDictionary<NSString *, id> *properties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(imageSource, NULL);
35-
NSUInteger loopCount = [properties[(id)kCGImagePropertyGIFDictionary][(id)kCGImagePropertyGIFLoopCount] unsignedIntegerValue];
36-
35+
NSUInteger loopCount = 0;
36+
if ([[properties[(id)kCGImagePropertyGIFDictionary] allKeys] containsObject:(id)kCGImagePropertyGIFLoopCount]) {
37+
loopCount = [properties[(id)kCGImagePropertyGIFDictionary][(id)kCGImagePropertyGIFLoopCount] unsignedIntegerValue];
38+
if (loopCount == 0) {
39+
// A loop count of 0 means infinite
40+
loopCount = HUGE_VALF;
41+
} else {
42+
// A loop count of 1 means it should repeat twice, 2 means, thrice, etc.
43+
loopCount += 1;
44+
}
45+
}
46+
3747
UIImage *image = nil;
3848
size_t imageCount = CGImageSourceGetCount(imageSource);
3949
if (imageCount > 1) {
@@ -84,11 +94,12 @@ - (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData
8494
// Create animation
8595
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"];
8696
animation.calculationMode = kCAAnimationDiscrete;
87-
animation.repeatCount = loopCount == 0 ? HUGE_VALF : loopCount;
97+
animation.repeatCount = loopCount;
8898
animation.keyTimes = keyTimes;
8999
animation.values = images;
90100
animation.duration = duration;
91101
animation.removedOnCompletion = NO;
102+
animation.fillMode = kCAFillModeForwards;
92103
image.reactKeyframeAnimation = animation;
93104

94105
} else {

0 commit comments

Comments
 (0)