Merge pull request #2067 from dreampiggy/feature_gif_encoding_macOS

Add the animated GIF encoding support for SDWebImageGIFCoder on macOS(use NSImage's API)
This commit is contained in:
Bogdan Poplauschi 2017-10-19 20:51:06 +03:00 committed by GitHub
commit 30275b4415
2 changed files with 30 additions and 23 deletions

View File

@ -45,8 +45,7 @@
if (count <= 1) { if (count <= 1) {
animatedImage = [[UIImage alloc] initWithData:data]; animatedImage = [[UIImage alloc] initWithData:data];
} } else {
else {
NSMutableArray *images = [NSMutableArray array]; NSMutableArray *images = [NSMutableArray array];
NSTimeInterval duration = 0.0f; NSTimeInterval duration = 0.0f;
@ -103,9 +102,7 @@
NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime]; NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
if (delayTimeUnclampedProp) { if (delayTimeUnclampedProp) {
frameDuration = [delayTimeUnclampedProp floatValue]; frameDuration = [delayTimeUnclampedProp floatValue];
} } else {
else {
NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime]; NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
if (delayTimeProp) { if (delayTimeProp) {
frameDuration = [delayTimeProp floatValue]; frameDuration = [delayTimeProp floatValue];
@ -147,11 +144,22 @@
} }
NSMutableData *imageData = [NSMutableData data]; NSMutableData *imageData = [NSMutableData data];
NSUInteger frameCount = 0; // assume static images by default
CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:format]; CFStringRef imageUTType = [NSData sd_UTTypeFromSDImageFormat:format];
NSUInteger frameCount = 1; #if SD_MAC
if (image.images) { NSBitmapImageRep *bitmapRep;
frameCount = image.images.count; for (NSImageRep *imageRep in image.representations) {
if ([imageRep isKindOfClass:[NSBitmapImageRep class]]) {
bitmapRep = (NSBitmapImageRep *)imageRep;
break;
}
} }
if (bitmapRep) {
frameCount = [[bitmapRep valueForProperty:NSImageFrameCount] unsignedIntegerValue];
}
#else
frameCount = image.images.count;
#endif
// Create an image destination. GIF does not support EXIF image orientation // Create an image destination. GIF does not support EXIF image orientation
CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, frameCount, NULL); CGImageDestinationRef imageDestination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageData, imageUTType, frameCount, NULL);
@ -160,29 +168,30 @@
return nil; return nil;
} }
#ifdef SD_MAC if (frameCount == 0) {
CGImageDestinationAddImage(imageDestination, image.CGImage, nil);
#else
if (!image.images) {
// for static single GIF images // for static single GIF images
CGImageDestinationAddImage(imageDestination, image.CGImage, nil); CGImageDestinationAddImage(imageDestination, image.CGImage, nil);
} else { } else {
// for animated GIF images // for animated GIF images
NSUInteger loopCount = image.sd_imageLoopCount; NSUInteger loopCount = image.sd_imageLoopCount;
NSTimeInterval totalDuration = image.duration;
NSTimeInterval frameDuration = totalDuration / frameCount;
NSDictionary *gifProperties = @{(__bridge_transfer NSString *)kCGImagePropertyGIFDictionary: @{(__bridge_transfer NSString *)kCGImagePropertyGIFLoopCount : @(loopCount)}}; NSDictionary *gifProperties = @{(__bridge_transfer NSString *)kCGImagePropertyGIFDictionary: @{(__bridge_transfer NSString *)kCGImagePropertyGIFLoopCount : @(loopCount)}};
CGImageDestinationSetProperties(imageDestination, (__bridge CFDictionaryRef)gifProperties); CGImageDestinationSetProperties(imageDestination, (__bridge CFDictionaryRef)gifProperties);
for (size_t i = 0; i < frameCount; i++) { for (size_t i = 0; i < frameCount; i++) {
@autoreleasepool { @autoreleasepool {
NSDictionary *frameProperties = @{(__bridge_transfer NSString *)kCGImagePropertyGIFDictionary : @{(__bridge_transfer NSString *)kCGImagePropertyGIFUnclampedDelayTime : @(frameDuration)}}; #if SD_MAC
// NSBitmapImageRep need to manually change frame. "Good taste" API
[bitmapRep setProperty:NSImageCurrentFrame withValue:@(i)];
float frameDuration = [[bitmapRep valueForProperty:NSImageCurrentFrameDuration] floatValue];
CGImageRef frameImageRef = bitmapRep.CGImage;
#else
float frameDuration = image.duration / frameCount;
CGImageRef frameImageRef = image.images[i].CGImage; CGImageRef frameImageRef = image.images[i].CGImage;
#endif
NSDictionary *frameProperties = @{(__bridge_transfer NSString *)kCGImagePropertyGIFDictionary : @{(__bridge_transfer NSString *)kCGImagePropertyGIFUnclampedDelayTime : @(frameDuration)}};
CGImageDestinationAddImage(imageDestination, frameImageRef, (__bridge CFDictionaryRef)frameProperties); CGImageDestinationAddImage(imageDestination, frameImageRef, (__bridge CFDictionaryRef)frameProperties);
} }
} }
} }
#endif
// Finalize the destination. // Finalize the destination.
if (CGImageDestinationFinalize(imageDestination) == NO) { if (CGImageDestinationFinalize(imageDestination) == NO) {
// Handle failure. // Handle failure.

View File

@ -89,11 +89,11 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
return nil; return nil;
} }
#if SD_MAC
return [[UIImage alloc] initWithData:data];
#else
UIImage *image = [[UIImage alloc] initWithData:data]; UIImage *image = [[UIImage alloc] initWithData:data];
#if SD_MAC
return image;
#else
if (!image) { if (!image) {
return nil; return nil;
} }
@ -105,14 +105,12 @@ static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to over
image = [UIImage animatedImageWithImages:@[image] duration:image.duration]; image = [UIImage animatedImageWithImages:@[image] duration:image.duration];
return image; return image;
} }
#if SD_UIKIT || SD_WATCH
UIImageOrientation orientation = [[self class] sd_imageOrientationFromImageData:data]; UIImageOrientation orientation = [[self class] sd_imageOrientationFromImageData:data];
if (orientation != UIImageOrientationUp) { if (orientation != UIImageOrientationUp) {
image = [UIImage imageWithCGImage:image.CGImage image = [UIImage imageWithCGImage:image.CGImage
scale:image.scale scale:image.scale
orientation:orientation]; orientation:orientation];
} }
#endif
return image; return image;
#endif #endif