版本記錄
版本號(hào) | 時(shí)間 |
---|---|
V1.0 | 2018.02.25 |
前言
我們做APP括袒,文字和圖片是絕對(duì)不可缺少的元素厦滤,特別是圖片一般存儲(chǔ)在圖床里面援岩,一般公司可以委托第三方保存,NB的公司也可以自己存儲(chǔ)圖片掏导,ios有很多圖片加載的第三方框架享怀,其中最優(yōu)秀的莫過(guò)于SDWebImage,它幾乎可以滿(mǎn)足你所有的需求趟咆,用了好幾年這個(gè)框架添瓷,今天想總結(jié)一下。感興趣的可以看其他幾篇值纱。
1. SDWebImage探究(一)
2. SDWebImage探究(二)
3. SDWebImage探究(三)
4. SDWebImage探究(四)
5. SDWebImage探究(五)
6. SDWebImage探究(六) —— 圖片類(lèi)型判斷深入研究
7. SDWebImage探究(七) —— 深入研究圖片下載流程(一)之有關(guān)option的位移枚舉的說(shuō)明
8. SDWebImage探究(八) —— 深入研究圖片下載流程(二)之開(kāi)始下載并返回下載結(jié)果的總的方法
9. SDWebImage探究(九) —— 深入研究圖片下載流程(三)之下載之前的緩存查詢(xún)操作
10. SDWebImage探究(十) —— 深入研究圖片下載流程(四)之查詢(xún)緩存后的block回調(diào)處理
11. SDWebImage探究(十一) —— 深入研究圖片下載流程(五)之SDWebImageDownloadToken和操作對(duì)象的生成和返回
12. SDWebImage探究(十二) —— 深入研究圖片下載流程(六)之下載器到具體下載操作的代理分發(fā)實(shí)現(xiàn)
13. SDWebImage探究(十三) —— 深入研究圖片下載流程(七)之NSURLSession中幾個(gè)代理的基本用法和關(guān)系
14. SDWebImage探究(十四) —— 深入研究圖片下載流程(八)之下載完成代理方法的調(diào)用
15. SDWebImage探究(十五) —— 深入研究圖片下載流程(九)之身份驗(yàn)證質(zhì)詢(xún)代理方法調(diào)用
16. SDWebImage探究(十六) —— 深入研究圖片下載流程(十)之緩存相關(guān)代理方法調(diào)用
17. SDWebImage探究(十七) —— 深入研究圖片下載流程(十一)之收到響應(yīng)代理方法調(diào)用
18. SDWebImage探究(十八) —— 深入研究圖片下載流程(十二)之收到圖像數(shù)據(jù)代理方法調(diào)用
圖像為什么需要解碼
一般下載或者從磁盤(pán)獲取的圖片是PNG或者JPG鳞贷,這是經(jīng)過(guò)編碼壓縮后的圖片數(shù)據(jù),不是位圖虐唠,要把它們渲染到屏幕前就需要進(jìn)行解碼轉(zhuǎn)成位圖數(shù)據(jù)搀愧,而這個(gè)解碼操作比較耗時(shí)。你也可以這么理解疆偿,圖片在遠(yuǎn)端存儲(chǔ)一定都是編碼后存儲(chǔ)的咱筛,這樣體積小,一個(gè)圖像可以看做是一個(gè)圖像文件杆故,里面包含了文件頭迅箩,文件體和文件尾,圖像的數(shù)據(jù)就包含在文件體中处铛,而我們的解碼就是運(yùn)用算法將文件體中的圖像數(shù)據(jù)轉(zhuǎn)化為位圖數(shù)據(jù)沙热,方便渲染和展示叉钥。
iOS默認(rèn)是在主線(xiàn)程解碼罢缸,所以SDWebImage將這個(gè)過(guò)程放到子線(xiàn)程了篙贸。
同時(shí)因?yàn)槲粓D體積很大,所以磁盤(pán)緩存不會(huì)直接緩存位圖數(shù)據(jù)枫疆,而是編碼壓縮后的PNG或JPG數(shù)據(jù)爵川。
圖像是否可以解碼的判斷
這里有幾種情況是不進(jìn)行解碼的。
- 動(dòng)圖息楔,判斷
image.images != nil
寝贡,滿(mǎn)足這個(gè)條件的就是動(dòng)圖,就不解碼值依。 - 有alpha信息的圖片不解碼圃泡。
1. 動(dòng)圖
這里首先要糾正一個(gè)概念,動(dòng)態(tài)圖片也不僅僅限于gif愿险,png格式也有動(dòng)態(tài)的颇蜡,只是常見(jiàn)的是GIF格式的比較多而已。
這里動(dòng)圖為什么不解碼呢辆亏?
這個(gè)我還沒(méi)找到正確的答案风秤,猜測(cè)可能是動(dòng)圖解碼后的數(shù)據(jù)占用內(nèi)存太大,所以就不對(duì)動(dòng)圖進(jìn)行解碼了扮叨。關(guān)于GIF動(dòng)圖的支持在FLAnimatedImageView
分類(lèi)中缤弦。
2. 有alpha信息的圖片
(a) 有alpha信息的圖片的判斷
首先我們需要判斷的就是什么圖片包含alpha信息,蘋(píng)果提供了支持彻磁。
/* Return the alpha info of `image'. */
CG_EXTERN CGImageAlphaInfo CGImageGetAlphaInfo(CGImageRef cg_nullable image)
CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
CGImageRef imageRef = image.CGImage;
CGImageAlphaInfo alpha = CGImageGetAlphaInfo(imageRef);
BOOL anyAlpha = (alpha == kCGImageAlphaFirst ||
alpha == kCGImageAlphaLast ||
alpha == kCGImageAlphaPremultipliedFirst ||
alpha == kCGImageAlphaPremultipliedLast);
這里需要說(shuō)明的就是CGImageAlphaInfo
碍沐,這個(gè)是什么鬼?
typedef CF_ENUM(uint32_t, CGImageAlphaInfo) {
kCGImageAlphaNone, /* For example, RGB. */
kCGImageAlphaPremultipliedLast, /* For example, premultiplied RGBA */
kCGImageAlphaPremultipliedFirst, /* For example, premultiplied ARGB */
kCGImageAlphaLast, /* For example, non-premultiplied RGBA */
kCGImageAlphaFirst, /* For example, non-premultiplied ARGB */
kCGImageAlphaNoneSkipLast, /* For example, RBGX. */
kCGImageAlphaNoneSkipFirst, /* For example, XRGB. */
kCGImageAlphaOnly /* No color data, alpha data only */
};
這是CoreGraphic
框架中CGImage.h
中的一個(gè)枚舉衷蜓。
圖像的解碼實(shí)現(xiàn)
SDWebImage中有關(guān)于圖像解碼的部分累提,我們先看一下實(shí)現(xiàn)方式,然后進(jìn)行詳細(xì)的解析恍箭。
+ (nullable UIImage *)decodedImageWithImage:(nullable UIImage *)image {
if (![UIImage shouldDecodeImage:image]) {
return image;
}
// autorelease the bitmap context and all vars to help system to free memory when there are memory warning.
// on iOS7, do not forget to call [[SDImageCache sharedImageCache] clearMemory];
@autoreleasepool{
CGImageRef imageRef = image.CGImage;
CGColorSpaceRef colorspaceRef = [UIImage colorSpaceForImageRef:imageRef];
size_t width = CGImageGetWidth(imageRef);
size_t height = CGImageGetHeight(imageRef);
size_t bytesPerRow = kBytesPerPixel * width;
// kCGImageAlphaNone is not supported in CGBitmapContextCreate.
// Since the original image here has no alpha info, use kCGImageAlphaNoneSkipLast
// to create bitmap graphics contexts without alpha info.
CGContextRef context = CGBitmapContextCreate(NULL,
width,
height,
kBitsPerComponent,
bytesPerRow,
colorspaceRef,
kCGBitmapByteOrderDefault|kCGImageAlphaNoneSkipLast);
if (context == NULL) {
return image;
}
// Draw the image into the context and retrieve the new bitmap image without alpha
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGImageRef imageRefWithoutAlpha = CGBitmapContextCreateImage(context);
UIImage *imageWithoutAlpha = [UIImage imageWithCGImage:imageRefWithoutAlpha
scale:image.scale
orientation:image.imageOrientation];
CGContextRelease(context);
CGImageRelease(imageRefWithoutAlpha);
return imageWithoutAlpha;
}
}
+ (BOOL)shouldDecodeImage:(nullable UIImage *)image {
// Prevent "CGBitmapContextCreateImage: invalid context 0x0" error
if (image == nil) {
return NO;
}
// do not decode animated images
if (image.images != nil) {
return NO;
}
CGImageRef imageRef = image.CGImage;
CGImageAlphaInfo alpha = CGImageGetAlphaInfo(imageRef);
BOOL anyAlpha = (alpha == kCGImageAlphaFirst ||
alpha == kCGImageAlphaLast ||
alpha == kCGImageAlphaPremultipliedFirst ||
alpha == kCGImageAlphaPremultipliedLast);
// do not decode images with alpha
if (anyAlpha) {
return NO;
}
return YES;
}
+ (CGColorSpaceRef)colorSpaceForImageRef:(CGImageRef)imageRef {
// current
CGColorSpaceModel imageColorSpaceModel = CGColorSpaceGetModel(CGImageGetColorSpace(imageRef));
CGColorSpaceRef colorspaceRef = CGImageGetColorSpace(imageRef);
BOOL unsupportedColorSpace = (imageColorSpaceModel == kCGColorSpaceModelUnknown ||
imageColorSpaceModel == kCGColorSpaceModelMonochrome ||
imageColorSpaceModel == kCGColorSpaceModelCMYK ||
imageColorSpaceModel == kCGColorSpaceModelIndexed);
if (unsupportedColorSpace) {
colorspaceRef = CGColorSpaceCreateDeviceRGB();
CFAutorelease(colorspaceRef);
}
return colorspaceRef;
}
這里做的就是首先判斷什么樣的圖像可以解碼刻恭,是一個(gè)類(lèi)方法,如果不能就直接返回傳入的image
參數(shù)扯夭,如果可以解碼就對(duì)圖像進(jìn)行解碼后返回鳍贾。
這里有幾個(gè)點(diǎn)需要說(shuō)明:
(a) CGBitmapContextCreate上下文的創(chuàng)建
kCGImageAlphaNone
在CGBitmapContextCreate
中不受支持。由于此處的原始圖像沒(méi)有alpha信息交洗,因此請(qǐng)使用kCGImageAlphaNoneSkipLast
創(chuàng)建不帶alpha信息的位圖圖形上下文骑科。
這里我們看一下,這個(gè)上下文創(chuàng)建的API
/* Create a bitmap context. The context draws into a bitmap which is `width'
pixels wide and `height' pixels high. The number of components for each
pixel is specified by `space', which may also specify a destination color
profile. The number of bits for each component of a pixel is specified by
`bitsPerComponent'. The number of bytes per pixel is equal to
`(bitsPerComponent * number of components + 7)/8'. Each row of the bitmap
consists of `bytesPerRow' bytes, which must be at least `width * bytes
per pixel' bytes; in addition, `bytesPerRow' must be an integer multiple
of the number of bytes per pixel. `data', if non-NULL, points to a block
of memory at least `bytesPerRow * height' bytes. If `data' is NULL, the
data for context is allocated automatically and freed when the context is
deallocated. `bitmapInfo' specifies whether the bitmap should contain an
alpha channel and how it's to be generated, along with whether the
components are floating-point or integer. */
CG_EXTERN CGContextRef __nullable CGBitmapContextCreate(void * __nullable data,
size_t width, size_t height, size_t bitsPerComponent, size_t bytesPerRow,
CGColorSpaceRef cg_nullable space, uint32_t bitmapInfo)
CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
創(chuàng)建一個(gè)位圖上下文构拳。 上下文繪制成寬度為width
像素和height
像素為高的位圖咆爽。 每個(gè)像素的組件數(shù)量由space
指定梁棠,它也可以指定目標(biāo)顏色配置文件。 像素的每個(gè)分量的位數(shù)由bitsPerComponent
指定斗埂。 每個(gè)像素的字節(jié)數(shù)等于(bitsPerComponent *components+7)/ 8
符糊。 位圖的每一行都由bytesPerRow
字節(jié)組成,它們必須至少為每個(gè)像素的字節(jié)數(shù) * 寬度width
呛凶。另外男娄,bytesPerRow
必須是每個(gè)像素字節(jié)數(shù)的整數(shù)倍。 data
漾稀,如果非NULL模闲,則至少指向bytesPerRow * height
字節(jié)的內(nèi)存塊。 如果data
為NULL崭捍,上下文數(shù)據(jù)將自動(dòng)分配尸折,并在釋放上下文時(shí)釋放。 bitmapInfo
指定位圖是否應(yīng)該包含一個(gè)alpha通道以及如何生成殷蛇,以及組件是浮點(diǎn)還是整數(shù)实夹。
(b) 位圖信息CGBitmapInfo
最后一個(gè)參數(shù),關(guān)于CGBitmapInfo
的一個(gè)枚舉晾咪。
typedef CF_OPTIONS(uint32_t, CGBitmapInfo) {
kCGBitmapAlphaInfoMask = 0x1F,
kCGBitmapFloatInfoMask = 0xF00,
kCGBitmapFloatComponents = (1 << 8),
kCGBitmapByteOrderMask = kCGImageByteOrderMask,
kCGBitmapByteOrderDefault = (0 << 12),
kCGBitmapByteOrder16Little = kCGImageByteOrder16Little,
kCGBitmapByteOrder32Little = kCGImageByteOrder32Little,
kCGBitmapByteOrder16Big = kCGImageByteOrder16Big,
kCGBitmapByteOrder32Big = kCGImageByteOrder32Big
} CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);
這里存放的就是位圖組成部分的信息收擦。
-
kCGBitmapAlphaInfoMask
- Aplha通道信息遮罩圈纺。用這個(gè)值來(lái)提取alpha信息嗜傅。這個(gè)值明確了位圖是否包含了alpha通道和alpha通道是如何生成的。
-
kCGBitmapFloatComponents
- 位圖數(shù)據(jù)都是浮點(diǎn)值跌前。
-
kCGBitmapByteOrderMask
- 像素格式的字節(jié)順序
-
kCGBitmapByteOrderDefault
- 默認(rèn)的字節(jié)順序
-
kCGBitmapByteOrder16Little
- 16位小端格式
-
kCGBitmapByteOrder32Little
- 32位小端格式
-
kCGBitmapByteOrder16Big
- 16位大端格式
-
kCGBitmapByteOrder32Big
- 32位大端格式
(c) 生成圖像顏色空間CGColorSpaceRef
// current
CGColorSpaceModel imageColorSpaceModel = CGColorSpaceGetModel(CGImageGetColorSpace(imageRef));
CGColorSpaceRef colorspaceRef = CGImageGetColorSpace(imageRef);
BOOL unsupportedColorSpace = (imageColorSpaceModel == kCGColorSpaceModelUnknown ||
imageColorSpaceModel == kCGColorSpaceModelMonochrome ||
imageColorSpaceModel == kCGColorSpaceModelCMYK ||
imageColorSpaceModel == kCGColorSpaceModelIndexed);
if (unsupportedColorSpace) {
colorspaceRef = CGColorSpaceCreateDeviceRGB();
CFAutorelease(colorspaceRef);
}
return colorspaceRef;
這里昼蛀,CGColorSpaceRef
表示需要使用的色彩標(biāo)準(zhǔn)(為創(chuàng)建CGColor做準(zhǔn)備)例如RBG:CGColorSpaceCreateDeviceRGB
宴猾。
Quartz支持由顏色管理系統(tǒng)使用的與設(shè)備無(wú)關(guān)的顏色空間的標(biāo)準(zhǔn)顏色空間,并且還支持通用叼旋,索引和模式顏色空間仇哆。 設(shè)備無(wú)關(guān)的顏色空間以在設(shè)備之間可移植的方式表示顏色。 它們用于將顏色數(shù)據(jù)從一個(gè)設(shè)備的本地顏色空間到另一個(gè)設(shè)備的本地顏色空間的交換夫植。 在不同設(shè)備上顯示時(shí)讹剔,設(shè)備無(wú)關(guān)顏色空間中的顏色顯示相同,只要設(shè)備的功能允許详民。 因此延欠,與設(shè)備無(wú)關(guān)的顏色空間是表示顏色的最佳選擇。
具有精確顏色要求的應(yīng)用程序應(yīng)始終使用與設(shè)備無(wú)關(guān)的顏色空間沈跨。 常見(jiàn)的設(shè)備無(wú)關(guān)顏色空間是通用顏色空間由捎。 通用顏色空間使操作系統(tǒng)為您的應(yīng)用程序提供最佳的顏色空間。 繪圖到顯示看起來(lái)像打印相同的內(nèi)容到打印機(jī)饿凛。
重點(diǎn):iOS不支持設(shè)備無(wú)關(guān)或通用顏色空間狞玛。 iOS應(yīng)用程序必須使用設(shè)備顏色空間软驰。
下面看一下CGColorSpaceModel
,顏色空間模型心肪。
/* The model of a color space. */
typedef CF_ENUM (int32_t, CGColorSpaceModel) {
kCGColorSpaceModelUnknown = -1,
kCGColorSpaceModelMonochrome,
kCGColorSpaceModelRGB,
kCGColorSpaceModelCMYK,
kCGColorSpaceModelLab,
kCGColorSpaceModelDeviceN,
kCGColorSpaceModelIndexed,
kCGColorSpaceModelPattern
};
參考文章
1. SDWebImageDecoder引發(fā)的思考
2. CGBitmapInfo
3. 【CoreGraphics】CGColorSpace - 色彩空間
4. Color and Color Spaces
后記
本篇文章主要解析了圖像解碼相關(guān)锭亏,包括為什么要進(jìn)行圖像解碼、是否可以解碼的判斷以及解碼的代碼實(shí)現(xiàn)等幾個(gè)問(wèn)題蒙畴。