zoukankan      html  css  js  c++  java
  • 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!!!!








  • 相关阅读:
    PAT (Advanced Level) 1060. Are They Equal (25)
    PAT (Advanced Level) 1059. Prime Factors (25)
    PAT (Advanced Level) 1058. A+B in Hogwarts (20)
    PAT (Advanced Level) 1057. Stack (30)
    PAT (Advanced Level) 1056. Mice and Rice (25)
    PAT (Advanced Level) 1055. The World's Richest (25)
    PAT (Advanced Level) 1054. The Dominant Color (20)
    PAT (Advanced Level) 1053. Path of Equal Weight (30)
    PAT (Advanced Level) 1052. Linked List Sorting (25)
    PAT (Advanced Level) 1051. Pop Sequence (25)
  • 原文地址:https://www.cnblogs.com/yunis/p/4290666.html
Copyright © 2011-2022 走看看