SDWebImage源码解读 之 NSData+ImageContentType

第一篇

前言

从今天开始,我将开启一段源码解读的旅途了。在这里先暂时不透露具体解读的源码到底是哪些?因为也可能随着解读的进行会更改计划。但能够肯定的是,这一系列之中肯定会有Swift版本的代码。

说说我的目的。想成为一名好的程序员,肯定绕不开模仿这条路。之所以做出这么一个决定,也是想提高自己写框架的能力,逻辑思维能力,扩展知识面。同时也能够给那些想了解这些框架的同学一些基本的解释。何乐而不为呢?

解读方法

对于框架的源码解读,我个人的习惯是先看头文件,先从头文件最简单的开始解读,也就是说首先看不依赖外部文件的类。

这就说明了一个问题,我们在写代码的时候,import头文件也是需要经过慎重考虑的。应该导入什么头文件应该让别的开发者很明白该类具体依赖那些外部文件。

NSData (ImageContentType)

很明显这是一个NSData的分类,我们都知道分类一般是用来扩展一些方法的。我们看看它扩展了什么方法?

/**
 *  Compute the content type for an image data
 *
 *  @param data the input data
 *
 *  @return the content type as string (i.e. image/jpeg, image/gif)
 */
+ (NSString *)sd_contentTypeForImageData:(NSData *)data;

好,看这个方法,就应该明白了,目的是根据二进制的数据获取图片的contentType。因此,我们在这里就要插入一段contentType的介绍了。

文件头

文件头是位于文件开头的一段承担一定任务的数据,一般都在开头的部分。

别看这个文件头和C语言中的头文件读起来很像,但这两个东西其实根本没有一点关系:头文件是一种包含功能函数,数据接口声明的载体文件;而文件头则是直接位于文件中的一段数据,是文件的一部分

说的简单一点就是,当文件都使用二进制流作为传输时,需要制定一套规范,用来区分该文件到底是什么类型的。 文件头有很多个,我们在这里就介绍一些主流的且跟图片相关的文件头。

  1. JPEG (jpg),文件头:FFD8FFE1
  2. PNG (png),文件头:89504E47
  3. GIF (gif),文件头:47494638
  4. TIFF tif;tiff 0x49492A00
  5. TIFF tif;tiff 0x4D4D002A
  6. RAR Archive (rar),文件头:52617221
  7. WebP : 524946462A73010057454250

可以看出来我们通过每个文件头的第一个字节就能判断出是什么类型。但是值得注意的是52开头的。这个要做特别的判断。

WebP这种格式很特别。是由12个字节组成的文件头,我们如果把这些字节通过ASCII编码后会得到下边这样一张表格:

+ (NSString *)sd_contentTypeForImageData:(NSData *)data {
    uint8_t c;
    [data getBytes:&c length:1];
    switch (c) {
        case 0xFF:
            return @"image/jpeg";
        case 0x89:
            return @"image/png";
        case 0x47:
            return @"image/gif";
        case 0x49:
        case 0x4D:
            return @"image/tiff";
        case 0x52:
            // R as RIFF for WEBP
            if ([data length] < 12) {
                return nil;
            }

            NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
            if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {
                return @"image/webp";
            }

            return nil;
    }
    return nil;
}

现在再看上边方法的实现,我们就明白了。其中jpeg/png/gif/tiff 是最好判断的。当第一个字节为52时,如果长度<12 我们就认定为不是图片。因此返回nil。我们通过数据截取后获得testString,如果testString头部包含RIFF且尾部也包含WEBP,那么就认定该图片格式为webp。

演示

为了更好的演示webp,我们用代码打印出结果来看看。

首先我们获得一个webp图片:google@2x.webp

 NSString *path = [[NSBundle mainBundle] pathForResource:@"google@2x" ofType:@"webp"];
 NSData *data = [NSData dataWithContentsOfFile:path];
 NSString *contentType = [NSData sd_contentTypeForImageData:data];
 NSLog(@"-----%@------%@", contentType, data);

我们看下打印结果:

-----image/webp------<52494646 72370000 57454250 56503858 0a000000 10000000 190200bd 0000414c 50484711 00000187 40906d33 83cd9ff7 778888a4 b3e53068 db4650c2 9f747a77 ff1822fa 9f927ff8 9224460e c3301c46 86216224 932431e6 1f5edfb6 6dd76d6c db56c195 20884bfb ffaf959d c214d01a 39e6f521 a2ffe95b b6edbaad 6ddb2a20 c03b40e4 ffffdade fbb0500b 2ddb2146 8c8788fe a7feff26 7ecae76a 9f2e77a3 fd9ce513 3ffc8fdd a7d286ec b65aa2d3 b3f6c735 44ef3ad6 ac879cce 21fafd58 929e6eac 53ccce25 e9c33bb8 d779b52f 438ccf59 9fdcc1bd ee7871ac f284be4f fad40eee 75c77b63 93b5d1ca 27de1de5 6c4376cf a28fece0 5e77bc36 3659b94a 64311e75 c8562dfa bc0eee75 c75b4393 efb32636 c3d165a7 167d5807 f7bae3a5 aecaf72b a1e28f21 1bb5e893 3ab8d71d 2f5da67c 9ba7472f 36d93892 3ea6a58e 30a6e39d 53e56b71

其中52494646 72370000 57454250正好占用了12字节。那么也正好符合了我们上边解释的webp文件头。

NSData (ImageContentTypeDeprecated)

这个分类有一个东西值得我们学习。

+ (NSString *)contentTypeForImageData:(NSData *)data __deprecated_msg("Use `sd_contentTypeForImageData:`");

这个__deprecated_msg可以告诉开发者该方法不建议使用。这就有使用场景了。当我们在写框架或者类的时候,如果功能相同,但是想使用新的方法名的时候,使用__deprecated_msg给予其他开发者一个提示。这远远比我们直接删除旧的更专业。

总结

这是SDWebImage源码解读的第一篇,我们解读的目的是发现代码中我们不知道的细节和知识。尽可能的想象出使用场景。在解读完之后,需要做一个所有知识点的总结。我们应该尽量去揣摩作者驾驭代码的思想。也许当我们抓住这些知识点并使用时,我们写出的代码跟别人就有了不同的感觉。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容