● 我們先來看.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