147 lines
4.5 KiB
Objective-C
147 lines
4.5 KiB
Objective-C
//
|
|
// UIImage+JHUD.m
|
|
// JHudViewDemo
|
|
//
|
|
// Created by 晋先森 on 16/7/18.
|
|
// Copyright © 2016年 晋先森. All rights reserved.
|
|
//
|
|
|
|
#import "UIImage+JHUD.h"
|
|
#import <ImageIO/ImageIO.h>
|
|
|
|
@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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|