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:
commit
30275b4415
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue