92 lines
3.1 KiB
Mathematica
92 lines
3.1 KiB
Mathematica
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||
|
|
||
|
#import "RCTGIFImage.h"
|
||
|
|
||
|
#import "RCTLog.h"
|
||
|
|
||
|
static CAKeyframeAnimation *RCTGIFImageWithImageSource(CGImageSourceRef imageSource)
|
||
|
{
|
||
|
if (!UTTypeConformsTo(CGImageSourceGetType(imageSource), kUTTypeGIF)) {
|
||
|
CFRelease(imageSource);
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
NSDictionary *properties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(imageSource, NULL);
|
||
|
NSUInteger loopCount = [properties[(id)kCGImagePropertyGIFDictionary][(id)kCGImagePropertyGIFLoopCount] unsignedIntegerValue];
|
||
|
|
||
|
size_t imageCount = CGImageSourceGetCount(imageSource);
|
||
|
NSTimeInterval duration = 0;
|
||
|
NSMutableArray *delays = [NSMutableArray arrayWithCapacity:imageCount];
|
||
|
NSMutableArray *images = [NSMutableArray arrayWithCapacity:imageCount];
|
||
|
for (size_t i = 0; i < imageCount; i++) {
|
||
|
CGImageRef image = CGImageSourceCreateImageAtIndex(imageSource, i, NULL);
|
||
|
NSDictionary *frameProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(imageSource, i, NULL);
|
||
|
NSDictionary *frameGIFProperties = frameProperties[(id)kCGImagePropertyGIFDictionary];
|
||
|
|
||
|
const NSTimeInterval kDelayTimeIntervalDefault = 0.1;
|
||
|
NSNumber *delayTime = frameGIFProperties[(id)kCGImagePropertyGIFUnclampedDelayTime] ?: frameGIFProperties[(id)kCGImagePropertyGIFDelayTime];
|
||
|
if (delayTime == nil) {
|
||
|
if (i == 0) {
|
||
|
delayTime = @(kDelayTimeIntervalDefault);
|
||
|
} else {
|
||
|
delayTime = delays[i - 1];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const NSTimeInterval kDelayTimeIntervalMinimum = 0.02;
|
||
|
if (delayTime.floatValue < (float)kDelayTimeIntervalMinimum - FLT_EPSILON) {
|
||
|
delayTime = @(kDelayTimeIntervalDefault);
|
||
|
}
|
||
|
|
||
|
duration += delayTime.doubleValue;
|
||
|
delays[i] = delayTime;
|
||
|
images[i] = (__bridge_transfer id)image;
|
||
|
}
|
||
|
|
||
|
NSMutableArray *keyTimes = [NSMutableArray arrayWithCapacity:delays.count];
|
||
|
NSTimeInterval runningDuration = 0;
|
||
|
for (NSNumber *delayNumber in delays) {
|
||
|
[keyTimes addObject:@(runningDuration / duration)];
|
||
|
runningDuration += delayNumber.doubleValue;
|
||
|
}
|
||
|
|
||
|
[keyTimes addObject:@1.0];
|
||
|
|
||
|
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"];
|
||
|
animation.calculationMode = kCAAnimationDiscrete;
|
||
|
animation.repeatCount = loopCount == 0 ? HUGE_VALF : loopCount;
|
||
|
animation.keyTimes = keyTimes;
|
||
|
animation.values = images;
|
||
|
animation.duration = duration;
|
||
|
return animation;
|
||
|
}
|
||
|
|
||
|
CAKeyframeAnimation *RCTGIFImageWithData(NSData *data)
|
||
|
{
|
||
|
if (data.length == 0) {
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
CGImageSourceRef imageSource = CGImageSourceCreateWithData((CFDataRef)data, NULL);
|
||
|
CAKeyframeAnimation *animation = RCTGIFImageWithImageSource(imageSource);
|
||
|
CFRelease(imageSource);
|
||
|
return animation;
|
||
|
}
|
||
|
|
||
|
CAKeyframeAnimation *RCTGIFImageWithFileURL(NSURL *URL)
|
||
|
{
|
||
|
if (!URL) {
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
if (![URL isFileURL]) {
|
||
|
RCTLogError(@"Loading remote image URLs synchronously is a really bad idea.");
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
CGImageSourceRef imageSource = CGImageSourceCreateWithURL((CFURLRef)URL, NULL);
|
||
|
CAKeyframeAnimation *animation = RCTGIFImageWithImageSource(imageSource);
|
||
|
CFRelease(imageSource);
|
||
|
return animation;
|
||
|
}
|