ios 圖片的解壓縮

圖片的解壓縮

最近在看 SDWebimage 的源碼自点,順便補習下圖片的解壓縮原理

參考1參考2

我們一班看到的圖片,都是如 png jpeg 之類的圖片疚漆,都是經(jīng)過編碼的,為什么要編碼蚊惯,如果不編碼將圖片的原始信息傳輸愿卸,那么他的大小會非常非常大,不利用傳輸截型,所以經(jīng)過壓縮編碼之后趴荸,效率更加

位圖其實就是一個像素點陣圖像,包含的一個一個像素點宦焦,將這些像素點組裝起來放到屏幕上就可以顯示了发钝。

平時我們的使用

UIImageView *imageView = ...;
UIImage *image = [UIImage imageWithContentsOfFile:@"/.../.../path.JPG"];
imageView.image = image;

我們這樣取用,UIImage *image = [UIImage imageWithContentsOfFile:@"/.../.../path.JPG"]; 這樣其實并沒有對圖片進行解壓縮波闹,當我們賦值給imageview 的image時候酝豪,圖片馬上要渲染到屏幕上的時候,系統(tǒng)會為我們解壓縮精堕,并且是在主線程中進行的孵淘,是非常耗cpu性能的,所以歹篓,你想瘫证,我們的tableview中揉阎,有很多圖片,每次都這樣去設置背捌,那能不卡嗎毙籽?所以現(xiàn)在用到的第三方框架,都是提前給你在子線程解碼好了毡庆,顯示的時候拿來顯示就可以了

解碼 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)建一個 CGContextRef 上下文坑赡,來分析下每個參數(shù)的含義

bitsPerComponent:表示每一個成分有多少位組成,Component 就是指顏色分量么抗,例如 RGB 中毅否,指定 R/G/B 這些顏色分量由多少位來表示
bytesPerPixel:表示一個像素點有多少個字節(jié)組成,上面的方法注釋中提到了一個公式 (bitsPerComponent * number of components + 7)/8蝇刀,即一個像素點的字節(jié)數(shù)量與表示當前圖像的顏色的顏色分量數(shù)量和每個分量的位數(shù)有關
bytesPerRow:圖像一行有多少字節(jié)搀突,上面注釋中也提到了,它一般是width * bytes per pixel熊泵,很好理解仰迁,也就是圖像像素寬度與每個像素字節(jié)大小的乘積。所以我們可以想到最開始我們說的那個計算位圖大小的公式顽分,只要 bytesPerRow 再乘上圖像的像素高度 height 即可徐许。
space:即顏色空間,我們平常一直說的 RGB 就是一種顏色空間卒蘸,另外還有 CMYK 也都是顏色空間雌隅,每個像素的信息必須要在一個顏色空間中才有意義。也就是說缸沃,我們通過顏色空間告訴系統(tǒng)一個像素上面的顏色信息都是什么意思恰起。顯然同樣的一個位圖每一個像素的信息,在 RGB 顏色中間中表示的意思與在 CMYK 中是不同的趾牧,最后渲染出來的圖像一定是不一樣的检盼。

我們的手機一般支持 RGB 顏色空間,其 bitsPerComponent = 8翘单。那 bytesPerPixel 是多少呢吨枉,根據(jù)上面的公式,我們首先要知道 RGB 中有多少顏色分量呢哄芜?我們可能認為是 3貌亭,因為紅、綠认臊、藍就是 3 個分量圃庭,實際上一般是4?因為 RGB 顏色空間中,其實還要包含一個 alpha 通道剧腻,也就是透明度斟薇。所以實際上應該是 ARGB 或者 RGBA,兩者的區(qū)別就是 alpha 通道在哪里表示恕酸,這個下面還會再說。當然也可能是3胯陋,那就說明沒有 alpha 通道∪镂拢現(xiàn)在就是知道了 RGB 顏色空間中,實際上是有 4 個分量遏乔,所以我們可以算出 bytesPerPixel = (8 * 4 + 7)/8 = 4B义矛。所以我們現(xiàn)在知道為什么最開始的時候我們計算位圖的大小的時候,每個像素的大小我們使用的值是 4B 了盟萨。事實上不同的顏色空間下凉翻,上面這些值都是不同的,但是一般在手機上捻激,我們使用 RGB 顏色空間制轰,所以差不多就是上面的值。

現(xiàn)在我們回到上面那個方法的參數(shù)上面:
第一個參數(shù)data胞谭,根據(jù)注釋垃杖,我們可以賦值為 NULL,這樣系統(tǒng)會自動幫我們分配和釋放相應大小的空間丈屹。
第二個參數(shù)和第三個參數(shù)即上下文的寬和高调俘,因為我們根據(jù)原始的圖片來創(chuàng)建上下文進行渲染,所以這兩個值就是原始圖片的寬和高旺垒。
第四個參數(shù)bitsPerComponent我們知道了就是每個成分由多少位組成彩库,因為我們默認實在 RGB 顏色空間中,所以一般都是傳入 8先蒋。
第五個參數(shù)bytesPerRow骇钦,這個我之前也專門介紹過了,就是像素寬度與每個像素大小的乘積竞漾,因為這些值都是知道的司忱,我們可以這么傳入。當然這里我們還可以直接傳入0畴蹭,這樣系統(tǒng)會幫我們進行計算坦仍,而且這樣做系統(tǒng)還會幫我們做一些優(yōu)化,這樣更好叨襟。
第六個參數(shù)space即顏色空間繁扎,我們可以直接使用RGB,直接使用系統(tǒng)提供的 API 獲取: CGColorSpaceCreateDeviceRGB()
第七個參數(shù)bitmapInfo表示位圖的布局信息梳玫。這個參數(shù)實際上系統(tǒng)提供了一個枚舉值

顏色空間

顏色空間是對色彩的一種描述方式爹梁,主要有6種:RGB、CMY/CMYK提澎、HSV/HSB姚垃、HSI/HSL、Lab盼忌、YUV/YCbCr积糯。

比如RGB是通過紅綠藍三原色來描述顏色的顏色空間,R=Red谦纱、G=Green看成、B=Blue。RGB顏色空間下跨嘉,一個像素由R川慌、G、B三個顏色分量表示祠乃,每個分量使用的bit 數(shù)就是bpc梦重。若每個分量用8位,那么一個像素共用24位表示亮瓷,24就是像素的深度忍饰。

最常用的就是RGB和CMYK。同一個色值在不同的顏色空間下表現(xiàn)出來是不同的顏色寺庄。

比如我們拿一個RGB格式的圖片去打印艾蓝,會發(fā)現(xiàn)打印出來的顏色和我們在電腦上面看到的有色差,這就是因為顏色空間不同導致的斗塘,因為打印機的顏色空間是CMYK赢织。

PBC

然后這個的PBC就是一個像素中每個獨立的顏色分量使用的 bit 數(shù)。

顏色分量是什么馍盟?比如RGB是通過紅綠藍三原色來描述顏色的顏色空間于置,R=Red、G=Green贞岭、B=Blue八毯,也就是紅綠藍。RGB顏色空間下瞄桨,一個像素就由R话速、G、B三個顏色分量表示芯侥,這個就是顏色分量泊交。每個分量使用的bit 數(shù)就是bpc乳讥。

如果每個分量用8位,那么一個像素共用24位表示廓俭,24就是像素的深度云石。再加上如果有透明度信息,那就是8888研乒,一共有32位也就是4個字節(jié)汹忠,就是我們前面說的iOS中每個像素所占的字節(jié)數(shù)。

BitmapInfo

然后還有BitmapInfo雹熬。BitmapInfo就是用來說明每個像素中的bits包含了哪些信息宽菜。有以下三個方面:

是否包含Alpha通道,如果包含 alpha 橄唬,那么 alpha 信息所處的位置,在像素的最低有效位参歹,比如 RGBA 仰楚,還是最高有效位,比如 ARGB 犬庇;
如果包含 alpha 僧界,那么每個顏色分量是否已經(jīng)乘以 alpha 的值,這種做法可以加速圖片的渲染時間臭挽,因為它避免了渲染時的額外乘法運算捂襟。比如,對于 RGB 顏色空間欢峰,用已經(jīng)乘以 alpha 的數(shù)據(jù)來渲染圖片葬荷,每個像素都可以避免 3 次乘法運算,紅色乘以 alpha 纽帖,綠色乘以 alpha 和藍色乘以 alpha
顏色分量是否為浮點數(shù)

iOS中宠漩,alpha通道的布局信息是一個枚舉值 CGImageAlphaInfo ,有以下幾種情況:

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 */
};
kCGImageAlphaNone : 無alpha通道
kCGImageAlphaOnly:無顏色數(shù)據(jù)懊直,只有alpha通道
kCGImageAlphaNoneSkipLast扒吁、kCGImageAlphaNoneSkipFirst :有alpha通道,但是忽略了alpha值室囊,即透明度不起作用雕崩。兩者的區(qū)別是alpha通道所在的位置
kCGImageAlphaLast、kCGImageAlphaFirst:有alpha通道融撞,且alpha通道起作用盼铁,兩者的區(qū)別是alpha通道所在的位置不同
kCGImageAlphaPremultipliedLast、kCGImageAlphaPremultipliedFirst :有alpha通道尝偎,且alpha通道起作用捉貌。這兩個值的區(qū)別是alpha通道坐在的位置不同。和kCGImageAlphaLast、kCGImageAlphaFirst的區(qū)別是:帶有Premultiplied趁窃,在解壓縮的時候就將透明度乘到每個顏色分量上牧挣,這樣渲染的時候就不用再處理alpha通道,提高了渲染的效率醒陆。

根據(jù)蘋果官方文檔的介紹瀑构,如果圖片無alpha通道,則應該使用kCGImageAlphaNoneSkipFirst刨摩,如果圖片含alpha通道寺晌,則應該使用kCGImageAlphaPremultipliedFirst。

然后就是bitmapInfo澡刹。這個參數(shù)除了要指定alpha的信息外呻征,就是前面提到的ARGB還是RGBA,另外還需要指定字節(jié)順序罢浇。

字節(jié)順序分為兩種:小端模式和大端模式陆赋。它是由枚舉值 CGImageByteOrderInfo 來表示的:

typedef CF_ENUM(uint32_t, CGImageByteOrderInfo) {
    kCGImageByteOrderMask     = 0x7000,
    kCGImageByteOrderDefault  = (0 << 12),
    kCGImageByteOrder16Little = (1 << 12),
    kCGImageByteOrder32Little = (2 << 12),
    kCGImageByteOrder16Big    = (3 << 12),
    kCGImageByteOrder32Big    = (4 << 12)
} CG_AVAILABLE_STARTING(10.0, 2.0);

在iOS中使用的是小端模式,在macOS中使用的是大端模式嚷闭,為了兼容攒岛,使用kCGBitmapByteOrder32Host,32位字節(jié)順序胞锰,該宏在不同的平臺上面會自動組裝換成不同的模式灾锯。32是指數(shù)據(jù)以32bit為單位(字節(jié)順序)。字節(jié)順序也以32bit為單位排序嗅榕。

#ifdef __BIG_ENDIAN__
# define kCGBitmapByteOrder16Host kCGBitmapByteOrder16Big
# define kCGBitmapByteOrder32Host kCGBitmapByteOrder32Big
#else    /* Little endian. */
# define kCGBitmapByteOrder16Host kCGBitmapByteOrder16Little
# define kCGBitmapByteOrder32Host kCGBitmapByteOrder32Little
#endif
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末顺饮,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子凌那,更是在濱河造成了極大的恐慌领突,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件案怯,死亡現(xiàn)場離奇詭異君旦,居然都是意外死亡,警方通過查閱死者的電腦和手機嘲碱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門金砍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人麦锯,你說我怎么就攤上這事恕稠。” “怎么了扶欣?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵鹅巍,是天一觀的道長千扶。 經(jīng)常有香客問我,道長骆捧,這世上最難降的妖魔是什么澎羞? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮敛苇,結果婚禮上妆绞,老公的妹妹穿的比我還像新娘。我一直安慰自己枫攀,他們只是感情好括饶,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著来涨,像睡著了一般图焰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蹦掐,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天技羔,我揣著相機與錄音,去河邊找鬼笤闯。 笑死堕阔,一個胖子當著我的面吹牛棍厂,可吹牛的內(nèi)容都是我干的颗味。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼牺弹,長吁一口氣:“原來是場噩夢啊……” “哼浦马!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起张漂,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤晶默,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后航攒,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體磺陡,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年漠畜,在試婚紗的時候發(fā)現(xiàn)自己被綠了币他。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡憔狞,死狀恐怖蝴悉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瘾敢,我是刑警寧澤拍冠,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布尿这,位于F島的核電站,受9級特大地震影響庆杜,放射性物質(zhì)發(fā)生泄漏射众。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一欣福、第九天 我趴在偏房一處隱蔽的房頂上張望责球。 院中可真熱鬧,春花似錦拓劝、人聲如沸雏逾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽栖博。三九已至,卻和暖如春厢洞,著一層夾襖步出監(jiān)牢的瞬間仇让,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留猿诸,地道東北人翁巍。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像踊淳,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子陕靠,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354