// // UIImage+JHUD.m // JHudViewDemo // // Created by 晋先森 on 16/7/18. // Copyright © 2016年 晋先森. All rights reserved. // #import "UIImage+JHUD.h" #import @implementation UIImage (JHUD) // See YYWebImage for details. + (UIImage *)jHUDImageWithSmallGIFData:(NSData *)data scale:(CGFloat)scale { CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFTypeRef)(data), NULL); if (!source) return nil; size_t count = CGImageSourceGetCount(source); if (count <= 1) { CFRelease(source); return [self.class imageWithData:data scale:scale]; } NSUInteger frames[count]; double oneFrameTime = 1 / 50.0; // 50 fps NSTimeInterval totalTime = 0; NSUInteger totalFrame = 0; NSUInteger gcdFrame = 0; for (size_t i = 0; i < count; i++) { NSTimeInterval delay = jHUDCGImageSourceGetGIFFrameDelayAtIndex(source, i); totalTime += delay; NSInteger frame = lrint(delay / oneFrameTime); if (frame < 1) frame = 1; frames[i] = frame; totalFrame += frames[i]; if (i == 0) gcdFrame = frames[i]; else { NSUInteger frame = frames[i], tmp; if (frame < gcdFrame) { tmp = frame; frame = gcdFrame; gcdFrame = tmp; } while (true) { tmp = frame % gcdFrame; if (tmp == 0) break; frame = gcdFrame; gcdFrame = tmp; } } } NSMutableArray *array = [NSMutableArray new]; for (size_t i = 0; i < count; i++) { CGImageRef imageRef = CGImageSourceCreateImageAtIndex(source, i, NULL); if (!imageRef) { CFRelease(source); return nil; } size_t width = CGImageGetWidth(imageRef); size_t height = CGImageGetHeight(imageRef); if (width == 0 || height == 0) { CFRelease(source); CFRelease(imageRef); return nil; } CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef) & kCGBitmapAlphaInfoMask; BOOL hasAlpha = NO; if (alphaInfo == kCGImageAlphaPremultipliedLast || alphaInfo == kCGImageAlphaPremultipliedFirst || alphaInfo == kCGImageAlphaLast || alphaInfo == kCGImageAlphaFirst) { hasAlpha = YES; } // BGRA8888 (premultiplied) or BGRX8888 // same as UIGraphicsBeginImageContext() and -[UIView drawRect:] CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host; bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, space, bitmapInfo); CGColorSpaceRelease(space); if (!context) { CFRelease(source); CFRelease(imageRef); return nil; } CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef); // decode CGImageRef decoded = CGBitmapContextCreateImage(context); CFRelease(context); if (!decoded) { CFRelease(source); CFRelease(imageRef); return nil; } UIImage *image = [UIImage imageWithCGImage:decoded scale:scale orientation:UIImageOrientationUp]; CGImageRelease(imageRef); CGImageRelease(decoded); if (!image) { CFRelease(source); return nil; } for (size_t j = 0, max = frames[i] / gcdFrame; j < max; j++) { [array addObject:image]; } } CFRelease(source); UIImage *image = [self.class animatedImageWithImages:array duration:totalTime]; return image; } static NSTimeInterval jHUDCGImageSourceGetGIFFrameDelayAtIndex(CGImageSourceRef source, size_t index) { NSTimeInterval delay = 0; CFDictionaryRef dic = CGImageSourceCopyPropertiesAtIndex(source, index, NULL); if (dic) { CFDictionaryRef dicGIF = CFDictionaryGetValue(dic, kCGImagePropertyGIFDictionary); if (dicGIF) { NSNumber *num = CFDictionaryGetValue(dicGIF, kCGImagePropertyGIFUnclampedDelayTime); if (num.doubleValue <= __FLT_EPSILON__) { num = CFDictionaryGetValue(dicGIF, kCGImagePropertyGIFDelayTime); } delay = num.doubleValue; } CFRelease(dic); } // http://nullsleep.tumblr.com/post/16524517190/animated-gif-minimum-frame-delay-browser-compatibility if (delay < 0.02) delay = 0.1; return delay; } @end