圖片ImageI/O解碼探究

最近在做ImageI/O的相關(guān)調(diào)研凭语,在使用CGImageSourceCreateImageAtIndex方法創(chuàng)建UIImage對象,和使用CGImageSourceCreateThumbnailAtIndex創(chuàng)建UIImage對象縮略圖時扑庞,引發(fā)了一系列的問題和思考探究,主要是關(guān)于ImageI/O的使用以及解碼過程。

正常情況下砚著,當(dāng)你用 UIImage 或 CGImageSource 的那幾個方法創(chuàng)建圖片時祷蝌,圖片數(shù)據(jù)并不會立刻解碼茅撞。圖片設(shè)置到 UIImageView 或者 CALayer.contents 中去,并且 CALayer 被提交到 GPU 前,CGImage 中的數(shù)據(jù)才會得到解碼米丘。這一步是發(fā)生在主線程的剑令,并且不可避免。我們可以通過下面的方法模擬圖片被解碼并渲染的過程:


- (void)drawImage:(UIImage*)image {

    size_t width = CGImageGetWidth(image.CGImage);

    size_t height = CGImageGetHeight(image.CGImage);

    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();

    CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, width * 4, colorSpaceRef, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);

    if(!context)return;

    CGColorSpaceRelease(colorSpaceRef);

    CGContextDrawImage(context,CGRectMake(0,0, width, height), image.CGImage);// decode

    CGImageRef newImageRef = CGBitmapContextCreateImage(context);

    CFRelease(context);

    CGImageRelease(newImageRef);

}

用TimeProfiler一步一步來看過程中內(nèi)部調(diào)用的函數(shù)可以幫助我們解決問題拄查,由于TimeProfiler統(tǒng)計(jì)函數(shù)棧為間隔一段時間統(tǒng)計(jì)一次吁津,導(dǎo)致沒有記錄下所有函數(shù)的調(diào)用而且每次函數(shù)棧還可能不一致,所以沒法精確判斷函數(shù)棧是如何調(diào)用的堕扶,但是可以大概推測出每步做了什么碍脏。

那么我們看下正常情況下圖片解碼時候,系統(tǒng)都是如何做的稍算。首先是PNG格式的圖片:

PNG的解碼過程

CGContextDrawImageWithOptions方法中典尾,調(diào)用了PNGPlugin庫中的一系列方法,沒有明顯看到帶有decode關(guān)鍵字的方法糊探,猜測png_read_IDAT_dataApple就是執(zhí)行的解碼過程钾埂。

接著看下JPEG格式的圖片:

JPEG的解碼過程

CGContextDrawImageWithOptions方法中,調(diào)用了AppleJPEGPlugin庫中的一系列方法科平,可以看到帶有decode關(guān)鍵字的方法FigPhotoJPEGDecodeJPEGIntoRGBSurface褥紫,這個應(yīng)該就是執(zhí)行解碼的過程。

好了匠抗,以上的實(shí)驗(yàn)知道了PNG和JPEG格式的圖片執(zhí)行解碼的關(guān)鍵方法故源,接下來正式進(jìn)入本文章的探究主題。

下面的方法是使用ImageI/O汞贸,通過獲取縮略圖的方法绳军,將圖片進(jìn)行裁剪操作,生成所需要的UIImage對象矢腻。


- (UIImage*)resizeWithData:(NSData*)data scaleSize:(CGSize)size {

    if(!data) {

        returnnil;

    }

    // Create the image source

    CGImageSourceRef imageSourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);

    if(!imageSourceRef) {

        returnnil;

    }

    CGFloatmaxPixelSize =MAX(size.width, size.height);

    // Create thumbnail options

    CFDictionaryRef options = (__bridge CFDictionaryRef) @{

                                                           (__bridgeid)kCGImageSourceShouldCacheImmediately: (__bridgeid)kCFBooleanFalse,

                                                           (__bridgeid)kCGImageSourceShouldCache: (__bridgeid)kCFBooleanFalse,

                                                           (__bridgeid)kCGImageSourceCreateThumbnailFromImageAlways: (__bridgeid)kCFBooleanTrue,

                                                           (__bridgeid)kCGImageSourceThumbnailMaxPixelSize: [NSNumbernumberWithFloat:maxPixelSize]

                                                           };

    // Generate the thumbnail

    CGImageRef imageRef = CGImageSourceCreateThumbnailAtIndex(imageSourceRef, 0, options);

    UIImage*thumbnailImage = [UIImageimageWithCGImage:imageRef];

    CFRelease(imageSourceRef);

    CGImageRelease(imageRef);

    returnthumbnailImage;

}

這里有幾個參數(shù)需要解釋一下门驾,依次如下:

kCGImageSourceShouldCacheImmediately,查看文檔解釋:


/* Specifies whether image decoding and caching should happen at image creation time.

 * The value of this key must be a CFBooleanRef. The default value is kCFBooleanFalse (image decoding will

 * happen at rendering time).

 */

翻譯過來就是說:

是否應(yīng)該在圖像創(chuàng)建過程中多柑,進(jìn)行圖像解碼和緩存奶是。 此鍵的值必須是CFBooleanRef。 默認(rèn)值為kCFBooleanFalse(圖像解碼將在渲染時發(fā)生)竣灌。

kCGImageSourceShouldCache聂沙,查看下官方文檔解釋:


/** Keys for the options dictionary of "CGImageSourceCopyPropertiesAtIndex"

 ** and "CGImageSourceCreateImageAtIndex". **/

/* Specifies whether the image should be cached in a decoded form. The

 * value of this key must be a CFBooleanRef.

 * kCFBooleanFalse indicates no caching, kCFBooleanTrue indicates caching.

 * For 64-bit architectures, the default is kCFBooleanTrue, for 32-bit the default is kCFBooleanFalse.

 */

翻譯過來就是:

在方法CGImageSourceCopyPropertiesAtIndex和CGImageSourceCreateImageAtIndex中使用

指定是否應(yīng)以解碼形式緩存圖像。 此鍵的值必須是CFBooleanRef初嘹。 kCFBooleanFalse表示沒有緩存及汉,kCFBooleanTrue表示緩存。 對于64位體系結(jié)構(gòu)屯烦,默認(rèn)值為kCFBooleanTrue坷随,對于32位房铭,默認(rèn)值為kCFBooleanFalse。

注意:此key指定的是解碼后的數(shù)據(jù)是否需要緩存温眉。此處我們設(shè)置為kCFBooleanFalse缸匪,不進(jìn)行緩存。

kCGImageSourceCreateThumbnailFromImageAlways类溢,文檔解釋:


/* Specifies whether a thumbnail should be created from the full image even

 * if a thumbnail is present in the image source file. The thumbnail will

 * be created from the full image, subject to the limit specified by

 * kCGImageSourceThumbnailMaxPixelSize---if a maximum pixel size isn't

 * specified, then the thumbnail will be the size of the full image, which

 * probably isn't what you want. The value of this key must be a

 * CFBooleanRef; the default value of this key is kCFBooleanFalse. */

翻譯過來就是:

指定是否應(yīng)從完整圖像創(chuàng)建縮略圖凌蔬,即使圖像源文件中存在縮略圖也是如此。 縮略圖將根據(jù)完整圖像創(chuàng)建豌骏,受kCGImageSourceThumbnailMaxPixelSize指定的限制---如果未指定最大像素大小龟梦,則縮略圖將是完整圖像的大小,這可能不是您想要的窃躲。 該鍵的值必須是CFBooleanRef; 此鍵的默認(rèn)值為kCFBooleanFalse。

這里我們設(shè)置為kCFBooleanTrue钦睡。

kCGImageSourceThumbnailMaxPixelSize蒂窒,官方解釋:


/* Specifies the maximum width and height in pixels of a thumbnail.  If

 * this this key is not specified, the width and height of a thumbnail is

 * not limited and thumbnails may be as big as the image itself.  If

 * present, this value of this key must be a CFNumberRef. */

翻譯如下:

指定縮略圖的最大寬度和高度(以像素為單位)。 如果未指定此鍵荞怒,則縮略圖的寬度和高度不受限制洒琢,縮略圖可能與圖像本身一樣大。 如果存在褐桌,則此鍵的此值必須為CFNumberRef衰抑。

好的,接下來荧嵌,我們看看CGImageSourceCreateThumbnailAtIndex系統(tǒng)具體做了什么呛踊。

首先我們看下PNG格式的圖片 512x384.png

同時為了測試圖片的解碼過程,我們將代碼中kCGImageSourceShouldCacheImmediately對應(yīng)的值修改為kCFBooleanTrue啦撮,也就是創(chuàng)建圖片過程中進(jìn)行解碼谭网。

根據(jù)Time Profiler我們查看下系統(tǒng)都在這個函數(shù)里面做了什么,調(diào)用結(jié)果如下:

PNG的resizeWithData

可以看到赃春,- (UIImage)resizeWithData:(NSData)data scaleSize:(CGSize)size方法執(zhí)行了48.00ms愉择,其中CGImageSourceCreateThumbnailAtIndex執(zhí)行了大約45.00ms,大部分耗時都在這里织中。我們看下里面究竟做了什么锥涕。過程中系統(tǒng)調(diào)用了CGContextDrawImageWithOptions。因?yàn)槲覀兦懊嬖O(shè)置了kCGImageSourceShouldCacheImmediately對應(yīng)的值修改為kCFBooleanTrue狭吼,也就是需要解碼层坠,所以這里系統(tǒng)調(diào)用了CGContextDrawImageWithOptions方法,會將圖片渲染到畫布搏嗡,這個過程是會解碼的窿春。那么接著往下看拉一,具體解碼的步驟在哪里【善颍可以看到接下來最耗時的操作分別在img_interpolate_extent和img_interpolate_read兩個函數(shù)蔚润。然后分別看看這兩個函數(shù)做了什么。

PNG的img_interpolate_extent

這里系統(tǒng)調(diào)用了CGImageProviderCopyImageBlockSet尺栖,里面調(diào)用了PNGPlugin庫的_cg_png_read_row和_cg_png_read_info方法嫡纠,_cg_png_read_row方法調(diào)用了png_read_IDAT_dataApple,這個方法上面已經(jīng)提到了延赌,是進(jìn)行的解碼操作除盏。

PNG的img_interpolate_read

img_interpolate_read里面調(diào)用了img_decide_read,猜測應(yīng)該是讀取解碼完成的數(shù)據(jù)挫以。

好了者蠕,PNG格式的圖片如何解碼我們大致推理出來了,那么再看看JPEG格式的圖片掐松,512x384.jpg

JPEG的resizeWithData

JPEG圖片的- (UIImage)resizeWithData:(NSData)data scaleSize:(CGSize)size方法執(zhí)行了55.00ms踱侣,其中CGImageSourceCreateThumbnailAtIndex執(zhí)行了大約53.00ms,這里系統(tǒng)同樣調(diào)用了CGContextDrawImageWithOptions方法大磺,與PNG不同的是抡句,JPEG里面調(diào)用了img_decode_stage和img_interpolate_read方法。

JPEG的img_decode_stage

可以看到img_decode_stage方法里面同樣調(diào)用了CGImageProviderCopyImageBlockSet方法杠愧,然后調(diào)用了AppleJPEGPlugin庫的FigPhotoJPEGDecodeJPEGIntoRGBSurface方法待榔,這里進(jìn)行了解碼。

JPEG的img_interpolate_read

img_interpolate_read里面調(diào)用了img_decode_read流济,跟PNG圖片的一模一樣锐锣,應(yīng)該也是對解碼完成的數(shù)據(jù)進(jìn)行讀取。

以上就是解碼過程的剖析袭灯,那么作為對比試驗(yàn)刺下,我們接下來看下不經(jīng)過解碼時的調(diào)用過程。

將kCGImageSourceShouldCacheImmediately對應(yīng)的值修改為kCFBooleanFalse稽荧,也就是創(chuàng)建圖片過程中不進(jìn)行解碼橘茉。

首先還是看下PNG格式的圖片,512x384.png

PNG

然后就震驚了R陶伞3┳俊!有沒有s瘛N膛恕!居然跟之前強(qiáng)制解碼的一模一樣<哒0萋怼渗勘!展開圖中標(biāo)出的兩個方法。

JPEG
JPEG

真的是也會解碼A┟АM埂!這究竟是為什么呢扮超?

難道是


CFDictionaryRef options = (__bridge CFDictionaryRef) @{

                                                           (__bridgeid)kCGImageSourceShouldCacheImmediately: (__bridgeid)kCFBooleanFalse,

                                                           (__bridgeid)kCGImageSourceShouldCache: (__bridgeid)kCFBooleanFalse,

                                                           (__bridgeid)kCGImageSourceCreateThumbnailFromImageAlways: (__bridgeid)kCFBooleanTrue,

                                                           (__bridgeid)kCGImageSourceThumbnailMaxPixelSize: [NSNumbernumberWithFloat:maxPixelSize]

                                                           };

這個options的問題取刃?試著嘗試使用不同的options,有了下面的結(jié)果:

情況一:


CFDictionaryRef options = (__bridge CFDictionaryRef) @{

                                                           (__bridgeid)kCGImageSourceShouldCacheImmediately: (__bridgeid)kCFBooleanFalse,

                                                           (__bridgeid)kCGImageSourceShouldCache: (__bridgeid)kCFBooleanFalse,

                                                           (__bridgeid)kCGImageSourceCreateThumbnailFromImageAlways: (__bridgeid)kCFBooleanTrue,

//                                                          (__bridge id) kCGImageSourceThumbnailMaxPixelSize : [NSNumber numberWithFloat:maxPixelSize]

                                                           };

實(shí)驗(yàn)結(jié)果如下:

情況一PNG
情況一JPEG

情況一結(jié)論:如果不設(shè)置kCGImageSourceThumbnailMaxPixelSize出刷,同時kCGImageSourceShouldCacheImmediately設(shè)置為kCFBooleanFalse璧疗,那么不管是PNG還是JPEG格式的圖片,都沒有進(jìn)行解碼操作馁龟。

情況二:


CFDictionaryRef options = (__bridge CFDictionaryRef) @{

                                                           (__bridgeid)kCGImageSourceShouldCacheImmediately: (__bridgeid)kCFBooleanTrue,

                                                           (__bridgeid)kCGImageSourceShouldCache: (__bridgeid)kCFBooleanFalse,

                                                           (__bridgeid)kCGImageSourceCreateThumbnailFromImageAlways: (__bridgeid)kCFBooleanTrue,

//                                                          (__bridge id) kCGImageSourceThumbnailMaxPixelSize : [NSNumber numberWithFloat:maxPixelSize]

                                                           };

實(shí)驗(yàn)結(jié)果如下:

情況二PNG
情況二JPEG

情況二結(jié)論:如果不設(shè)置kCGImageSourceThumbnailMaxPixelSize崩侠,同時kCGImageSourceShouldCacheImmediately設(shè)置為kCFBooleanTure,那么不管是PNG還是JPEG格式的圖片屁柏,都進(jìn)行了解碼操作啦膜。

情況三:


CFDictionaryRef options = (__bridge CFDictionaryRef) @{

                                                           (__bridgeid)kCGImageSourceShouldCacheImmediately: (__bridgeid)kCFBooleanFalse,

                                                           (__bridgeid)kCGImageSourceShouldCache: (__bridgeid)kCFBooleanFalse,

                                                           (__bridgeid)kCGImageSourceCreateThumbnailFromImageAlways: (__bridgeid)kCFBooleanTrue,

                                                           (__bridgeid)kCGImageSourceThumbnailMaxPixelSize: [NSNumbernumberWithFloat:maxPixelSize]

                                                           };

實(shí)驗(yàn)結(jié)果如下:

情況三PNG
情況三JPEG

情況三結(jié)論:如果設(shè)置了kCGImageSourceThumbnailMaxPixelSize,同時kCGImageSourceShouldCacheImmediately設(shè)置為kCFBooleanFalse淌喻,那么不管是PNG還是JPEG格式的圖片,都進(jìn)行了解碼操作雀摘。

情況四:


CFDictionaryRef options = (__bridge CFDictionaryRef) @{

                                                           (__bridgeid)kCGImageSourceShouldCacheImmediately: (__bridgeid)kCFBooleanTrue,

                                                           (__bridgeid)kCGImageSourceShouldCache: (__bridgeid)kCFBooleanFalse,

                                                           (__bridgeid)kCGImageSourceCreateThumbnailFromImageAlways: (__bridgeid)kCFBooleanTrue,

                                                           (__bridgeid)kCGImageSourceThumbnailMaxPixelSize: [NSNumbernumberWithFloat:maxPixelSize]

                                                           };

實(shí)驗(yàn)結(jié)果如下:

情況四PNG
情況四JPEG

情況四結(jié)論:如果設(shè)置了kCGImageSourceThumbnailMaxPixelSize裸删,同時kCGImageSourceShouldCacheImmediately設(shè)置為kCFBooleanTure,那么不管是PNG還是JPEG格式的圖片阵赠,也都進(jìn)行了解碼操作涯塔。

總結(jié):

1、在使用CGImageSourceCreateThumbnailAtIndex方法時清蚀,如果設(shè)置了kCGImageSourceThumbnailMaxPixelSize匕荸,那么肯定會進(jìn)行解碼操作,生成對應(yīng)的新圖CGImageRef枷邪。

2榛搔、如果不設(shè)置kCGImageSourceThumbnailMaxPixelSize,那么是否進(jìn)行解碼操作东揣,取決于kCGImageSourceShouldCacheImmediately對應(yīng)的值是kCFBooleanTure還是kCFBooleanFalse践惑。

ImageI/O中使用CGImageSourceCreateThumbnailAtIndex創(chuàng)建縮略圖方法的結(jié)論就是如上所述。那么這里又有另一個思考嘶卧,如果是CGImageSourceCreateImageAtIndex方法尔觉,那么上述的kCGImageSourceShouldCacheImmediately鍵值對會造成什么影響呢?


- (UIImage*)resizeWithData:(NSData*)data scaleSize:(CGSize)size {

    if(!data) {

        returnnil;

    }

    // Create the image source

    CGImageSourceRef imageSourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);

    if(!imageSourceRef) {

        returnnil;

    }

    // Create thumbnail options

    CFDictionaryRef options = (__bridge CFDictionaryRef) @{

                                                           (__bridgeid)kCGImageSourceShouldCacheImmediately: (__bridgeid)kCFBooleanFalse,

                                                           (__bridgeid)kCGImageSourceShouldCache: (__bridgeid)kCFBooleanFalse

                                                           };

    // Generate the thumbnail

    NSLog(@"%@", options);

    CGImageRefimageRef =

    CGImageSourceCreateImageAtIndex(imageSourceRef,0, options);

    UIImage*thumbnailImage = [UIImageimageWithCGImage:imageRef];

    CFRelease(imageSourceRef);

    CGImageRelease(imageRef);

    returnthumbnailImage;

}

情況一:


CFDictionaryRef options = (__bridge CFDictionaryRef) @{

                                                           (__bridgeid)kCGImageSourceShouldCacheImmediately: (__bridgeid)kCFBooleanFalse,

                                                           (__bridgeid)kCGImageSourceShouldCache: (__bridgeid)kCFBooleanFalse

                                                           };

實(shí)驗(yàn)如下:

CGImageSourceCreateImageAtIndex不解碼_PNG
CGImageSourceCreateImageAtIndex不解碼_JPEG

情況一結(jié)論:設(shè)置kCGImageSourceShouldCacheImmediately為kCFBooleanFalse時芥吟,PNG和JPEG都沒有進(jìn)行解碼侦铜。

情況二:


CFDictionaryRef options = (__bridge CFDictionaryRef) @{

                                                           (__bridgeid)kCGImageSourceShouldCacheImmediately: (__bridgeid)kCFBooleanTrue,

                                                           (__bridgeid)kCGImageSourceShouldCache: (__bridgeid)kCFBooleanFalse

                                                           };

實(shí)驗(yàn)如下:

CGImageSourceCreateImageAtIndex解碼_PNG
CGImageSourceCreateImageAtIndex解碼_JPEG

情況二結(jié)論:設(shè)置kCGImageSourceShouldCacheImmediately為kCFBooleanTrue時专甩,PNG和JPEG都進(jìn)行了解碼。

總結(jié):在使用CGImageSourceCreateImageAtIndex方法創(chuàng)建CGImageRef時钉稍,kCGImageSourceShouldCacheImmediately值會影響是否開啟解碼操作涤躲。ImageI/O默認(rèn)的kCGImageSourceShouldCacheImmediately為kCFBooleanFalse,也就是說創(chuàng)建圖片時候不解碼嫁盲,會等到圖片被渲染的時候才進(jìn)行解碼篓叶。

以上部分就明確了CGImageSourceCreateImageAtIndex和CGImageSourceCreateThumbnailAtIndex時系統(tǒng)底層具體的實(shí)現(xiàn)。

當(dāng)然羞秤,在使用這個- (UIImage*)resizeWithData:(NSData*)data scaleSize:(CGSize)size方法時候也采坑了缸托。因?yàn)橐话愦蟛糠智闆r下(參考圖片縮放使用UIKIt、Core Graphics瘾蛋、Core Foundation等情況下的方法)俐镐,是為UIImage添加一個分類,使用分類方法進(jìn)行縮放哺哼。那么既然如此佩抹,為什么不同樣使用分類呢?嗯取董,不錯的想法棍苹,筆者剛開始是這樣做的:


- (UIImage*)resizeWithImage:(UIImage*)image scaleSize:(CGSize)size {

    CFDataRef bitmapData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));

    // Create the image source

    CGImageSourceRef imageSourceRef = CGImageSourceCreateWithData(bitmapData, NULL);

    if(!imageSourceRef) {

        returnnil;

    }

    CGFloatmaxPixelSize =MAX(size.width, size.height);

    // Create thumbnail options

    CFDictionaryRef options = (__bridge CFDictionaryRef) @{

                                                                                                                      (__bridgeid)kCGImageSourceShouldCache: (__bridgeid)kCFBooleanFalse,

                                                           (__bridgeid)kCGImageSourceCreateThumbnailFromImageAlways: (__bridgeid)kCFBooleanTrue,

                                                           (__bridgeid)kCGImageSourceThumbnailMaxPixelSize: [NSNumbernumberWithFloat:maxPixelSize]

                                                           };

    // Generate the thumbnail

    CGImageRef imageRef = CGImageSourceCreateThumbnailAtIndex(imageSourceRef, 0, options);

    UIImage*thumbnailImage = [UIImageimageWithCGImage:imageRef];

    CFRelease(imageSourceRef);

    CGImageRelease(imageRef);

    returnthumbnailImage;

}

干凈漂亮,直接跑起來茵汰,美滋滋枢里。

但是!u逦纭栏豺!結(jié)果返回的圖片為nil。

為什么豆胸?百思不得其解奥洼,詳細(xì)了解了下CGDataProvider的一系列API,CGimage的dataProvider晚胡,指的是CGImageCreate時候灵奖,傳入的承載了Bitmap Buffer數(shù)組的一個提供者,可以是一個內(nèi)存中的buffer搬泥,也可以是一個callback來實(shí)現(xiàn)惰性解碼桑寨。也就是說,這個傳入的Bitmap Buffer數(shù)組忿檩,必須是未經(jīng)過解壓縮的數(shù)據(jù)尉尾。如果是經(jīng)過了解壓縮的圖片數(shù)據(jù),那么傳給ImageI/0是沒有意義的燥透。

問題真的出在這里嗎沙咏?這兩個方法參數(shù)不同之處是辨图,一個是使用UIImage *image = [UIImage imageWithContentsOfFile:path],傳入UIImage對象肢藐,而另一個是通過NSData *data = [NSData dataWithContentsOfFile:path]故河,傳入的NSData對象。

那么這兩個方法本質(zhì)的區(qū)別到底是什么呢吆豹?為什么造成不同的結(jié)局呢鱼的?系統(tǒng)在這兩個方法里面具體都干了什么呢?

首先痘煤,拿JPEG格式的做實(shí)驗(yàn)凑阶,看看[UIImage imageWithContentsOfFile:]都做了什么。

JPEG的imageWithContentsOfFile

可以看到衷快,在該方法中系統(tǒng)調(diào)用了CGImageSourceCreateImageAtIndex方法宙橱,在該方法中,系統(tǒng)使用了AppleJPEGPlugin庫的一些方法,但是并沒有發(fā)現(xiàn)decode相關(guān)的函數(shù),所以這里應(yīng)該沒有進(jìn)行解碼祝辣,而只是將圖片進(jìn)行了解壓縮(decompress)。這也就解釋了為什么使用CGImageGetDataProvider獲取的CGDataProvider對象是無效的了瘪松。

那么同時可以看下PNG格式的圖片,在使用[UIImage imageWithContentsOfFile:]時系統(tǒng)都做了什么。

PNG的imageWithContentsOfFile

PNG格式的圖片,同樣是調(diào)用CGImageSourceCreateImageAtIndex等方法猬仁,同時可以看到使用的是PNGPlugin庫相關(guān)的方法,PNGReadPlugin讀取文件數(shù)據(jù)進(jìn)行解壓縮先誉。

有興趣的同學(xué)可以看下[UIImage imageWithNamed:]方法創(chuàng)建的UIImage對象,至于[UIImage imageWithNamed:]和[UIImage imageWithContentsOfFile:]的具體區(qū)別的烁,會另起一篇文章進(jìn)行分析褐耳。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市渴庆,隨后出現(xiàn)的幾起案子铃芦,更是在濱河造成了極大的恐慌,老刑警劉巖襟雷,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刃滓,死亡現(xiàn)場離奇詭異,居然都是意外死亡耸弄,警方通過查閱死者的電腦和手機(jī)咧虎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來计呈,“玉大人砰诵,你說我怎么就攤上這事征唬。” “怎么了茁彭?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵总寒,是天一觀的道長。 經(jīng)常有香客問我理肺,道長摄闸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任妹萨,我火速辦了婚禮年枕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘眠副。我一直安慰自己画切,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布囱怕。 她就那樣靜靜地躺著霍弹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪娃弓。 梳的紋絲不亂的頭發(fā)上典格,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天,我揣著相機(jī)與錄音台丛,去河邊找鬼耍缴。 笑死,一個胖子當(dāng)著我的面吹牛挽霉,可吹牛的內(nèi)容都是我干的防嗡。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼侠坎,長吁一口氣:“原來是場噩夢啊……” “哼蚁趁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起实胸,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤他嫡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后庐完,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钢属,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年门躯,在試婚紗的時候發(fā)現(xiàn)自己被綠了淆党。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖宁否,靈堂內(nèi)的尸體忽然破棺而出窒升,到底是詐尸還是另有隱情,我是刑警寧澤慕匠,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布饱须,位于F島的核電站,受9級特大地震影響台谊,放射性物質(zhì)發(fā)生泄漏蓉媳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一锅铅、第九天 我趴在偏房一處隱蔽的房頂上張望酪呻。 院中可真熱鬧,春花似錦盐须、人聲如沸玩荠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽阶冈。三九已至,卻和暖如春塑径,著一層夾襖步出監(jiān)牢的瞬間女坑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工统舀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留匆骗,地道東北人。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓誉简,卻偏偏與公主長得像碉就,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子闷串,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內(nèi)容