SDWebImage 源码分析 --加载gif图片
n年关了,马上放假,终于把手头上的事情告一段落,连续发布了3个app,我也是醉了。
终于有了点时间。想研究下SDWebImage是怎么加载gif图片的。
一直很好奇。
现在开始。
1,首先我们看下SDWebImage是怎么加载gif的。
faceButton.image = [UIImage sd_animatedGIFNamed:[NSString stringWithFormat:@"CHATA_%d",i - 46]];
sd_animatedGIFNamed是SDWebImage提供的加载gif图片的一种方法。我们点进去这个方法去看以下。
2,sd_animatedGIFNamed 这个方法的实现如下。生成一个UIImage对象。
+ (UIImage *)sd_animatedGIFNamed:(NSString *)name { //取到屏幕分辨率 CGFloat scale = [UIScreen mainScreen].scale; //是否是高清屏 if (scale > 1.0f) { //如果是高清屏 取@2x图片 //读取图片 NSString *retinaPath = [[NSBundle mainBundle] pathForResource:[name stringByAppendingString:@"@2x"] ofType:@"gif"]; //图片转换为data NSData *data = [NSData dataWithContentsOfFile:retinaPath]; //如果图片存在 if (data) { //调用sd_animatedGIFWithData 生成image实例 // return [UIImage sd_animatedGIFWithData:data]; } //如果@2x图片不存在 读取普通图片 NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"]; //图片转换为data data = [NSData dataWithContentsOfFile:path]; //如果图片存在 if (data) { //调用sd_animatedGIFWithData 生成image实例 return [UIImage sd_animatedGIFWithData:data]; } //如果图片不存在 return [UIImage imageNamed:name]; } else { //如果不是高清屏 读取普通图片 NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"]; //图片转换为data NSData *data = [NSData dataWithContentsOfFile:path]; //如果图片存在 if (data) { //调用sd_animatedGIFWithData 生成image实例 return [UIImage sd_animatedGIFWithData:data]; } //如果图片不存在 return [UIImage imageNamed:name]; } }
注释已经很详细了,这个类方法里面主要是确定当前设备的分辨率,以便加载不同分辨率的图片。
然后通过
dataWithContentsOfFile
方法把图片转换为NSData,判断NSData是否存在。
如果存在调用sd_animatedGIFWithData 后续处理。
3,sd_animatedGIFWithData 方法。
+ (UIImage *)sd_animatedGIFWithData:(NSData *)data { if (!data) { return nil; } CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL); 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++) { CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL); duration += [self frameDurationAtIndex:i source:source]; [images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]]; CGImageRelease(image); } if (!duration) { duration = (1.0f / 10.0f) * count; } animatedImage = [UIImage animatedImageWithImages:images duration:duration]; } CFRelease(source); return animatedImage; }
先看这行代码
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
CGImageSourceRef定义如下,
typedef struct CGImageSource *CGImageSourceRef;
可以看到它是一个CGImageSource 指针。
CGImageSource又是什么呢?
CGImageSource是对图像数据读取任务的抽象,通过它可以获得图像对象、缩略图、图像的属性(包括Exif信息)。
那么这行代码可以这样理解:通过nadata取到图像的以系列信息。
goon,
size_t count = CGImageSourceGetCount(source);
这行代码是读取CGImageSourceRef有几个图片对象。
next,下面就不难理解了,
CGImageSourceCreateImageAtIndex 从
source里面读取各个图片放入数组里面。
读取显示图片的 时间。
duration += [self frameDurationAtIndex:i source:source];
4,计算图片显示时间
+ (float)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]; } } if (frameDuration < 0.011f) { frameDuration = 0.100f; } CFRelease(cfFrameProperties); return frameDuration; }
详细分析 待续!!!
5,
animatedImage = [UIImage animatedImageWithImages:images duration:duration];
播放数组里里面的图片。
over!!!!
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。