最近项目中有个需求,需要从后台获取一张GIF,保存到本地.每次请求该接口时,如果有新的GIF,那么需要把新的GIF保存到本地,删除原来的GIF,并且把新的GIF显示到手机上面.
UIImageView按道理说是不能直接显示GIF图片的,但是我们知道GIF图其实是很多张图片,设置好每张图片之间的间隔后,拼成了一张图片.所以我们可以通过拆解下载好的GIF为一张张的图片,把这些图片放到一个数组里面,通过UIImage的类方法+ (nullable UIImage *)animatedImageWithImages:(NSArray<UIImage *> *)images duration:(NSTimeInterval)duration ;来生成一张GIF图片.把生成好的赋值给UIImageView的image属性即可.
在SDWebImage 4.0之前的版本(4.0之后,对于GIF图片,提供了一个FLAnimatedImageView来代替UIImageView)我们可以在UIImage+GIF.m文件中可以找到相应的实现.
+ (UIImage *)sd_animatedGIFWithData:(NSData *)data {
if (!data) {
return nil;
}
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
//gif都是一张张图片拼出来的,这里的count就是拼出这个gif图一共用了多少张图片.
size_t count = CGImageSourceGetCount(source);
UIImage *animatedImage;
//如果只是一张图片,那么就简单的进行解码
if (count <= 1) {
animatedImage = [[UIImage alloc] initWithData:data];
}
else {
//存放图片的数组.
NSMutableArray *images = [NSMutableArray array];
//设置图片的时间长度
NSTimeInterval duration = 0.0f;
for (size_t i = 0; i < count; i++) {
//根据source来获取到每帧图片,并且生成CGImageRef.
CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
if (!image) {
continue;
}
//获取gif图片每帧之间的时间间隔并且叠加.
duration += [self sd_frameDurationAtIndex:i source:source];
//将生成的每帧图片放到图片数组中.
[images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]];
//因为使用了create,所以需要使用release释放掉生成的CGImageRef
CGImageRelease(image);
}
if (!duration) {
duration = (1.0f / 10.0f) * count;
}
//生成一张GIF图片.
animatedImage = [UIImage animatedImageWithImages:images duration:duration];
}
CFRelease(source);
return animatedImage;
}
//获取每帧图片的duration
+ (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source {
float frameDuration = 0.1f;
CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
if (delayTimeUnclampedProp) {
frameDuration = [delayTimeUnclampedProp floatValue];
}
else {
NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
if (delayTimeProp) {
frameDuration = [delayTimeProp floatValue];
}
}
// Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
// We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
// a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
// for more information.
//很多烦人的广告指定间隔为0来制作一种非常快的闪图.
//我们遵循Firefox的行为,对于间隔小于10ms的帧
if (frameDuration < 0.011f) {
frameDuration = 0.100f;
}
CFRelease(cfFrameProperties);
return frameDuration;
}
主要就是这两段代码.
我的做法是:直接用SDWebImageManager中的下载方法,下载图片pic,再将pic的url保存起来,等到下次请求回来图片的URL时,进行比较,如果一样,那么就直接拿url.absoluteString作为key去磁盘里面去就可以了.
还是比较简单的,如果你想存到自己的文件里面,那也可以,只需要把路径设置好就行了,然后去对应的路径里面,把文件以data的形式加载出来,然后通过上面贴的代码,把data作为参数来获取到GIF图片即可.