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








  • 相关阅读:
    数字重排
    环游世界
    Hibernate笔记(一)增删改查CRUD
    Sliding Window Algorithm 滑动窗口算法
    纯HTML/CSS/JS实现淘宝、京东两种轮播图
    COA计算机组织与结构笔记
    数据结构与算法笔记:最小生成树Kruskal、Prim算法与JAVA实现
    数据结构与算法笔记:图的基础与JAVA实现
    数据结构与算法:并查集
    JDBC学习笔记
  • 原文地址:https://www.cnblogs.com/yunis/p/4290666.html
Copyright © 2020-2023  润新知