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