【IOS開發(fā)基礎(chǔ)系列】UIImage/UIImageView專題

1 UIImage知識點(diǎn)

iOS開發(fā)中關(guān)于UIImage的知識點(diǎn)總結(jié)

http://mobile.51cto.com/hot-442118.htm

????????UIImage是iOS中層級比較高的一個(gè)用來加載和繪制圖像的一個(gè)類檩淋,更底層的類還有 CGImage芬为,以及iOS5.0以后新增加的CIImage萄金。今天我們主要聊一聊UIImage的三個(gè)屬性: imageOrientation, size, scale,幾個(gè)初始化的方法: imageNamed媚朦,imageWithContentsOfFile氧敢,以及繪制Image的幾個(gè)draw開頭的方法。

????????UIImage是iOS中層級比較高的一個(gè)用來加載和繪制圖像的一個(gè)類询张,更底層的類還有 CGImage孙乖,以及iOS5.0以后新增加的CIImage。今天我們主要聊一聊UIImage的三個(gè)屬性: imageOrientation, size, scale份氧,幾個(gè)初始化的方法: imageNamed唯袄,imageWithContentsOfFile,以及繪制Image的幾個(gè)draw開頭的方法蜗帜。

1.1 UIImage的size恋拷,scale屬性

????????先想一個(gè)問題“一個(gè)圖像的尺寸到底是多大呢?”

????????第一反應(yīng)可能就是image.size钮糖,恭喜你答錯(cuò)了梅掠,正確的答案是圖像的實(shí)際的尺寸(像 素)等于image.size乘以image.scale。如果做過界面貼圖的話你可能經(jīng)常會(huì)需要準(zhǔn)備至少兩套圖店归,一套1倍圖阎抒,一套圖已@2x命名的二倍 圖。這樣當(dāng)我們的程序運(yùn)行在retina屏幕的時(shí)候系統(tǒng)就會(huì)自動(dòng)的去加載@2x的圖片消痛,它的size將和一倍圖加載進(jìn)來的size相等且叁,但是scale卻 置為2,這點(diǎn)大家可以做個(gè)簡單的小測試驗(yàn)證一下秩伞。然我們再深入一點(diǎn)兒為什么不直接加載到成二倍的尺寸呢逞带,原因很簡單因?yàn)槲覀冊诮缑娌季种羞壿嬜鴺?biāo)系中的 (單位是point),而實(shí)際的繪制都是在設(shè)備坐標(biāo)系(單位是pixel)進(jìn)行的纱新,系統(tǒng)會(huì)自動(dòng)幫我們完成從point到pixel之間的轉(zhuǎn)化展氓。其實(shí)這個(gè)比 例也就剛好和UIScreen中的scale對應(yīng),這樣整條scale的線就可以串通了脸爱。

1.2 UIImage的幾種初始化方法的對比

1遇汞、imageNamed:方法

????????imageNamed:是UIImage的一個(gè)類方法,它做的事情比我們看到的要稍微多一些簿废。它的加載流程如下:

????a. 系統(tǒng)回去檢查系統(tǒng)緩存中是否存在該名字的圖像空入,如果存在則直接返回。

????b. 如果系統(tǒng)緩存中不存在該名字的圖像族檬,則會(huì)先加載到緩存中歪赢,在返回該對象。

????????觀察上面的操作我們發(fā)現(xiàn)系統(tǒng)會(huì)緩存我們使用imageNamed:方法加載的圖像時(shí)候单料,系統(tǒng)會(huì)自動(dòng)幫我們緩存埋凯。這種機(jī)制適合于那種頻繁用到界面貼圖累的加載点楼,但如果我們需要短時(shí)間內(nèi)頻繁的加載一些一次性的圖像的話,最好不要使用這種方法递鹉。

2盟步、imageWithContentsOfFile:initWithContentsOfFile:方法

????????這兩個(gè)方法跟前一個(gè)方法一樣都是完成從文件加載圖像的功能。但是不會(huì)經(jīng)過系統(tǒng)緩存躏结,直接從文件系統(tǒng)中加載并返回却盘。

????????順便提一下,當(dāng)收到內(nèi)存警告的時(shí)候媳拴,系統(tǒng)可能會(huì)將UIImage內(nèi)部的存儲圖像的內(nèi)存釋放黄橘,下一次需要繪制的時(shí)候會(huì)重新去加載。

3屈溉、imageWithCGImage:scale:orientation:方法

????????該方面使用一個(gè)CGImageRef創(chuàng)建UIImage塞关,在創(chuàng)建時(shí)還可以指定方法倍數(shù)以及旋轉(zhuǎn)方向。當(dāng)scale設(shè)置為1的時(shí)候子巾,新創(chuàng)建的圖像將和原圖像尺寸一摸一樣帆赢,而orientaion則可以指定新的圖像的繪制方向。

1.3 UIImage的imageOrientation屬性

????????UIImage有一個(gè)imageOrientation的屬性线梗,主要作用是控制image的繪制方向椰于,共有以下8中方向:

typedef?NS_ENUM(NSInteger,?UIImageOrientation)?{

????UIImageOrientationUp,????????????//?default?orientation??

????UIImageOrientationDown,??????????//?180?deg?rotation ??????

????UIImageOrientationLeft,??????????//?90?deg?CCW(編程發(fā)現(xiàn)官方文檔中,left和right圖像標(biāo)反了仪搔,此處更正過來)

????UIImageOrientationRight,?????????//?90?deg?CW???

????UIImageOrientationUpMirrored,????//?as?above?but?image?mirrored?along?other?axis.?horizontal?flip??

????UIImageOrientationDownMirrored,??//?horizontal?flip

????UIImageOrientationLeftMirrored,??//?vertical?flip

????UIImageOrientationRightMirrored,?//?vertical?flip

};

????????默認(rèn)的方向是UIImageOrientationUp瘾婿,這8種方向?qū)?yīng)的繪制方如上面所示。我 們在日常使用中經(jīng)常會(huì)碰到把iPhone相冊中的照片導(dǎo)入到windows中烤咧,發(fā)現(xiàn)方向不對的問題就是與這個(gè)屬性有關(guān)偏陪,因?yàn)閷?dǎo)出照片的時(shí)候,寫exif中 的方向信息時(shí)候沒有考慮該方向的原因煮嫌。既然這個(gè)屬性可以控制image的繪制方向笛谦,那我們能不能通過改過這個(gè)屬性來完成UIImage的旋轉(zhuǎn)和翻轉(zhuǎn)呢?帶 著這個(gè)問題我們繼續(xù)往下看昌阿。

1.4 UIImage的幾個(gè)draw方法

????????UIImage的幾個(gè)draw方法是用來繪制圖像的利器饥脑,為什么這樣說呢?因?yàn)樗鼈冊诶L制圖 像的時(shí)候會(huì)考慮當(dāng)前圖像的方向宝泵,即根據(jù)的imageOrientation繪制出不同的方向好啰。由于圖像是繪制在當(dāng)前context中的轩娶,它同時(shí)還會(huì)考慮到 當(dāng)前context的transform的變化儿奶。利于這兩點(diǎn)我們就可以玩轉(zhuǎn)圖像的旋轉(zhuǎn)和翻轉(zhuǎn)了。

????????搜索了一下鳄抒,目前網(wǎng)上大部分圖像旋轉(zhuǎn)都是通過創(chuàng)建CGBitmapContext闯捎,然后根據(jù)圖像方向設(shè)置context的transform來實(shí)現(xiàn)的椰弊,這種方法要求對整個(gè)矩陣變化的過程都非常清楚,一個(gè)參數(shù)設(shè)置不多瓤鼻,出來的結(jié)果就會(huì)有問題秉版。

????????下面我介紹一種實(shí)現(xiàn)起來簡單方便的圖像旋轉(zhuǎn)方法,這種方法主要就是利用imageWithCGImage:scale:orientation:方法茬祷,指定不同的orientation來完成所需要的功能清焕,先舉個(gè)簡單的例子:

????????假設(shè)一副圖片顯示為?,我們要向左旋轉(zhuǎn)90°祭犯,那么轉(zhuǎn)過之后應(yīng)該就會(huì)顯示為秸妥,即將原圖從orientationUP轉(zhuǎn)到orientationLeft即可。以此類推為不同的方向旋轉(zhuǎn)沃粗,只需要注意看R的顯示即可粥惧,這樣整個(gè)旋轉(zhuǎn)和翻轉(zhuǎn)的實(shí)現(xiàn)過程中完全可以不用考慮Transform那些東西,是不是很簡單最盅。

????????下面是圖像旋轉(zhuǎn)和翻轉(zhuǎn)的完整代碼:

//

//??UIImage+Rotate_Flip.h

//??SvImageEdit

//

#import <UIKit/UIKit.h>

@interface?UIImage?(Rotate_Flip)

/*

*?@brief?rotate?image?90?withClockWise

*/

-?(UIImage*)rotate90Clockwise;

/*

*?@brief?rotate?image?90?counterClockwise

*/

-?(UIImage*)rotate90CounterClockwise;

/*

*?@brief?rotate?image?180?degree

*/

-?(UIImage*)rotate180;

/*

*?@brief?rotate?image?to?default?orientation

*/

-?(UIImage*)rotateImageToOrientationUp;

/*

*?@brief?flip?horizontal

*/

-?(UIImage*)flipHorizontal;

/*

*?@brief?flip?vertical

*/

-?(UIImage*)flipVertical;

/*

*?@brief?flip?horizontal?and?vertical

*/

-?(UIImage*)flipAll;

@end

UIImage+Rotate_Flip.h

//

//??UIImage+Rotate_Flip.m

//??SvImageEdit

//

//??Created?by??maple?on?5/14/13.

//??Copyright?(c)?2013?smileEvday.?All?rights?reserved.

//

#import?"UIImage+Rotate_Flip.h"

@implementation?UIImage?(Rotate_Flip)

/*

*?@brief?rotate?image?90?with?CounterClockWise

*/

-?(UIImage*)rotate90CounterClockwise

{

????UIImage?*image?=?nil;

????switch?(self.imageOrientation)?{

????????case?UIImageOrientationUp:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage scale: 1?orientation: UIImageOrientationLeft];

????????????break;

????????}

????????case?UIImageOrientationDown:

????????{????

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationRight];

????????????break;

????????}

????????case?UIImageOrientationLeft:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationDown];

????????????break;

????????}

????????case?UIImageOrientationRight:?

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationUp];

????????????break;

????????}

????????case?UIImageOrientationUpMirrored:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationRightMirrored];

????????????break;

????????}

????????case?UIImageOrientationDownMirrored:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationLeftMirrored];

????????????break;

????????}

????????case?UIImageOrientationLeftMirrored:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationUpMirrored];

????????????break;

????????}

????????case?UIImageOrientationRightMirrored:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationDownMirrored];

????????????break;

????????}

????????default:

????????????break;

????}

????return?image;

}

/*

*?@brief?rotate?image?90?with?Clockwise

*/

-?(UIImage*)rotate90Clockwise

{

????UIImage?*image?=?nil;

????switch?(self.imageOrientation)?{

????????case?UIImageOrientationUp:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationRight];

????????????break;

????????}

????????case?UIImageOrientationDown:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationLeft];

????????????break;

????????}

????????case?UIImageOrientationLeft:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationUp];

????????????break;

????????}

????????case?UIImageOrientationRight:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationDown];

????????????break;

????????}

????????case?UIImageOrientationUpMirrored:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationLeftMirrored];

????????????break;

????????}

????????case?UIImageOrientationDownMirrored:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationRightMirrored];

????????????break;

????????}

????????case?UIImageOrientationLeftMirrored:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationDownMirrored];

????????????break;

????????}

????????case?UIImageOrientationRightMirrored:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationUpMirrored];

????????????break;

????????}

????????default:

????????????break;

????}

????return?image;

}

/*

*?@brief?rotate?image?180?degree

*/

-?(UIImage*)rotate180

{

????UIImage?*image?=?nil;

????switch?(self.imageOrientation)?{

????????case?UIImageOrientationUp:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationDown];

????????????break;

????????}

????????case?UIImageOrientationDown:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationUp];

????????????break;

????????}

????????case?UIImageOrientationLeft:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationRight];

????????????break;

????????}

????????case?UIImageOrientationRight:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationLeft];

????????????break;

????????}

????????case?UIImageOrientationUpMirrored:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationDownMirrored];

????????????break;

????????}

????????case?UIImageOrientationDownMirrored:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationUpMirrored];

????????????break;

????????}

????????case?UIImageOrientationLeftMirrored:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationRightMirrored];

????????????break;

????????}

????????case?UIImageOrientationRightMirrored:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationLeftMirrored];

????????????break;

????????}

????????default:

????????????break;

????}

????return?image;

}

/*

*?@brief?rotate?image?to?default?orientation

*/

-?(UIImage*)rotateImageToOrientationUp

{

????CGSize?size?=?CGSizeMake(self.size.width?*?self.scale,?self.size.height?*?self.scale);

????UIGraphicsBeginImageContext(size);

????CGContextRef?context?=?UIGraphicsGetCurrentContext();

????CGContextClearRect(context,?CGRectMake(0,?0,?size.width,?size.height));

????[self?drawInRect: CGRectMake(0,?0,?size.width,?size.height)];

????UIImage?*image?=?UIGraphicsGetImageFromCurrentImageContext();

????UIGraphicsEndImageContext();

????return?image;

}

/*

*?@brief?flip?horizontal

*/

-?(UIImage*)flipHorizontal

{

????UIImage?*image?=?nil;

????switch?(self.imageOrientation)?{

????????case?UIImageOrientationUp:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationUpMirrored];

????????????break;

????????}

????????case?UIImageOrientationDown:

????????{????

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationDownMirrored];

????????????break;

????????}

????????case?UIImageOrientationLeft:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationRightMirrored];

????????????break;

????????}

????????case?UIImageOrientationRight:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationLeftMirrored];

????????????break;

????????}

????????case?UIImageOrientationUpMirrored:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationUp];

????????????break;

????????}

????????case?UIImageOrientationDownMirrored:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationDown];

????????????break;

????????}

????????case?UIImageOrientationLeftMirrored:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationRight];

????????????break;

????????}

????????case?UIImageOrientationRightMirrored:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationLeft];

????????????break;

????????}

????????default:

????????????break;

????}

????return?image;

}

/*

*?@brief?flip?vertical

*/

-?(UIImage*)flipVertical

{

????UIImage?*image?=?nil;

????switch(self.imageOrientation)?{

????????case?UIImageOrientationUp:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationDownMirrored];

????????????break;

????????}

????????case?UIImageOrientationDown:

????????{????

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationUpMirrored];

????????????break;

????????}

????????case?UIImageOrientationLeft:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationLeftMirrored];

????????????break;

????????}

????????case?UIImageOrientationRight:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationRightMirrored];

????????????break;

????????}

????????case?UIImageOrientationUpMirrored:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationDown];

????????????break;

????????}

????????case?UIImageOrientationDownMirrored:

????????{?

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationUp];

????????????break;

????????}

????????case?UIImageOrientationLeftMirrored:

????????{

????????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale:1? orientation: UIImageOrientationLeft];

????????????break;

????????}

????????case?UIImageOrientationRightMirrored:

????????{

???????????image?=?[UIImage?imageWithCGImage: self.CGImage?scale: 1?orientation: UIImageOrientationRight];

????????????break;

????????}

????????default:

????????????break;

????}

????return?image;

}

/*

*?@brief?flip?horizontal?and?vertical

*/

-?(UIImage*)flipAll

{

????return?[self?rotate180];

}

@end

UIImage+Rotate_Flip.m

????????以上只是實(shí)現(xiàn)了圖像的順時(shí)針90°突雪,逆時(shí)針90°,180°旋轉(zhuǎn)涡贱,以及水平翻轉(zhuǎn)咏删,數(shù)值翻轉(zhuǎn)等。至于任意角度旋轉(zhuǎn)怎么實(shí)現(xiàn)盼产?其實(shí)也很簡單饵婆,留著給大家思考吧。雖然我們可以通過orientation這種方法簡單的完成圖像旋轉(zhuǎn)戏售,但是如果有時(shí)間的話還是 建議大家盡量的看一下那種通過transform來完成旋轉(zhuǎn)的代碼侨核,你會(huì)徹底搞清楚旋轉(zhuǎn)矩陣是怎么回事兒。當(dāng)然程序中使用的時(shí)候推薦使用我上面提供的這種 方法灌灾,因?yàn)椴簧婕罢鎸?shí)的旋轉(zhuǎn)操作搓译,速度會(huì)快很多。

????????通過上面的小例子锋喜,我們可以看出越高級別的API幫助我們做的事情就越多些己,越底層的API提 供了更多的靈活性,但同時(shí)也帶來了很多需要我們處理的東西嘿般。再編程的過程中盡量的使用高級別的API段标,同時(shí)最好能搞懂底層的實(shí)現(xiàn)機(jī)制。這樣我們的程序才會(huì) 更高效炉奴,出了問題才知道去哪里查找逼庞。


1.5 圖片處理小技巧

摘抄鏈接:iOS處理圖片的一些小Tip

http://blog.ibireme.com/2015/11/02/ios_image_tips/

1.5.1 如何把GIF動(dòng)圖保存到相冊?

????????iOS的相冊是支持保存GIF和APNG動(dòng)圖的瞻赶,只是不能直接播放赛糟。用[ALAssetsLibrary writeImageDataToSavedPhotosAlbum: metadata: completionBlock]可以直接把APNG派任、GIF的數(shù)據(jù)寫入相冊。如果圖省事直接用UIImageWriteToSavedPhotosAlbum()寫相冊璧南,那么圖像會(huì)被強(qiáng)制轉(zhuǎn)碼為PNG掌逛。

1.5.2 將UIImage保存到磁盤,用什么方式最好司倚?

????????目前來說豆混,保存UIImage有三種方式:

????1.直接用NSKeyedArchiver把UIImage序列化保存;

????2.用UIImagePNGRepresentation()先把圖片轉(zhuǎn)為PNG保存动知;

????3.用UIImageJPEGRepresentation()把圖片壓縮成JPEG保存崖叫。

????????實(shí)際上,NSKeyedArchiver是調(diào)用了UIImagePNGRepresentation進(jìn)行序列化的拍柒,用它來保存圖片是消耗最大的心傀。蘋果對JPEG有硬編碼和硬解碼,保存成JPEG會(huì)大大縮減編碼解碼時(shí)間拆讯,也能減小文件體積脂男。所以如果圖片不包含透明像素時(shí),UIImageJPEGRepresentation(0.9)是最佳的圖片保存方式种呐,其次是UIImagePNGRepresentation()宰翅。

1.5.3 UIImage緩存是怎么回事?

????????通過imageNamed創(chuàng)建UIImage時(shí)爽室,系統(tǒng)實(shí)際上只是在Bundle內(nèi)查找到文件名汁讼,然后把這個(gè)文件名放到UIImage里返回,并沒有進(jìn)行實(shí)際的文件讀取和解碼阔墩。當(dāng)UIImage第一次顯示到屏幕上時(shí)嘿架,其內(nèi)部的解碼方法才會(huì)被調(diào)用,同時(shí)解碼結(jié)果會(huì)保存到一個(gè)全局緩存去啸箫。據(jù)我觀察嘲碱,在圖片解碼后羹应,App第一次退到后臺和收到內(nèi)存警告時(shí)怯邪,該圖片的緩存才會(huì)被清空缔莲,其他情況下緩存會(huì)一直存在。

1.5.4 我要是用imageWithData能不能避免緩存呢扎唾?

????????不能召川。通過數(shù)據(jù)創(chuàng)建UIImage時(shí),UIImage底層是調(diào)用ImageIO的CGImageSourceCreateWithData()方法胸遇。該方法有個(gè)參數(shù)叫ShouldCache荧呐,在64位的設(shè)備上,這個(gè)參數(shù)是默認(rèn)開啟的。這個(gè)圖片也是同樣在第一次顯示到屏幕時(shí)才會(huì)被解碼坛增,隨后解碼數(shù)據(jù)被緩存到CGImage內(nèi)部。與imageNamed創(chuàng)建的圖片不同薄腻,如果這個(gè)圖片被釋放掉收捣,其內(nèi)部的解碼數(shù)據(jù)也會(huì)被立刻釋放。

1.5.5 怎么能避免緩存呢庵楷?

????1.手動(dòng)調(diào)用CGImageSourceCreateWithData()來創(chuàng)建圖片罢艾,并把ShouldCache和ShouldCacheImmediately關(guān)掉。這么做會(huì)導(dǎo)致每次圖片顯示到屏幕時(shí)尽纽,解碼方法都會(huì)被調(diào)用咐蚯,造成很大的CPU占用。

????2.把圖片用CGContextDrawImage()繪制到畫布上弄贿,然后把畫布的數(shù)據(jù)取出來當(dāng)作圖片春锋。這也是常見的網(wǎng)絡(luò)圖片庫的做法。

1.5.6 我能直接取到圖片解碼后的數(shù)據(jù)差凹,而不是通過畫布取到嗎期奔?

????1.CGImageSourceCreateWithData(data)創(chuàng)建ImageSource。

????2.CGImageSourceCreateImageAtIndex(source)創(chuàng)建一個(gè)未解碼的CGImage危尿。

????3.CGImageGetDataProvider(image)獲取這個(gè)圖片的數(shù)據(jù)源呐萌。

????4.CGDataProviderCopyData(provider)從數(shù)據(jù)源獲取直接解碼的數(shù)據(jù)。

????????ImageIO解碼發(fā)生在最后一步谊娇,這樣獲得的數(shù)據(jù)是沒有經(jīng)過顏色類型轉(zhuǎn)換的原生數(shù)據(jù)(比如灰度圖像)肺孤。

1.5.7 如何判斷一個(gè)文件的圖片類型?

????????通過讀取文件或數(shù)據(jù)的頭幾個(gè)字節(jié)然后和對應(yīng)圖片格式標(biāo)準(zhǔn)進(jìn)行比對济欢。我在這里寫了一個(gè)簡單的函數(shù)赠堵,能很快速的判斷圖片格式。

1.5.8 怎樣像瀏覽器那樣邊下載邊顯示圖片法褥?

????????首先顾腊,圖片本身有3種常見的編碼方式:

????第一種是baseline,即逐行掃描挖胃。默認(rèn)情況下杂靶,JPEG、PNG酱鸭、GIF都是這種保存方式吗垮。

????第二種是interlaced,即隔行掃描凹髓。PNG和GIF在保存時(shí)可以選擇這種格式烁登。

????第三種是progressive,即漸進(jìn)式。JPEG在保存時(shí)可以選擇這種方式饵沧。

????????在下載圖片時(shí)锨络,首先用CGImageSourceCreateIncremental(NULL)創(chuàng)建一個(gè)空的圖片源,隨后在獲得新數(shù)據(jù)時(shí)調(diào)用CGImageSourceUpdateData(data, false)來更新圖片源狼牺,最后在用CGImageSourceCreateImageAtIndex()創(chuàng)建圖片來顯示羡儿。

????????你可以用PINRemoteImage或者我寫的 YYWebImage來實(shí)現(xiàn)這個(gè)效果。SDWebImage并沒有用Incremental方式解碼是钥,所以顯示效果很差掠归。


2 開發(fā)技巧

2.1 圖片縮放

圖片縮放的三個(gè)函數(shù)

http://www.cnblogs.com/pengyingh/articles/2355052.html

????????程序中一個(gè)界面用到了好多張大圖,內(nèi)存報(bào)警告了悄泥,所以做了一下圖片縮放虏冻,在網(wǎng)上找了別人寫的代碼

//把圖片做等比縮放,生成一個(gè)新圖片

- (UIImage*) imageByScalingProportionallyToSize:(CGSize)targetSize sourceImage:(UIImage*)sourceImage {

? ? UIGraphicsBeginImageContext(targetSize);

????[sourceImage drawInRect: CGRectMake(0, 0, targetSize.width, targetSize.height)];

????UIImage* scaledImage =UIGraphicsGetImageFromCurrentImageContext();

????UIGraphicsEndImageContext();

????return scaledImage;


????UIImage *newImage = nil;

????CGSize imageSize = sourceImage.size;

????CGFloat width = imageSize.width;

????CGFloat height = imageSize.height;

????CGFloat targetWidth = targetSize.width;

????CGFloat targetHeight = targetSize.height;

????CGFloat scaleFactor =0.0;

????CGFloat scaledWidth = targetWidth;

????CGFloat scaledHeight = targetHeight;

????CGPoint thumbnailPoint = CGPointMake(0.0,0.0);


????UIGraphicsBeginImageContext(targetSize);// this will crop

????CGRect thumbnailRect = CGRectZero;

????thumbnailRect.origin = thumbnailPoint;

????thumbnailRect.size.width? = scaledWidth;

????thumbnailRect.size.height = scaledHeight;

????[sourceImage drawInRect: thumbnailRect];


????newImage = UIGraphicsGetImageFromCurrentImageContext();

????if(newImage== nil)

????????NSLog(@"could not scale image");


????//pop the context to get back to the default

????UIGraphicsEndImageContext();

????return newImage;

}

//把圖片按照新大小進(jìn)行裁剪弹囚,生成一個(gè)新圖片

- (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize image:(UIImage? *) sourceImage

{

? ? ?//???UIImage *sourceImage = self;

? ? ?UIImage *newImage = nil;

? ? ?CGSize imageSize = sourceImage.size;

? ? ?CGFloat width = imageSize.width;

? ? ?CGFloat height = imageSize.height;

? ? ?CGFloat targetWidth = targetSize.width;

? ? ?CGFloat targetHeight = targetSize.height;

? ? ?CGFloat scaleFactor =0.0;

? ? ?CGFloat scaledWidth = targetWidth;

? ? ?CGFloat scaledHeight = targetHeight;

? ? ?CGPoint thumbnailPoint = CGPointMake(0.0,0.0);


? ? ?if (CGSizeEqualToSize(imageSize, targetSize) == NO)

? ? ?{

? ? ? ? ?CGFloat widthFactor = targetWidth / width;

? ? ? ? ?CGFloat heightFactor = targetHeight / height;


? ? ? ? ?if (widthFactor > heightFactor)

? ? ? ? ? ? ?scaleFactor = widthFactor;????// scale to fit height

? ? ? ? ?else

? ? ? ? ? ? ?scaleFactor = heightFactor;????// scale to fit width

? ? ? ? ?scaledWidth? = width * scaleFactor;

? ? ? ? ?scaledHeight = height * scaleFactor;


? ? ? ? ?// center the image

? ? ? ? ?if(widthFactor > heightFactor)

? ? ? ? ?{

? ? ? ? ? ? ?thumbnailPoint.y = (targetHeight -scaledHeight) *0.5;

? ? ? ? ?}

? ? ? ? ?else

? ? ? ? ? ? ?if(widthFactor < heightFactor)

? ? ? ? ? ? ?{

? ? ? ? ? ? ? ? ?thumbnailPoint.x =(targetWidth - scaledWidth) *0.5;

? ? ? ? ? ? ?}

? ? ?}??????


? ? ?UIGraphicsBeginImageContext(targetSize);????// this will crop


? ? ?CGRect thumbnailRect = CGRectZero;

? ? ?thumbnailRect.origin = thumbnailPoint;

? ? ?thumbnailRect.size.width? = scaledWidth;

? ? ?thumbnailRect.size.height = scaledHeight;


? ? ?[sourceImage drawInRect: thumbnailRect];


? ? ?newImage = UIGraphicsGetImageFromCurrentImageContext();

? ? ?if(newImage== nil)

? ? ? ? ?NSLog(@"could not scale image");


? ? ?//pop the context to get back to the default

? ? ?UIGraphicsEndImageContext();

? ? ?return newImage;

}


- (UIImage*)generatePhotoThumbnail:(UIImage *)image

{

? ? ?// Create a thumbnail version of the image for the event object.

? ? ?CGSize size = image.size;

? ? ?CGSize croppedSize;

? ? ?CGFloat ratio =64.0;//這個(gè)是設(shè)置轉(zhuǎn)換后圖片的尺寸大小

? ? ?CGFloat offsetX =0.0;

? ? ?CGFloat offsetY =0.0;


? ? ?// check the size of the image, we want to make it

? ? ?// a square with sides the size of the smallest dimension

? ? ?if(size.width > size.height) {

? ? ? ? ?offsetX = (size.height - size.width) /2;

? ? ? ? ?croppedSize = CGSizeMake(size.height, size.height);

? ? ?}

????else{

? ? ? ? ?offsetY = (size.width - size.height) /2;

? ? ? ? ?croppedSize = CGSizeMake(size.width, size.width);

? ? ?}


? ? ?// Crop the image before resize

? ? ?CGRect clippedRect = CGRectMake(offsetX *-1, offsetY * -1, croppedSize.width, croppedSize.height);

????//裁剪圖片

????CGImageRef imageRef =CGImageCreateWithImageInRect([image CGImage], clippedRect);

????// Resize the image

? ? ?CGRect rect = CGRectMake(0.0,0.0,ratio, ratio);


? ? ?UIGraphicsBeginImageContext(rect.size);

? ? ?[[UIImage imageWithCGImage: imageRef] drawInRect: rect];

? ? ?UIImage *thumbnail = UIGraphicsGetImageFromCurrentImageContext();

? ? ?UIGraphicsEndImageContext();

? ? ?// DoneResizing


? ? ?return thumbnail;

}


實(shí)際應(yīng)用簡化

- (UIImage *)generatePhotoThumbnail:(UIImage*)image

{

???CGRect rect=CGRectMake(0,0,60,78);

????//裁剪圖片

???CGImageRef imageRef=CGImageCreateWithImageInRect([image CGImage], CGRectMake(0,0,140,182));


???UIGraphicsBeginImageContext(rect.size);

???[[UIImage imageWithCGImage: imageRef] drawInRect: rect];

????//如果不裁剪圖片可以直接畫

???//[image drawInRect:CGRectMake(0, 0, theSize.width, theSize.height)];

???UIImage *thumbnail = UIGraphicsGetImageFromCurrentImageContext();

???UIGraphicsEndImageContext();

???return thumbnail;

}


附:

????UIImage類并沒有提供縮放圖片需要用到的API厨相,是不是覺得很吃驚?沒關(guān)系鸥鹉,我們自己來添加一個(gè)领铐。

定義縮放圖片的Category

//? UIImage+Scale.h

@interface UIImage (scale)

- (UIImage*) scaleToSize: (CGSize)size;


@end


實(shí)現(xiàn)這個(gè)Category的定義

// UIImage+Scale.m?

#import "UIImage+Scale.h"


@implementation UIImage (scale)


-(UIImage*)scaleToSize:(CGSize)size

{

????// 創(chuàng)建一個(gè)bitmap的context,并把它設(shè)置成為當(dāng)前正在使用的context

?????UIGraphicsBeginImageContext(size);


?????// 繪制改變大小的圖片

????[self drawInRect: CGRectMake(0, 0, size.width, size.height)];


?????// 從當(dāng)前context中創(chuàng)建一個(gè)改變大小后的圖片

?????UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();


?????// 使當(dāng)前的context出堆棧

?????UIGraphicsEndImageContext();


?????// 返回新的改變大小后的圖片

????return scaledImage;

}


@end


如何使用

// 創(chuàng)建圖片

UIImage *image = [UIImage imageNamed:@"myImage.png"];


// 更改圖片大小

UIImage *scaledImage = [image scaleToSize: CGSizeMake(25.0f,35.0f)]


2.2 圖片裁切的四種方法

///方法中會(huì)自動(dòng)做縮放處理

+ (void) getBitmapImage: (UIImage *)image Size: (CGSize)imageSize CompletionBlock: (HJCallbackBlock)block

{

??? ????//改進(jìn)方案

????dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{

??? ????????//YES參數(shù)表示不透明裁切

??????? ????UIGraphicsBeginImageContextWithOptions(imageSize,YES, 0);

??????????? CGContextRef context = UIGraphicsGetCurrentContext();


??????? ????if(!context) {

??????????? ????dispatch_async(dispatch_get_main_queue(),^{

?????? ?????????????block(image);

??????????? ????});

??????? }


??????? CGRect rect = CGRectMake(0, 0, imageSize.width, imageSize.height);


??????? //坐標(biāo)系統(tǒng)已經(jīng)自動(dòng)考慮了縮放因素宋舷,不需要額外處理

??????? [image drawInRect: rect blendMode: kCGBlendModeNormal alpha:1];


??????? UIImage*temp = UIGraphicsGetImageFromCurrentImageContext();

??????? NSData*tempData = UIImageJPEGRepresentation(temp,1);

??????? UIGraphicsEndImageContext();


??????? //設(shè)置SDWebImage庫的緩存

??????? NSString*device = [HJUtility getCurrentDevice];

??????? if([device rangeOfString:@"iPhone 4"].length> 0) {

??????????? if(tempData.length > 500000) {

??????????????? tempData =UIImageJPEGRepresentation(temp,0.6);

??????????? }


??????????? temp = [UIImage imageWithData: tempData];

??????? }


??????? dispatch_async(dispatch_get_main_queue(),^{

??????????? if(block) {

??????????????? block(temp);

???? ???????}

??????? });

??? });


??? //??? //改進(jìn)方案1

??? //??????? CGImageRef imgRef = CGImageCreateWithImageInRect(image.CGImage, CGRectMake(0, 0, image.size.width, image.size.height));

??? //???????UIGraphicsBeginImageContextWithOptions(imageSize, YES, 0);

??? //??????? CGContextRef context =UIGraphicsGetCurrentContext();

??? //

??? //??????? CGContextDrawImage(context, imageRect, imgRef);

??? //

??? //??? //???[image drawInRect: imageRect];

??? //??????? UIImage *imgData = UIGraphicsGetImageFromCurrentImageContext();

??? //

??? //??????? UIGraphicsEndImageContext();

??? //??????? CGImageRelease(imgRef);

??? //

??? //??????? UIImage *data = [selfverticallyFlipImage: imgData];

??? //

??? //??????? return data;


??? //方案二绪撵,內(nèi)存有釋放,掛機(jī)

??? //???UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);

??? //

??? //??? CGContextRef context = UIGraphicsGetCurrentContext();

??? //??? CGRect rect = CGRectMake(0, 0,imageSize.width * [UIScreen mainScreen].scale, imageSize.height * [UIScreenmainScreen].scale);

??? //??? // draw alpha-mask

??? ////??? CGContextSetBlendMode(context,kCGBlendModeNormal);

??? //??? CGContextDrawImage(context, rect,image.CGImage);

??? //??? // draw tint color, preserving alpha valuesof original image

??? ////??? CGContextSetBlendMode(context,kCGBlendModeSourceIn);

??? //

??? //??? CGContextFillRect(context, rect);

??? //

??? //??? //Set the original greyscale template asthe overlay of the new image

??? //??? UIImage *imgData = [self verticallyFlipImage: image];

??? //??? [imgData drawInRect: imageRect];

??? //??? UIImage *colouredImage = UIGraphicsGetImageFromCurrentImageContext();

??? //??? UIGraphicsEndImageContext();

??? //??? colouredImage = [self verticallyFlipImage: colouredImage];

??? //??? CGContextRelease(context);

??? //

??? //??? return colouredImage;


??? //方案三祝蝠,CGBitmapContextCreate方案音诈,內(nèi)存沒釋放

??? //??? CGFloat targetWidth = imageSize.width *[UIScreen mainScreen].scale;

??? //

??? //??? CGFloat targetHeight = imageSize.height *[UIScreen mainScreen].scale;

??? //??? CGImageRef imageRef = [image CGImage];

??? //

??? //??? CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);

??? //

??? //??? CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);

??? //??? CGContextRef bitmapContext;

??? //??? bitmapContext = CGBitmapContextCreate(NULL, targetWidth, targetHeight, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);

??? //??? CGContextDrawImage(bitmapContext, CGRectMake(0, 0, targetWidth, targetHeight), imageRef);

??? //

??? //??? CGImageRef imgref = CGBitmapContextCreateImage(bitmapContext);

??? //??? UIImage* newImage = [UIImage imageWithCGImage: imgref];

??? //

??? //??? CGColorSpaceRelease(colorSpaceInfo);

??? //??? CGContextRelease(bitmapContext);

??? //??? CGImageRelease(imgref);

??? //

??? //??? return newImage;


??? //方案四,CGBitmapContextCreate方案绎狭,但是采用CGDataProviderCreateWithCFData方案解決內(nèi)存占用問題

??? //??? NSData *data =UIImageJPEGRepresentation(image, 1);

??? //??? CGDataProviderRef dataProvider =CGDataProviderCreateWithCFData((__bridge CFDataRef)data);

??? //??? CGImageRef imageRef =CGImageCreateWithJPEGDataProvider(dataProvider,

??? //??????????????????????????????????????????????????????????NULL, NO,

??? //??????????????????????????????????????????????????????????kCGRenderingIntentDefault);

??? //

??? //??? CGFloat targetWidth = imageSize.width *[UIScreen mainScreen].scale;

??? //??? CGFloat targetHeight = imageSize.height *[UIScreen mainScreen].scale;

??? //??? //???????CGImageRef imageRef = [image CGImage];

??? //

??? //??? CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);

??? //

??? //??? CGColorSpaceRef colorSpaceInfo =CGImageGetColorSpace(imageRef);

??? //??? CGContextRef bitmapContext;

??? //??? bitmapContext = CGBitmapContextCreate(NULL,targetWidth, targetHeight,CGImageGetBitsPerComponent(imageRef),0,colorSpaceInfo, bitmapInfo);

??? //??? CGContextDrawImage(bitmapContext,CGRectMake(0, 0, targetWidth, targetHeight), imageRef);

??? //

??? //??? // If failed, return undecompressed image

??? //??? if (!bitmapContext) return image;

??? //

??? //??? CGImageRef imgref =CGBitmapContextCreateImage(bitmapContext);

??? //??? UIImage* newImage = [UIImageimageWithCGImage:imgref];//[UIImage imageWithCGImage:decompressedImageRefscale:image.scale orientation:image.imageOrientation];

??? //???

??? //??? CGColorSpaceRelease(colorSpaceInfo);

??? //??? CGContextRelease(bitmapContext);

??? //??? CGImageRelease(imgref);

??? //???

??? //??? return newImage;

}


3 參考鏈接

iOS開發(fā)中關(guān)于UIImage的知識點(diǎn)總結(jié)

http://mobile.51cto.com/hot-442118.htm

iOS開發(fā)筆記--使用blend改變圖片顏色

http://blog.csdn.net/hopedark/article/details/17761177

iOS處理圖片的一些小Tip

http://blog.ibireme.com/2015/11/02/ios_image_tips/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末细溅,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子儡嘶,更是在濱河造成了極大的恐慌喇聊,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蹦狂,死亡現(xiàn)場離奇詭異誓篱,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)凯楔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門窜骄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人摆屯,你說我怎么就攤上這事邻遏。” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵准验,是天一觀的道長赎线。 經(jīng)常有香客問我,道長糊饱,這世上最難降的妖魔是什么垂寥? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮济似,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘盏缤。我一直安慰自己砰蠢,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布唉铜。 她就那樣靜靜地躺著台舱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪潭流。 梳的紋絲不亂的頭發(fā)上竞惋,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天,我揣著相機(jī)與錄音灰嫉,去河邊找鬼拆宛。 笑死,一個(gè)胖子當(dāng)著我的面吹牛讼撒,可吹牛的內(nèi)容都是我干的浑厚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼根盒,長吁一口氣:“原來是場噩夢啊……” “哼钳幅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起炎滞,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤敢艰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后册赛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钠导,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年森瘪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了辈双。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,424評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡柜砾,死狀恐怖湃望,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤证芭,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布瞳浦,位于F島的核電站,受9級特大地震影響废士,放射性物質(zhì)發(fā)生泄漏叫潦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一官硝、第九天 我趴在偏房一處隱蔽的房頂上張望矗蕊。 院中可真熱鬧,春花似錦氢架、人聲如沸傻咖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卿操。三九已至,卻和暖如春孙援,著一層夾襖步出監(jiān)牢的瞬間害淤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工拓售, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留窥摄,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓础淤,卻偏偏與公主長得像溪王,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子值骇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評論 2 359

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