SDWebImage 源碼分析 --加載gif圖片

n年關了,立刻放假,終於把手頭上的事情告一段落,連續發佈了3個app,我也是醉了。數組

終於有了點時間。想研究下SDWebImage是怎麼加載gif圖片的。app

一直很好奇。指針

如今開始。orm

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;blog

能夠看到它是一個CGImageSource 指針。圖片

CGImageSource又是什麼呢?string

CGImageSource是對圖像數據讀取任務的抽象,經過它能夠得到圖像對象、縮略圖、圖像的屬性(包括Exif信息)。it

 

那麼這行代碼能夠這樣理解:經過nadata取到圖像的以系列信息。io

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

相關文章
相關標籤/搜索