SDWebImage里自己寫(xiě)了一個(gè)編解碼管理器,用于實(shí)現(xiàn)編碼编曼,解碼豆巨,壓縮,縮小圖片像素功能灵巧。涉及到的文件有SDWebImageCodersManager搀矫,SDWebImageCoder抹沪,SDWebImageImageIOCoder等等
一刻肄、SDWebImageCodersManager
我們先來(lái)看SDWebImageCodersManager,SDWebImageCodersManager是一個(gè)編碼解碼管理器融欧,處理多個(gè)圖片編碼解碼任務(wù)敏弃,編碼器數(shù)組是一個(gè)優(yōu)先級(jí)隊(duì)列,這意味著后面添加的編碼器將具有最高優(yōu)先級(jí)噪馏。
SDWebImageCodersManager.h
@interface SDWebImageCodersManager : NSObject<SDWebImageCoder>
/**
Shared reusable instance
單例
*/
+ (nonnull instancetype)sharedInstance;
/**
All coders in coders manager. The coders array is a priority queue, which means the later added coder will have the highest priority
編碼器管理器中的所有編碼器麦到。編碼器數(shù)組是一個(gè)優(yōu)先級(jí)隊(duì)列,這意味著后面添加的編碼器將具有最高優(yōu)先級(jí)欠肾。
*/
@property (nonatomic, strong, readwrite, nullable) NSArray<SDWebImageCoder>* coders;
/**
Add a new coder to the end of coders array. Which has the highest priority.
增加一個(gè)新的coder 瓶颠,新加入的最先編解碼
@param coder coder
*/
- (void)addCoder:(nonnull id<SDWebImageCoder>)coder;
/**
Remove a coder in the coders array.
刪除一個(gè)coder
@param coder coder
*/
- (void)removeCoder:(nonnull id<SDWebImageCoder>)coder;
初始化方法
+ (nonnull instancetype)sharedInstance {
static dispatch_once_t once;
static id instance;
dispatch_once(&once, ^{
instance = [self new];
});
return instance;
}
- (instancetype)init {
if (self = [super init]) {
// initialize with default coders
_mutableCoders = [@[[SDWebImageImageIOCoder sharedCoder]] mutableCopy]; //初始化SDWebImageImageIOCoder支持PNG,JPEG刺桃,TIFF粹淋,包括支持漸進(jìn)解碼的解碼器
#ifdef SD_WEBP
[_mutableCoders addObject:[SDWebImageWebPCoder sharedCoder]]; //添加WebP
#endif
_mutableCodersAccessQueue = dispatch_queue_create("com.hackemist.SDWebImageCodersManager", DISPATCH_QUEUE_CONCURRENT); //創(chuàng)建隊(duì)列
}
return self;
}
添加編碼器和刪除編碼器
//添加編碼器
- (void)addCoder:(nonnull id<SDWebImageCoder>)coder { //增加編碼器,遵守SDWebImageCoder協(xié)議
if ([coder conformsToProtocol:@protocol(SDWebImageCoder)]) {//該編碼器是否實(shí)現(xiàn)了SDWebImageCoder協(xié)議的方法
dispatch_barrier_sync(self.mutableCodersAccessQueue, ^{ //同步添加編碼器瑟慈,將自己的任務(wù)插入到隊(duì)列的時(shí)候桃移,需要等待自己的任務(wù)結(jié)束之后才會(huì)繼續(xù)插入被寫(xiě)在它后面的任務(wù),然后執(zhí)行它們
[self.mutableCoders addObject:coder];
});
}
}
//刪除編碼器
- (void)removeCoder:(nonnull id<SDWebImageCoder>)coder {//遵守SDWebImageCoder協(xié)議
dispatch_barrier_sync(self.mutableCodersAccessQueue, ^{//同步刪除編碼器
[self.mutableCoders removeObject:coder];
});
}
coders的getter和setter方法
//coders getter 方法
- (NSArray<SDWebImageCoder> *)coders {
__block NSArray<SDWebImageCoder> *sortedCoders = nil;
dispatch_sync(self.mutableCodersAccessQueue, ^{
sortedCoders = (NSArray<SDWebImageCoder> *)[[[self.mutableCoders copy] reverseObjectEnumerator] allObjects];
});
return sortedCoders;
}
//coders setter 方法
- (void)setCoders:(NSArray<SDWebImageCoder> *)coders {
dispatch_barrier_sync(self.mutableCodersAccessQueue, ^{
self.mutableCoders = [coders mutableCopy];
});
}
reverseObjectEnumerator 將數(shù)組倒序
e.g.
//1.原始數(shù)組
NSMutableArray array = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",nil];
//2.倒序的數(shù)組
NSArray reversedArray = [[array reverseObjectEnumerator] allObjects];
SDWebImageCoder delegate 方法
1.該圖片是否可以編碼葛碧。 遍歷self.coders中遵守SDWebImageCoder 的 coder借杰, 然后通過(guò)canEncodeToFormat 這個(gè)方法來(lái)判斷是否可以編碼
- (BOOL)canEncodeToFormat:(SDImageFormat)format {
for (id<SDWebImageCoder> coder in self.coders) {
if ([coder canEncodeToFormat:format]) {
return YES;
}
}
return NO;
}
2.解碼。 遍歷self.coders中遵守SDWebImageCoder 的 coder进泼, 然后通過(guò)canDecodeFromData 這個(gè)方法來(lái)判斷是否可以解碼蔗衡,如果可以纤虽,將圖像解碼
- (UIImage *)decodedImageWithData:(NSData *)data {
if (!data) {
return nil;
}
for (id<SDWebImageCoder> coder in self.coders) {
if ([coder canDecodeFromData:data]) {
return [coder decodedImageWithData:data];
}
}
return nil;
}
3.壓縮圖像. 遍歷self.coders中遵守SDWebImageCoder 的 coder, 然后通過(guò)canDecodeFromData 這個(gè)方法來(lái)判斷是否可以解碼绞惦,如果可以廓推,將圖片壓縮顯示
- (UIImage *)decompressedImageWithImage:(UIImage *)image
data:(NSData *__autoreleasing _Nullable *)data
options:(nullable NSDictionary<NSString*, NSObject*>*)optionsDict {
if (!image) {
return nil;
}
for (id<SDWebImageCoder> coder in self.coders) {
if ([coder canDecodeFromData:*data]) {
return [coder decompressedImageWithImage:image data:data options:optionsDict];
}
}
return nil;
}
4.根據(jù)image和format(類(lèi)型)編碼圖像
- (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format {
if (!image) {
return nil;
}
for (id<SDWebImageCoder> coder in self.coders) {
if ([coder canEncodeToFormat:format]) {
return [coder encodedDataWithImage:image format:format];
}
}
return nil;
}
二、SDWebImageCoder
SDWebImageCoder是單個(gè)coder翩隧,是管理器的操作對(duì)象樊展,SDWebImage里寫(xiě)了兩個(gè)協(xié)議:SDWebImageCoder和SDWebImageProgressiveCoder。SDWebImageCodersManager遵守SDWebImageCoder協(xié)議堆生,SDWebImageImageIOCoder等遵守SDWebImageProgressiveCoder专缠,主要用于設(shè)置一些協(xié)議和公用標(biāo)識(shí)
SDWebImageCoder.h
公共定義
/**
A Boolean value indicating whether to scale down large images during decompressing. (NSNumber)
標(biāo)識(shí)是否在壓縮圖片的時(shí)候縮小圖片的大小
*/
FOUNDATION_EXPORT NSString * _Nonnull const SDWebImageCoderScaleDownLargeImagesKey;
/**
Return the shared device-dependent RGB color space created with CGColorSpaceCreateDeviceRGB.
@return The device-dependent RGB color space
色彩空間:(Color Space)這是一個(gè)色彩范圍的容器,類(lèi)型必須是CGColorSpaceRef.對(duì)于這個(gè)參數(shù)淑仆,我們可以傳入CGColorSpaceCreateDeviceRGB函數(shù)的返回值涝婉,它將給我們一個(gè)RGB色彩空間。
*/
CG_EXTERN CGColorSpaceRef _Nonnull SDCGColorSpaceGetDeviceRGB(void);
/**
Check whether CGImageRef contains alpha channel.
@param imageRef The CGImageRef
@return Return YES if CGImageRef contains alpha channel, otherwise return NO
是否有透明度
*/
CG_EXTERN BOOL SDCGImageRefContainsAlpha(_Nullable CGImageRef imageRef);
SDWebImageCoder協(xié)議
/**
Returns YES if this coder can decode some data. Otherwise, the data should be passed to another coder.
@param data The image data so we can look at it
@return YES if this coder can decode the data, NO otherwise
*/
- (BOOL)canDecodeFromData:(nullable NSData *)data;
/**
Decode the image data to image.
@param data The image data to be decoded
@return The decoded image from data
*/
- (nullable UIImage *)decodedImageWithData:(nullable NSData *)data;
/**
Decompress the image with original image and image data.
@param image The original image to be decompressed
@param data The pointer to original image data. The pointer itself is nonnull but image data can be null. This data will set to cache if needed. If you do not need to modify data at the sametime, ignore this param.
@param optionsDict A dictionary containing any decompressing options. Pass {SDWebImageCoderScaleDownLargeImagesKey: @(YES)} to scale down large images
@return The decompressed image
*/
- (nullable UIImage *)decompressedImageWithImage:(nullable UIImage *)image
data:(NSData * _Nullable * _Nonnull)data
options:(nullable NSDictionary<NSString*, NSObject*>*)optionsDict;
#pragma mark - Encoding
/**
Returns YES if this coder can encode some image. Otherwise, it should be passed to another coder.
@param format The image format
@return YES if this coder can encode the image, NO otherwise
*/
- (BOOL)canEncodeToFormat:(SDImageFormat)format;
/**
Encode the image to image data.
@param image The image to be encoded
@param format The image format to encode, you should note `SDImageFormatUndefined` format is also possible
@return The encoded image data
*/
- (nullable NSData *)encodedDataWithImage:(nullable UIImage *)image format:(SDImageFormat)format;
SDWebImageProgressiveCoder協(xié)議
@required
/**
Returns YES if this coder can incremental decode some data. Otherwise, it should be passed to another coder.
@param data The image data so we can look at it
@return YES if this coder can decode the data, NO otherwise
*/
- (BOOL)canIncrementallyDecodeFromData:(nullable NSData *)data;
/**
Incremental decode the image data to image.
@param data The image data has been downloaded so far
@param finished Whether the download has finished
@warning because incremental decoding need to keep the decoded context, we will alloc a new instance with the same class for each download operation to avoid conflicts
@return The decoded image from data
*/
- (nullable UIImage *)incrementallyDecodedImageWithData:(nullable NSData *)data finished:(BOOL)finished;
SDWebImageCoder.m比較簡(jiǎn)單
獲取顏色空間和判斷圖片是否包含透明度
//獲取顏色空間
CGColorSpaceRef SDCGColorSpaceGetDeviceRGB(void) {
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;
}
三蔗怠、SDWebImageImageIOCoder墩弯,SDWebImageGIFCoder,SDWebImageWebPCoder
這三個(gè)類(lèi)主要實(shí)現(xiàn)SDWebImageCoder的SDWebImageProgressiveCoder協(xié)議
(1)SDWebImageImageIOCoder
內(nèi)置的編碼器寞射,支持PNG渔工,JPEG,TIFF桥温,包括支持漸進(jìn)解碼引矩。
GIF 只處理第一幀
HEIC 取決于 設(shè)備性能
(2)SDWebImageGIFCoder 處理GIF圖像的編解碼
(3)SDWebImageWebPCoder 處理webP的編解碼
四、SDWebImageImageIOCoder
我們首先熟悉下一些定義
static const size_t kBytesPerPixel = 4; //kBytesPerPixel用來(lái)說(shuō)明每個(gè)像素占用內(nèi)存多少個(gè)字節(jié)侵浸,在這里是占用4個(gè)字節(jié)旺韭。(圖像在iOS設(shè)備上是以像素為單位顯示的)。
static const size_t kBitsPerComponent = 8;//kBitsPerComponent表示每一個(gè)組件占多少位掏觉。這個(gè)不太好理解区端,我們先舉個(gè)例子,比方說(shuō)RGBA澳腹,其中R(紅色)G(綠色)B(藍(lán)色)A(透明度)是4個(gè)組件织盼,每個(gè)像素由這4個(gè)組件組成,那么我們就用8位來(lái)表示著每一個(gè)組件遵湖,所以這個(gè)RGBA就是8*4 = 32位悔政。
//知道了kBitsPerComponent和每個(gè)像素有多少組件組成就能計(jì)算kBytesPerPixel了。計(jì)算公式是:(bitsPerComponent * number of components + 7)/8.
/*
* Defines the maximum size in MB of the decoded image when the flag `SDWebImageScaleDownLargeImages` is set
* Suggested value for iPad1 and iPhone 3GS: 60.
* Suggested value for iPad2 and iPhone 4: 120.
* Suggested value for iPhone 3G and iPod 2 and earlier devices: 30.
*/
static const CGFloat kDestImageSizeMB = 60.0f; //最大支持壓縮圖像源的大小默認(rèn)的單位是MB延旧,這里設(shè)置了60MB谋国。當(dāng)我們要壓縮一張圖像的時(shí)候,首先就是要定義最大支持的源文件的大小迁沫,不能沒(méi)有任何限制芦瘾。
/*
* Defines the maximum size in MB of a tile used to decode image when the flag `SDWebImageScaleDownLargeImages` is set
* Suggested value for iPad1 and iPhone 3GS: 20.
* Suggested value for iPad2 and iPhone 4: 40.
* Suggested value for iPhone 3G and iPod 2 and earlier devices: 10.
*/
static const CGFloat kSourceImageTileSizeMB = 20.0f;//原圖方塊的大小,這個(gè)方塊將會(huì)被用來(lái)分割原圖捌蚊,默認(rèn)設(shè)置為20M。
static const CGFloat kBytesPerMB = 1024.0f * 1024.0f;//1M有多少字節(jié)
static const CGFloat kPixelsPerMB = kBytesPerMB / kBytesPerPixel;//1M有多少像素
static const CGFloat kDestTotalPixels = kDestImageSizeMB * kPixelsPerMB;//目標(biāo)總像素
static const CGFloat kTileTotalPixels = kSourceImageTileSizeMB * kPixelsPerMB;//原圖放款總像素
static const CGFloat kDestSeemOverlap = 2.0f; // the numbers of pixels to overlap the seems where tiles meet.重疊像素大小
是否可以解碼,根據(jù)data判斷圖片類(lèi)型,WebP不支持近弟,根據(jù)本機(jī)類(lèi)型來(lái)判斷是否支持SDImageFormatHEIC
- (BOOL)canDecodeFromData:(nullable NSData *)data {
switch ([NSData sd_imageFormatForImageData:data]) {
case SDImageFormatWebP:
// Do not support WebP decoding
return NO;
case SDImageFormatHEIC:
// Check HEIC decoding compatibility
return [[self class] canDecodeFromHEICFormat];
default:
return YES;
}
}
是否可以編碼,并且實(shí)現(xiàn)逐漸顯示效果,根據(jù)data判斷圖片類(lèi)型,WebP不支持缅糟,根據(jù)本機(jī)類(lèi)型來(lái)判斷是否支持SDImageFormatHEIC
- (BOOL)canIncrementallyDecodeFromData:(NSData *)data {
switch ([NSData sd_imageFormatForImageData:data]) {
case SDImageFormatWebP:
// Do not support WebP progressive decoding
return NO;
case SDImageFormatHEIC:
// Check HEIC decoding compatibility
return [[self class] canDecodeFromHEICFormat];
default:
return YES;
}
}
解碼圖像
先通過(guò)initWithData獲取到一個(gè)image,然后獲取data的類(lèi)型
如果是GIF祷愉,用 animatedImageWithImages:duration:方法獲取完整圖像
如果是其他的類(lèi)型窗宦,則通過(guò)sd_imageOrientationFromImageData獲取orientation,然后合成新的圖片
注意: imageWithCGImage: scale: orientation: 這個(gè)方法可以準(zhǔn)確還原原image的方向二鳄,尺寸
- (UIImage *)decodedImageWithData:(NSData *)data {
if (!data) {
return nil;
}
UIImage *image = [[UIImage alloc] initWithData:data];
#if SD_MAC
return image;
#else
if (!image) {
return nil;
}
SDImageFormat format = [NSData sd_imageFormatForImageData:data];
if (format == SDImageFormatGIF) {
// static single GIF need to be created animated for `FLAnimatedImage` logic
// GIF does not support EXIF image orientation
image = [UIImage animatedImageWithImages:@[image] duration:image.duration];
return image;
}
UIImageOrientation orientation = [[self class] sd_imageOrientationFromImageData:data];
if (orientation != UIImageOrientationUp) {
image = [UIImage imageWithCGImage:image.CGImage
scale:image.scale
orientation:orientation];
}
return image;
#endif
}
解碼圖像 逐漸顯示
繪制背景漸變
CGCradientCreateWithColorComponents函數(shù)需要四個(gè)參數(shù):
色彩空間:(Color Space)這是一個(gè)色彩范圍的容器赴涵,類(lèi)型必須是CGColorSpaceRef.對(duì)于這個(gè)參數(shù),我們可以傳入CGColorSpaceCreateDeviceRGB函數(shù)的返回值订讼,它將給我們一個(gè)RGB色彩空間髓窜。
顏色分量的數(shù)組:這個(gè)數(shù)組必須包含CGFloat類(lèi)型的紅、綠欺殿、藍(lán)和alpha值寄纵。數(shù)組中元素的數(shù)量和接下來(lái)兩個(gè)參數(shù)密切。從本質(zhì)來(lái)講脖苏,你必須讓這個(gè)數(shù)組包含足夠的值程拭,用來(lái)指定第四個(gè)參數(shù)中位置的數(shù)量。所以如果你需要兩個(gè)位置位置(起點(diǎn)和終點(diǎn))帆阳,那么你必須為數(shù)組提供兩種顏色
位置數(shù)組哺壶,顏色數(shù)組中各個(gè)顏色的位置:此參數(shù)控制該漸變從一種顏色過(guò)渡到另一種顏色的速度有多快屋吨。
位置的數(shù)量:這個(gè)參數(shù)指明了我們需要多少顏色和位置蜒谤。
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
CGFloat colors[] =
{
51.0 / 255.0, 160.0 / 255.0, 0.0 / 255.0, 1.00,
68.0 / 255.0, 198.0 / 255.0, 0.0 / 255.0, 1.00,
// 0.0 / 255.0, 50.0 / 255.0, 126.0 / 255.0, 1.00,
};
CGGradientRef myGradient = CGGradientCreateWithColorComponents(rgb, colors, NULL, sizeof(colors)/(sizeof(colors[0])*4));
// Allocate bitmap context
CGContextRef bitmapContext = CGBitmapContextCreate(NULL, 320, TITLE_CONTROL_HEIGHT, 8, 4 * 320, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipFirst);
創(chuàng)建好線性漸變后,我們將使用CGContextDrawLinearGradient過(guò)程在圖形上下文中繪制至扰,此過(guò)程需要五個(gè)參數(shù):
Graphics context 指定用于繪制線性漸變的圖形上下文鳍徽。
Axial gradient 我們使用CGGradientCreateWithColorComponents函數(shù)創(chuàng)建的線性漸變對(duì)象的句柄
start point 圖形上下文中的一個(gè)CGPoint類(lèi)型的點(diǎn),表示漸變的起點(diǎn)敢课。
End Point表示漸變的終點(diǎn)阶祭。
Gradient drawing options 當(dāng)你的起點(diǎn)或者終點(diǎn)不在圖形上下文的邊緣內(nèi)時(shí),指定該如何處理直秆。你可以使用你的開(kāi)始或結(jié)束顏色來(lái)填充漸變以外的空間濒募。此參數(shù)為以下值之一:KCGGradientDrawsAfterEndLocation擴(kuò)展整個(gè)漸變到漸變的終點(diǎn)之后的所有點(diǎn) KCGGradientDrawsBeforeStartLocation擴(kuò)展整個(gè)漸變到漸變的起點(diǎn)之前的所有點(diǎn)。0不擴(kuò)展該漸變圾结。
- (UIImage *)incrementallyDecodedImageWithData:(NSData *)data finished:(BOOL)finished {
if (!_imageSource) {
_imageSource = CGImageSourceCreateIncremental(NULL);
}
UIImage *image;
// The following code is from http://www.cocoaintheshell.com/2011/05/progressive-images-download-imageio/
// Thanks to the author @Nyx0uf
// Update the data source, we must pass ALL the data, not just the new bytes
CGImageSourceUpdateData(_imageSource, (__bridge CFDataRef)data, finished);
if (_width + _height == 0) {
CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(_imageSource, 0, NULL);//獲取圖像的屬性信息
if (properties) {
NSInteger orientationValue = 1;
CFTypeRef val = CFDictionaryGetValue(properties, kCGImagePropertyPixelHeight);//獲取圖片高度信息
if (val) CFNumberGetValue(val, kCFNumberLongType, &_height); //將圖片高度綁定在_height上
val = CFDictionaryGetValue(properties, kCGImagePropertyPixelWidth); //獲取圖片寬度信息
if (val) CFNumberGetValue(val, kCFNumberLongType, &_width);//將圖片寬度綁定在_width上
val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation); //獲取圖像方向信息
if (val) CFNumberGetValue(val, kCFNumberNSIntegerType, &orientationValue);//將圖片的方向信息綁定在orientationValue上
CFRelease(properties);
// When we draw to Core Graphics, we lose orientation information,
// which means the image below born of initWithCGIImage will be
// oriented incorrectly sometimes. (Unlike the image born of initWithData
// in didCompleteWithError.) So save it here and pass it on later.
#if SD_UIKIT || SD_WATCH
_orientation = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:orientationValue]; //轉(zhuǎn)換方向信息
#endif
}
}
if (_width + _height > 0) {
// Create the image
CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(_imageSource, 0, NULL); //獲取圖像
#if SD_UIKIT || SD_WATCH
// Workaround for iOS anamorphic image
if (partialImageRef) {
const size_t partialHeight = CGImageGetHeight(partialImageRef);
CGColorSpaceRef colorSpace = SDCGColorSpaceGetDeviceRGB();//色彩空間
CGContextRef bmContext = CGBitmapContextCreate(NULL, _width, _height, 8, 0, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst); //創(chuàng)建上下文
if (bmContext) {
CGContextDrawImage(bmContext, (CGRect){.origin.x = 0.0f, .origin.y = 0.0f, .size.width = _width, .size.height = partialHeight}, partialImageRef); //繪制圖像
CGImageRelease(partialImageRef);
partialImageRef = CGBitmapContextCreateImage(bmContext);
CGContextRelease(bmContext);
}
else {
CGImageRelease(partialImageRef);
partialImageRef = nil;
}
}
#endif
if (partialImageRef) { //拿到CGImageRef 轉(zhuǎn)換成image并且返回
#if SD_UIKIT || SD_WATCH
image = [UIImage imageWithCGImage:partialImageRef scale:1 orientation:_orientation];
#elif SD_MAC
image = [[UIImage alloc] initWithCGImage:partialImageRef size:NSZeroSize];
#endif
CGImageRelease(partialImageRef);
}
}
if (finished) { //下載完成瑰剃,銷(xiāo)毀對(duì)象
if (_imageSource) {
CFRelease(_imageSource);
_imageSource = NULL;
}
}
return image;
}
壓縮圖片
- (UIImage *)decompressedImageWithImage:(UIImage *)image
data:(NSData *__autoreleasing _Nullable *)data
options:(nullable NSDictionary<NSString*, NSObject*>*)optionsDict {
#if SD_MAC
return image;
#endif
#if SD_UIKIT || SD_WATCH
BOOL shouldScaleDown = NO;
if (optionsDict != nil) { //判斷是否有在壓縮過(guò)程中縮小圖片尺寸的標(biāo)識(shí)
NSNumber *scaleDownLargeImagesOption = nil;
if ([optionsDict[SDWebImageCoderScaleDownLargeImagesKey] isKindOfClass:[NSNumber class]]) {
scaleDownLargeImagesOption = (NSNumber *)optionsDict[SDWebImageCoderScaleDownLargeImagesKey];
}
if (scaleDownLargeImagesOption != nil) {
shouldScaleDown = [scaleDownLargeImagesOption boolValue];
}
}
if (!shouldScaleDown) {//如果沒(méi)有壓縮過(guò)程中縮小圖片尺寸的標(biāo)識(shí)
return [self sd_decompressedImageWithImage:image];
} else {//如果有壓縮過(guò)程中縮小圖片尺寸的標(biāo)識(shí)
UIImage *scaledDownImage = [self sd_decompressedAndScaledDownImageWithImage:image];
if (scaledDownImage && !CGSizeEqualToSize(scaledDownImage.size, image.size)) {
// if the image is scaled down, need to modify the data pointer as well
SDImageFormat format = [NSData sd_imageFormatForImageData:*data];
NSData *imageData = [self encodedDataWithImage:scaledDownImage format:format]; //解碼
if (imageData) {
*data = imageData;
}
}
return scaledDownImage;
}
#endif
}