11
11
#import < QuartzCore/QuartzCore.h>
12
12
13
13
#import < React/RCTUtils.h>
14
- #import < React/RCTAnimatedImage.h>
15
14
16
15
@implementation RCTGIFImageDecoder
17
16
@@ -31,13 +30,96 @@ - (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData
31
30
resizeMode : (RCTResizeMode)resizeMode
32
31
completionHandler : (RCTImageLoaderCompletionBlock)completionHandler
33
32
{
34
- RCTAnimatedImage *image = [[RCTAnimatedImage alloc ] initWithData: imageData scale: scale];
35
-
36
- if (!image) {
33
+ CGImageSourceRef imageSource = CGImageSourceCreateWithData ((CFDataRef )imageData, NULL );
34
+ if (!imageSource) {
37
35
completionHandler (nil , nil );
38
36
return ^{};
39
37
}
40
-
38
+ NSDictionary <NSString *, id > *properties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties (imageSource, NULL );
39
+ CGFloat loopCount = 0 ;
40
+ if ([[properties[(id )kCGImagePropertyGIFDictionary ] allKeys ] containsObject: (id )kCGImagePropertyGIFLoopCount ]) {
41
+ loopCount = [properties[(id )kCGImagePropertyGIFDictionary ][(id )kCGImagePropertyGIFLoopCount ] unsignedIntegerValue ];
42
+ if (loopCount == 0 ) {
43
+ // A loop count of 0 means infinite
44
+ loopCount = HUGE_VALF;
45
+ } else {
46
+ // A loop count of 1 means it should repeat twice, 2 means, thrice, etc.
47
+ loopCount += 1 ;
48
+ }
49
+ }
50
+
51
+ UIImage *image = nil ;
52
+ size_t imageCount = CGImageSourceGetCount (imageSource);
53
+ if (imageCount > 1 ) {
54
+
55
+ NSTimeInterval duration = 0 ;
56
+ NSMutableArray <NSNumber *> *delays = [NSMutableArray arrayWithCapacity: imageCount];
57
+ NSMutableArray <id /* CGIMageRef */ > *images = [NSMutableArray arrayWithCapacity: imageCount];
58
+ for (size_t i = 0 ; i < imageCount; i++) {
59
+
60
+ CGImageRef imageRef = CGImageSourceCreateImageAtIndex (imageSource, i, NULL );
61
+ if (!imageRef) {
62
+ continue ;
63
+ }
64
+ if (!image) {
65
+ image = [UIImage imageWithCGImage: imageRef scale: scale orientation: UIImageOrientationUp];
66
+ }
67
+
68
+ NSDictionary <NSString *, id > *frameProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex (imageSource, i, NULL );
69
+ NSDictionary <NSString *, id > *frameGIFProperties = frameProperties[(id )kCGImagePropertyGIFDictionary ];
70
+
71
+ const NSTimeInterval kDelayTimeIntervalDefault = 0.1 ;
72
+ NSNumber *delayTime = frameGIFProperties[(id )kCGImagePropertyGIFUnclampedDelayTime ] ?: frameGIFProperties[(id )kCGImagePropertyGIFDelayTime ];
73
+ if (delayTime == nil ) {
74
+ if (delays.count == 0 ) {
75
+ delayTime = @(kDelayTimeIntervalDefault );
76
+ } else {
77
+ delayTime = delays.lastObject ;
78
+ }
79
+ }
80
+
81
+ const NSTimeInterval kDelayTimeIntervalMinimum = 0.02 ;
82
+ if (delayTime.floatValue < (float )kDelayTimeIntervalMinimum - FLT_EPSILON) {
83
+ delayTime = @(kDelayTimeIntervalDefault );
84
+ }
85
+
86
+ duration += delayTime.doubleValue ;
87
+ [delays addObject: delayTime];
88
+ [images addObject: (__bridge_transfer id )imageRef];
89
+ }
90
+ CFRelease (imageSource);
91
+
92
+ NSMutableArray <NSNumber *> *keyTimes = [NSMutableArray arrayWithCapacity: delays.count];
93
+ NSTimeInterval runningDuration = 0 ;
94
+ for (NSNumber *delayNumber in delays) {
95
+ [keyTimes addObject: @(runningDuration / duration)];
96
+ runningDuration += delayNumber.doubleValue ;
97
+ }
98
+
99
+ [keyTimes addObject: @1.0 ];
100
+
101
+ // Create animation
102
+ CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath: @" contents" ];
103
+ animation.calculationMode = kCAAnimationDiscrete ;
104
+ animation.repeatCount = loopCount;
105
+ animation.keyTimes = keyTimes;
106
+ animation.values = images;
107
+ animation.duration = duration;
108
+ animation.removedOnCompletion = NO ;
109
+ animation.fillMode = kCAFillModeForwards ;
110
+ image.reactKeyframeAnimation = animation;
111
+
112
+ } else {
113
+
114
+ // Don't bother creating an animation
115
+ CGImageRef imageRef = CGImageSourceCreateImageAtIndex (imageSource, 0 , NULL );
116
+ if (imageRef) {
117
+ image = [UIImage imageWithCGImage: imageRef scale: scale orientation: UIImageOrientationUp];
118
+ CFRelease (imageRef);
119
+ }
120
+ CFRelease (imageSource);
121
+ }
122
+
41
123
completionHandler (nil , image);
42
124
return ^{};
43
125
}
0 commit comments