首先解释一下涉及到的一些基本概念和方法:
- 什么是文件头?
- 如何根据文件头判断图片格式?
1.什么是文件头
我们知道文件有很多类型,那如何判断文件究竟是属于哪种类型,这时候就需要利用文件头携带的信息去进行判断。
文件头:位于文件开头的一段承担一定任务的数据,一般都在开头的部分。
例如,用十六进制编辑器查看一张gif格式的图片的文件头如下(部分数据):
<47494638 39619001 2c01f672 007b4f27 866952a6 8839a58e 55b59d7d cbb439c3 af49e8dc 1ee9de2d faec1feb e026ece1 ...
965a6ec9 65975e7e 09669862 8e496699 66d21408 003b>
47494638即为gif图片格式的文件头标识。
2.根据文件头判断图片格式
| 图片格式 | 文件头 |
|---|---|
| JPEG (jpg) | FFD8FFE1 |
| PNG (png) | 89504E47 |
| GIF (gif) | 47494638 |
| TIFF(tiff) | 49492A00 或 4D4D002A |
| WebP | 524946462A73010057454250 |
重点来解释一下webp这种特殊格式,它是由是由12个字节组成的文件头,把这些字节通过ASCII编码,我们会得到如下内容:

3.源码解读
先贴下源码:
+ (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;
}
现在来看源码的话,就简单易懂了。
1.获取二进制数据开头一个字节长度的数据(只需比对文件头的第一个字节数据即可)
[data getBytes:&c length:1];
2.根据文件头判断图片格式,
即,如果第一个字节为FF,就可以判断该文件是一张格式为jpeg的图片,依此论推。
3.针对webp这种特殊格式,先判断data的字节长度是否 > 12,如果不大于12,说明不是webp格式;
如果 > 12,进而将十六进制转为文本字符串,如果该字符串开头是RIFF,并且结尾是WEBP,就判定该文件类型为webp格式的图片。