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

				
时间: 2024-10-10 06:09:41

SDWebImage 源码分析 --加载gif图片的相关文章

深入理解 spring 容器,源码分析加载过程

Spring框架提供了构建Web应用程序的全功能MVC模块,叫Spring MVC,通过Spring Core+Spring MVC即可搭建一套稳定的Java Web项目.本文通过Spring MVC源码分析介绍它的核心实现原理. Tomcat服务器启动入口文件是web.xml,通过在其中配置相关的Listener和Servlet即可加载Spring MVC所需数据.基于Spring MVC最简单的配置如下. <!-- 加载Spring配置文件 --> <context-param>

看看Spring的源码——Bean加载过程

最近几天跟同事聊起Spring的一些问题,对一些地方有些疑问,趁这两天有点空,看看Spring的源码,了解下具体的实现细节.本文基于Spring 4.0.5版本. 首先Web项目使用Spring是通过在web.xml里面配置org.springframework.web.context.ContextLoaderListener初始化IOC容器的. <listener> <listener-class>org.springframework.web.context.ContextL

hibernate源码-配置文件加载过程分析

Hibernate建议,在一个应用系统当中Configuration与SessionFactory为单例,Session为多例. 当我们执行如下代码,hibernate开始加载默认的配置文件 new Configuration().configure() hibernate会在classath的根路径下,查找名为"hibernate.cfg.xml" 的配置文件,并解析它,过程如图1所示 图1:配置文件加载过程时序图 下面一起分析一下配置文件加载过程 Step 1.Configurat

SDWebImage源码分析

SDWebImageManager -- 单例 1 - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock

Android图片加载库Picasso源码分析

图片加载在Android开发中是非常重要,好的图片加载库也比比皆是.ImageLoader.Picasso.Glide.Fresco均是优秀的图片加载库. 以上提到的几种图片加载库各有特色.用法与比较,网上已经很多了. 出于学习的角度,个人认为从Picasso入手较好.代码量小,同时API优美,很适合我们学习. 今天笔者就Picasso的源码进行分析,抛出一些图片加载的技术细节供园友参考. PS:建议园友先大致看一下源码. 我们对图片加载的要求 1.加载速度要快 2.资源消耗要低 3.加载图片不

Android图片异步加载框架Universal Image Loader的源码分析

项目地址:https://github.com/nostra13/android-universal-image-loader 1. 功能介绍 1.1 Android Universal Image Loader Android Universal Image Loader 是一个强大的.可高度定制的图片缓存,本文简称为UIL. 简单的说 UIL 就做了一件事--获取图片并显示在相应的控件上. 1.2 基本使用 1.2.1 初始化 添加完依赖后在Application或Activity中初始化I

jQuery实现DOM加载方法源码分析

传统的判断dom加载的方法 使用 dom0级 onload事件来进行触发所有浏览器都支持在最初是很流行的写法 我们都熟悉这种写法: window.onload=function(){ ... }  但是onload事件触发过于缓慢,尤其是在存在很多外部图片或者视频文件的时候,为了更好的了解这一点有必要知道一个html文档是如何进行加载的,这里引用一个园友的表述: 1.用户输入网址(假设是个html页面,并且是第一次访问),浏览器向服务器发出请求,服务器返回html文件: 2.浏览器开始载入htm

插件式换肤框架搭建 - 资源加载源码分析

1. 概述 大部分控件我们都会使用,但是我们未必知道其资源加载的原理,目前换肤的框架比较多我们可以随随便便拿过来用,但早在几年前这些资料是比较少的,如果想做一个换肤的框架那就只能自己一点一点啃源码. 如果说我们现在不去用第三方的开源框架,要做一个换肤的功能,摆在我们面前的其实只有一个问题需要解决,那就是如何读取另外一个皮肤apk中的资源. 所有分享大纲:2017Android进阶之路与你同行 视频讲解地址:http://pan.baidu.com/s/1bC3lAQ 2. 资源加载源码分析 2.

Android应用setContentView与LayoutInflater加载解析机制源码分析

[工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处,尊重分享成果] 1 背景 其实之所以要说这个话题有几个原因: 理解xml等控件是咋被显示的原理,通常大家写代码都是直接在onCreate里setContentView就完事,没怎么关注其实现原理. 前面分析<Android触摸屏事件派发机制详解与源码分析三(Activity篇)>时提到了一些关于布局嵌套的问题,当时没有深入解释. 所以接下来主要分析的就是View或者ViewGroup对象是如何添加至应用程