#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIImageView (WZGif)
/// 加载本地gif
/// @param imageName gif名字
- (void)showGifImageLocalWithImageName:(NSString *)imageName;
/// 加载网络gif
/// @param url gifURL
- (void)showGifImageWithURL:(NSURL *)url;
@end
NS_ASSUME_NONNULL_END
#import "UIImageView+WZGif.h"
#import <ImageIO/ImageIO.h>
#if __has_feature(objc_arc)
#define toCF (__bridge CFTypeRef)
#define ARCCompatibleAutorelease(object) object
#else
#define toCF (CFTypeRef)
#define ARCCompatibleAutorelease(object) [object autorelease]
#endif
@implementation UIImageView (WZGif)
- (void)animatedGIFImageSource:(CGImageSourceRef) source
andDuration:(NSTimeInterval) duration {
if (!source) return;
size_t count = CGImageSourceGetCount(source);
NSMutableArray *images = [NSMutableArray arrayWithCapacity:count];
for (size_t i = 0; i < count; ++i) {
CGImageRef cgImage = CGImageSourceCreateImageAtIndex(source, i, NULL);
if (!cgImage)
return;
[images addObject:[UIImage imageWithCGImage:cgImage]];
CGImageRelease(cgImage);
}
[self setAnimationImages:images];
[self setAnimationDuration:duration];
[self startAnimating];
}
- (NSTimeInterval)durationForGifData:(NSData *)data {
char graphicControlExtensionStartBytes[] = {0x21,0xF9,0x04};
double duration=0;
NSRange dataSearchLeftRange = NSMakeRange(0, data.length);
while(YES){
NSRange frameDescriptorRange = [data rangeOfData:[NSData dataWithBytes:graphicControlExtensionStartBytes
length:3]
options:NSDataSearchBackwards
range:dataSearchLeftRange];
if(frameDescriptorRange.location!=NSNotFound){
NSData *durationData = [data subdataWithRange:NSMakeRange(frameDescriptorRange.location+4, 2)];
unsigned char buffer[2];
[durationData getBytes:buffer length:1];
double delay = (buffer[0] | buffer[1] << 8);
duration += delay;
dataSearchLeftRange = NSMakeRange(0, frameDescriptorRange.location);
}else{
break;
}
}
return duration/100;
}
- (void)showGifImageWithData:(NSData *)data {
NSTimeInterval duration = [self durationForGifData:data];
CGImageSourceRef source = CGImageSourceCreateWithData(toCF data, NULL);
[self animatedGIFImageSource:source andDuration:duration];
CFRelease(source);
}
- (void)loadImageWith:(NSString *)filePath{
if (self && self != nil) {
dispatch_async(dispatch_get_main_queue(), ^{
NSData *data = [NSData dataWithContentsOfFile:filePath];
NSString *imageType = [self imageTypeWithData:data];
if ([imageType isEqualToString:@"gif"]) {
[self showGifImageWithData:data];
}else{
if (self.isAnimating) {
[self stopAnimating];
}
[self setImage:[UIImage imageWithData:data]];
}
});
}
}
/// 加载网络gif
/// @param url gifURL
- (void)showGifImageWithURL:(NSURL *)url {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *cache = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [cache stringByAppendingPathComponent:url.lastPathComponent];
BOOL flag = [[NSFileManager defaultManager] fileExistsAtPath:filePath];
if (flag) {
[self loadImageWith:filePath];
}else{
NSURLRequest *reque = [NSURLRequest requestWithURL:url];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]];
NSURLSessionDownloadTask *task = [session downloadTaskWithRequest:reque completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSURL *toURL = [NSURL fileURLWithPath:filePath];
[fileManager moveItemAtURL:location toURL:toURL error:nil];
[self loadImageWith:filePath];
}];
[task resume];
}
}
/// 加载本地gif
/// @param imageName gif名字
- (void)showGifImageLocalWithImageName:(NSString *)imageName{
NSString *filePath = [[NSBundle mainBundle] pathForResource:imageName ofType:@"gif"];
[self loadImageWith:filePath];
}
/// 获取数据类型
/// @param data data
- (NSString *)imageTypeWithData:(NSData *)data {
uint8_t type;
[data getBytes:&type length:1];
switch (type) {
case 0xFF:
return @"jpeg";
case 0x89:
return @"png";
case 0x47:
return @"gif";
case 0x49:
case 0x4D:
return @"tiff";
case 0x52:
if([data length] < 12) {
return nil;
}
NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
if([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {
return@"webp";
}
return nil;
}
return nil;
}