SDWebImage 内部实现了一个图片解码/编码的图片编码器,用于图片的编解码、压缩。其中涉及到编解码管理(SDWebImageCodersManager)、编解码协议(SDWebImageCoder)、PNG/JPEG/TIFF编解码,解压缩,显示大图(SDWebImageImageIOCoder)、GIF编解码(SDWebImageGIFCoder)、WebP编解码(SDWebImageWebPCoder)以及辅助类(SDWebImageCoderHelper

本篇只做 SDWebImageCoder 的分析。 SDWebImageCoder 是编解码协议,包含两个协议:SDWebImageCoderSDWebImageProgressiveCoder,两个协议定义了图片编解码类的接口。

公共变量与函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 //一个bool类型的key,标记在解压缩期间是否缩小大图片。使用:@{SDWebImageCoderScaleDownLargeImagesKey: @(BOOL值)}
FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageCoderScaleDownLargeImagesKey;

//.m文件
NSString * const SDWebImageCoderScaleDownLargeImagesKey = @"scaleDownLargeImages";

/**
返回使用CGColorSpaceCreateDeviceRGB创建的共享设备相关RGB颜色空间。

@return 与设备相关RGB颜色空间
*/
CG_EXTERN CGColorSpaceRef _Nonnull SDCGColorSpaceGetDeviceRGB(void);

/**
检查 CGImageRef 是否包含 alpha 通道

@param imageRef The CGImageRef
@return 如果CGImageRef包含alpha通道,则返回YES,否则返回NO
*/
CG_EXTERN BOOL SDCGImageRefContainsAlpha(_Nullable CGImageRef imageRef);

两个函数的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//定义了一个单利方法,获取设备的RGB色彩空间
CGColorSpaceRef SDCGColorSpaceGetDeviceRGB(void) {
//通过单例模式获取设备的RGB色彩空间并返回
static CGColorSpaceRef colorSpace;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
colorSpace = CGColorSpaceCreateDeviceRGB();
});
return colorSpace;
}

//检查图片是否有透明度
BOOL SDCGImageRefContainsAlpha(CGImageRef imageRef) {
//如果没有图片就返回没有透明度
if (!imageRef) {
return NO;
}
//获取图片的透明度信息
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef);
//如果满足下面的任何一个选项,就代表没有透明度;否则就有透明度
BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone ||
alphaInfo == kCGImageAlphaNoneSkipFirst ||
alphaInfo == kCGImageAlphaNoneSkipLast);
return hasAlpha;
}

两个协议

SDWebImageCoder 协议

该协议提供自定义图像解码/编码的图像编码器协议。
需要注意的是:不要从主队列调用这些方法。
该协议使用了 @required 关键词,标志着里面的协议方法必须实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@required //标志着里面的协议方法必须实现

#pragma mark - 解码
/**
如果此编码器可以解码某些data,返回YES,否则,它应该传递给另一个编码器

@param data 需要解码的图片数据
@return 如果此编码器可以解码图片,返回YES,否则返回NO
*/
- (BOOL)canDecodeFromData:(nullable NSData *)data;

/**
将图片数据解码为图片。

@param data 需要解码的图片数据
@return 解码后得到的图片
*/
- (nullable UIImage *)decodedImageWithData:(nullable NSData *)data;

/**
使用原始图片和图片数据解压缩图片。

@param image 需要压缩的原图片
@param data 指向原始图像数据的指针。 指针本身是非空的,但图像数据可以为空。 如果需要,此数据将设置为缓存。 如果您不需要同时修改数据,请忽略此参数。
@param optionsDict 一个包含任何解压缩选项的字典。 通过{SDWebImageCoderScaleDownLargeImagesKey:@(YES)}缩小大图像
@return 解压缩后的图片
*/
- (nullable UIImage *)decompressedImageWithImage:(nullable UIImage *)image
data:(NSData * _Nullable * _Nonnull)data
options:(nullable NSDictionary<NSString*, NSObject*>*)optionsDict;

#pragma mark -编码

/**
如果此编码器可以编码某些图片,返回YES,否则,它应该传递给另一个编码器

@param format 图片格式
@return 如果此编码器可以编码图片,返回YES,否则返回NO
*/
- (BOOL)canEncodeToFormat:(SDImageFormat)format;

/**
将图片编码为图片数据(imagedata)

@param image 需要编码的图片
@param format 要编码的图片格式, 也有可能是 `SDImageFormatUndefined` 格式(未识别格式)
@return The encoded image data
*/
- (nullable NSData *)encodedDataWithImage:(nullable UIImage *)image format:(SDImageFormat)format;
SDWebImageProgressiveCoder 协议

该协议提供自定义逐行图像解码的图像编码器协议。
注意:不要从主队列调用这些方法。
该协议使用了 @required 关键词,标志着里面的协议方法必须实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
`@required` //标志着里面的协议方法必须实现
/**
如果此编码器可以增量解码某些数据,返回YES,否则,它应该传递给另一个解码器。

@param data 图片数据,以便可以查看它
@return 如果此编码器可以增量解码该数据,返回YES,否则返回NO
*/
- (BOOL)canIncrementallyDecodeFromData:(nullable NSData *)data;

/**
将图片数据增量解码为图片

@param data 到目前为止已下载的图片数据
@param finished 下载是否已经结束
@warning 因为增量解码需要保持解码的上下文,我们将为每个下载操作分配一个具有相同类的新实例,以避免冲突
@return The decoded image from data
*/
- (nullable UIImage *)incrementallyDecodedImageWithData:(nullable NSData *)data finished:(BOOL)finished;