Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apng support #227

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 31 additions & 7 deletions FLAnimatedImage/FLAnimatedImage.m
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,35 @@ - (instancetype)initWithAnimatedGIFData:(NSData *)data optimalFrameCacheSize:(NS
}

// Early return if not GIF!
id dictionaryKey = nil;
id loopCountKey = nil;
id unclampedDelayTimeKey = nil;
id delayTimeKey = nil;

CFStringRef imageSourceContainerType = CGImageSourceGetType(_imageSource);
BOOL isGIFData = UTTypeConformsTo(imageSourceContainerType, kUTTypeGIF);
if (!isGIFData) {
FLLog(FLLogLevelError, @"Supplied data is of type %@ and doesn't seem to be GIF data %@", imageSourceContainerType, data);
return nil;
if (isGIFData) {
dictionaryKey = (id)kCGImagePropertyGIFDictionary;
loopCountKey = (id)kCGImagePropertyGIFLoopCount;
unclampedDelayTimeKey = (id)kCGImagePropertyGIFUnclampedDelayTime;
delayTimeKey = (id)kCGImagePropertyGIFDelayTime;
} else {
BOOL isPNGData = UTTypeConformsTo(imageSourceContainerType, kUTTypePNG);
if (isPNGData) {
size_t imageCount = CGImageSourceGetCount(_imageSource);
if (imageCount > 1) { // apng
dictionaryKey = (id)kCGImagePropertyPNGDictionary;
loopCountKey = (id)kCGImagePropertyAPNGLoopCount;
unclampedDelayTimeKey = (id)kCGImagePropertyAPNGUnclampedDelayTime;
delayTimeKey = (id)kCGImagePropertyAPNGDelayTime;
} else {
FLLog(FLLogLevelError, @"Supplied data is of type %@ and doesn't seem to be APNG data %@", imageSourceContainerType, data);
return nil;
}
} else {
FLLog(FLLogLevelError, @"Supplied data is of type %@ and doesn't seem to be GIF data %@", imageSourceContainerType, data);
return nil;
}
}

// Get `LoopCount`
Expand All @@ -228,7 +252,7 @@ - (instancetype)initWithAnimatedGIFData:(NSData *)data optimalFrameCacheSize:(NS
// };
// }
NSDictionary *imageProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(_imageSource, NULL);
_loopCount = [[[imageProperties objectForKey:(id)kCGImagePropertyGIFDictionary] objectForKey:(id)kCGImagePropertyGIFLoopCount] unsignedIntegerValue];
_loopCount = [[[imageProperties objectForKey:dictionaryKey] objectForKey:loopCountKey] unsignedIntegerValue];

// Iterate through frame images
size_t imageCount = CGImageSourceGetCount(_imageSource);
Expand Down Expand Up @@ -267,12 +291,12 @@ - (instancetype)initWithAnimatedGIFData:(NSData *)data optimalFrameCacheSize:(NS
// }

NSDictionary *frameProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(_imageSource, i, NULL);
NSDictionary *framePropertiesGIF = [frameProperties objectForKey:(id)kCGImagePropertyGIFDictionary];
NSDictionary *framePropertiesGIF = [frameProperties objectForKey:dictionaryKey];

// Try to use the unclamped delay time; fall back to the normal delay time.
NSNumber *delayTime = [framePropertiesGIF objectForKey:(id)kCGImagePropertyGIFUnclampedDelayTime];
NSNumber *delayTime = [framePropertiesGIF objectForKey:unclampedDelayTimeKey];
if (!delayTime) {
delayTime = [framePropertiesGIF objectForKey:(id)kCGImagePropertyGIFDelayTime];
delayTime = [framePropertiesGIF objectForKey:delayTimeKey];
}
// If we don't get a delay time from the properties, fall back to `kDelayTimeIntervalDefault` or carry over the preceding frame's value.
const NSTimeInterval kDelayTimeIntervalDefault = 0.1;
Expand Down