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!!!!








原文地址:https://www.cnblogs.com/yunis/p/4290666.html