Skip to content

Commit 005709b

Browse files
Revert "Animated image improvements (facebook#24822)"
This reverts commit 3b67bfa.
1 parent 73299ff commit 005709b

6 files changed

+89
-535
lines changed

Libraries/Image/RCTAnimatedImage.h

-21
This file was deleted.

Libraries/Image/RCTAnimatedImage.m

-166
This file was deleted.

Libraries/Image/RCTGIFImageDecoder.m

+87-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
#import <QuartzCore/QuartzCore.h>
1212

1313
#import <React/RCTUtils.h>
14-
#import <React/RCTAnimatedImage.h>
1514

1615
@implementation RCTGIFImageDecoder
1716

@@ -31,13 +30,96 @@ - (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData
3130
resizeMode:(RCTResizeMode)resizeMode
3231
completionHandler:(RCTImageLoaderCompletionBlock)completionHandler
3332
{
34-
RCTAnimatedImage *image = [[RCTAnimatedImage alloc] initWithData:imageData scale:scale];
35-
36-
if (!image) {
33+
CGImageSourceRef imageSource = CGImageSourceCreateWithData((CFDataRef)imageData, NULL);
34+
if (!imageSource) {
3735
completionHandler(nil, nil);
3836
return ^{};
3937
}
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+
41123
completionHandler(nil, image);
42124
return ^{};
43125
}

Libraries/Image/RCTImageView.m

+2-3
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
#import <SDWebImage/UIImageView+WebCache.h>
1717
#import <SDWebImagePhotosPlugin/SDWebImagePhotosPlugin.h>
1818

19-
#import <React/RCTUIImageViewAnimated.h>
2019
#import <React/RCTImageBlurUtils.h>
2120
#import <React/RCTImageLoader.h>
2221
#import <React/RCTImageUtils.h>
@@ -82,7 +81,7 @@ @implementation RCTImageView
8281
// Whether the latest change of props requires the image to be reloaded
8382
BOOL _needsReload;
8483

85-
RCTUIImageViewAnimated *_imageView;
84+
UIImageView *_imageView;
8685
}
8786

8887
- (instancetype)initWithBridge:(RCTBridge *)bridge
@@ -98,7 +97,7 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
9897
selector:@selector(clearImageIfDetached)
9998
name:UIApplicationDidEnterBackgroundNotification
10099
object:nil];
101-
_imageView = [[RCTUIImageViewAnimated alloc] init];
100+
_imageView = [[UIImageView alloc] init];
102101
_imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
103102
[self addSubview:_imageView];
104103
}

Libraries/Image/RCTUIImageViewAnimated.h

-12
This file was deleted.

0 commit comments

Comments
 (0)