二、SDWebImage源碼解析NSData + ImageContentType

● 我們先來看.h文件

typedef NS_ENUM(NSInteger, SDImageFormat) {
    SDImageFormatUndefined = -1,
    SDImageFormatJPEG = 0,
    SDImageFormatPNG,
    SDImageFormatGIF,
    SDImageFormatTIFF,
    SDImageFormatWebP,
    SDImageFormatHEIC
};

一個(gè)枚舉,列舉出圖片的類型

/**
 *  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 轉(zhuǎn)成系統(tǒng)type

 @param format Format as SDImageFormat
 @return The UTType as CFStringRef
 */
+ (nonnull CFStringRef)sd_UTTypeFromSDImageFormat:(SDImageFormat)format;

在看.m文件之前,我們先說一些知識(shí)
● SDWebImage通過文件頭來獲取圖片的類型,已png為例,png的前8個(gè)字節(jié)依次為:0x89 0x50 0x4E 0x47 0x0D 0x0A 0x1A 0x0A,再比如jpg圖片,jpg文件比較復(fù)雜,JPG文件數(shù)據(jù),分很多很多的數(shù)據(jù)段, 并且每個(gè)數(shù)據(jù)段都會(huì)以 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個(gè)字節(jié),當(dāng)?shù)谝粋€(gè)字節(jié)為52時(shí),如果長度<12 我們就認(rèn)定為不是圖片。因此返回nil。我們通過數(shù)據(jù)截取后獲得testString,如果testString頭部包含RIFF且尾部也包含WEBP,那么就認(rèn)定該圖片格式為webp。

● 關(guān)于.heic格式的圖片
1.什么是.heic格式圖片?
之前叫“l(fā)ive”圖片,打開下圖紅框中的按鈕即可打開該模式,拍照后會(huì)截取拍照前后大概兩秒的一個(gè)片段,與“Gif”圖不同的是,該格式還包含了聲音(目前只有),只有在 iOS11系統(tǒng)下且CPU為A10及其以上(最低也得是iPhone 7),其他情況下拍出來的都是普通“l(fā)ive”圖,即在需要轉(zhuǎn)換格式的時(shí)候會(huì)自動(dòng)轉(zhuǎn)換為“.jpg/.jpeg”格式
2.如何判斷.heic格式圖片?
第四到第八個(gè)字節(jié),分別等于:ftypheic,ftypheix,ftyphevc,ftyphevx,就可以認(rèn)定他是.heic格式的圖片

● 關(guān)于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")

因?yàn)閣ebpiOS系統(tǒng)沒有對應(yīng)的type,所以手動(dòng)創(chuàng)建了一個(gè),heic格式只在iOS11以后才支持,所以也手動(dòng)創(chuàng)建。

+ (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;
}

這個(gè)方法沒什么可說的,就是講枚舉轉(zhuǎn)化成系統(tǒng)type

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容