● 我们先来看.h文件
typedef NS_ENUM(NSInteger, SDImageFormat) {
SDImageFormatUndefined = -1,
SDImageFormatJPEG = 0,
SDImageFormatPNG,
SDImageFormatGIF,
SDImageFormatTIFF,
SDImageFormatWebP,
SDImageFormatHEIC
};
一个枚举,列举出图片的类型
/**
* Return image format 返回图片类型
*
* @param data the input image data
*
* @return the image format as `SDImageFormat` (enum)
*/
+ (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data;
/**
Convert SDImageFormat to UTType 转成系统type
@param format Format as SDImageFormat
@return The UTType as CFStringRef
*/
+ (nonnull CFStringRef)sd_UTTypeFromSDImageFormat:(SDImageFormat)format;
在看.m文件之前,我们先说一些知识
● SDWebImage通过文件头来获取图片的类型,已png为例,png的前8个字节依次为:0x89 0x50 0x4E 0x47 0x0D 0x0A 0x1A 0x0A,再比如jpg图片,jpg文件比较复杂,JPG文件数据,分很多很多的数据段, 并且每个数据段都会以 0xFF开头 ,所以我们就能明白以下代码的含义,
+ (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data {
if (!data) {
return SDImageFormatUndefined;
}
// File signatures table: http://www.garykessler.net/library/file_sigs.html
uint8_t c;
[data getBytes:&c length:1];
switch (c) {
case 0xFF:
return SDImageFormatJPEG; //jpeg是 FF开头
case 0x89:
return SDImageFormatPNG; //png 是 89开头
case 0x47:
return SDImageFormatGIF; // gif 是 47开头
case 0x49:
case 0x4D:
return SDImageFormatTIFF; // tiff 是 49 或者 4D开头
case 0x52: {
if (data.length >= 12) {
//RIFF....WEBP
NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {
return SDImageFormatWebP;
}
}
break;
}
case 0x00: {
if (data.length >= 12) {
//....ftypheic ....ftypheix ....ftyphevc ....ftyphevx
NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(4, 8)] encoding:NSASCIIStringEncoding];
if ([testString isEqualToString:@"ftypheic"]
|| [testString isEqualToString:@"ftypheix"]
|| [testString isEqualToString:@"ftyphevc"]
|| [testString isEqualToString:@"ftyphevx"]) {
return SDImageFormatHEIC;
}
}
break;
}
}
return SDImageFormatUndefined;
}
● 比较麻烦的是webp格式,webp是以524946462A73010057454250开头的,占用12个字节,当第一个字节为52时,如果长度<12 我们就认定为不是图片。因此返回nil。我们通过数据截取后获得testString,如果testString头部包含RIFF且尾部也包含WEBP,那么就认定该图片格式为webp。
● 关于.heic格式的图片
1.什么是.heic格式图片?
之前叫“live”图片,打开下图红框中的按钮即可打开该模式,拍照后会截取拍照前后大概两秒的一个片段,与“Gif”图不同的是,该格式还包含了声音(目前只有),只有在 iOS11系统下且CPU为A10及其以上(最低也得是iPhone 7),其他情况下拍出来的都是普通“live”图,即在需要转换格式的时候会自动转换为“.jpg/.jpeg”格式
2.如何判断.heic格式图片?
第四到第八个字节,分别等于:ftypheic,ftypheix,ftyphevc,ftyphevx,就可以认定他是.heic格式的图片
● 关于kSDUTTypeWebP和kSDUTTypeHEIC
// Currently Image/IO does not support WebP
#define kSDUTTypeWebP ((__bridge CFStringRef)@"public.webp")
// AVFileTypeHEIC is defined in AVFoundation via iOS 11, we use this without import AVFoundation
#define kSDUTTypeHEIC ((__bridge CFStringRef)@"public.heic")
因为webpiOS系统没有对应的type,所以手动创建了一个,heic格式只在iOS11以后才支持,所以也手动创建。
+ (nonnull CFStringRef)sd_UTTypeFromSDImageFormat:(SDImageFormat)format {
CFStringRef UTType;
switch (format) {
case SDImageFormatJPEG:
UTType = kUTTypeJPEG;
break;
case SDImageFormatPNG:
UTType = kUTTypePNG;
break;
case SDImageFormatGIF:
UTType = kUTTypeGIF;
break;
case SDImageFormatTIFF:
UTType = kUTTypeTIFF;
break;
case SDImageFormatWebP:
UTType = kSDUTTypeWebP;
break;
case SDImageFormatHEIC:
UTType = kSDUTTypeHEIC;
break;
default:
// default is kUTTypePNG
UTType = kUTTypePNG;
break;
}
return UTType;
}
这个方法没什么可说的,就是讲枚举转化成系统type