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

1 UIImage知識點

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

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

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

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

1.1 UIImage的size,scale屬性

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

????????第一反應(yīng)可能就是image.size,恭喜你答錯了,正確的答案是圖像的實際的尺寸(像 素)等于image.size乘以image.scale。如果做過界面貼圖的話你可能經(jīng)常會需要準(zhǔn)備至少兩套圖,一套1倍圖,一套圖已@2x命名的二倍 圖。這樣當(dāng)我們的程序運(yùn)行在retina屏幕的時候系統(tǒng)就會自動的去加載@2x的圖片,它的size將和一倍圖加載進(jìn)來的size相等,但是scale卻 置為2,這點大家可以做個簡單的小測試驗證一下。然我們再深入一點兒為什么不直接加載到成二倍的尺寸呢,原因很簡單因為我們在界面布局中邏輯坐標(biāo)系中的 (單位是point),而實際的繪制都是在設(shè)備坐標(biāo)系(單位是pixel)進(jìn)行的,系統(tǒng)會自動幫我們完成從point到pixel之間的轉(zhuǎn)化。其實這個比 例也就剛好和UIScreen中的scale對應(yīng),這樣整條scale的線就可以串通了。

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

1imageNamed:方法

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

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

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

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

2imageWithContentsOfFile:initWithContentsOfFile:方法

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

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

3、imageWithCGImage:scale:orientation:方法

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

1.3 UIImage的imageOrientation屬性

????????UIImage有一個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)常會碰到把iPhone相冊中的照片導(dǎo)入到windows中,發(fā)現(xiàn)方向不對的問題就是與這個屬性有關(guān),因為導(dǎo)出照片的時候,寫exif中 的方向信息時候沒有考慮該方向的原因。既然這個屬性可以控制image的繪制方向,那我們能不能通過改過這個屬性來完成UIImage的旋轉(zhuǎn)和翻轉(zhuǎn)呢?帶 著這個問題我們繼續(xù)往下看。

1.4 UIImage的幾個draw方法

????????UIImage的幾個draw方法是用來繪制圖像的利器,為什么這樣說呢?因為它們在繪制圖 像的時候會考慮當(dāng)前圖像的方向,即根據(jù)的imageOrientation繪制出不同的方向。由于圖像是繪制在當(dāng)前context中的,它同時還會考慮到 當(dāng)前context的transform的變化。利于這兩點我們就可以玩轉(zhuǎn)圖像的旋轉(zhuǎn)和翻轉(zhuǎn)了。

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

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

????????假設(shè)一副圖片顯示為?,我們要向左旋轉(zhuǎn)90°,那么轉(zhuǎn)過之后應(yīng)該就會顯示為,即將原圖從orientationUP轉(zhuǎn)到orientationLeft即可。以此類推為不同的方向旋轉(zhuǎn),只需要注意看R的顯示即可,這樣整個旋轉(zhuǎn)和翻轉(zhuǎn)的實現(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

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

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


1.5 圖片處理小技巧

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

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

1.5.1 如何把GIF動圖保存到相冊?

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

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

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

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

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

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

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

1.5.3 UIImage緩存是怎么回事?

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

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

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

1.5.5 怎么能避免緩存呢?

????1.手動調(diào)用CGImageSourceCreateWithData()來創(chuàng)建圖片,并把ShouldCache和ShouldCacheImmediately關(guān)掉。這么做會導(dǎo)致每次圖片顯示到屏幕時,解碼方法都會被調(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)建一個未解碼的CGImage。

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

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

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

1.5.7 如何判斷一個文件的圖片類型?

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

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

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

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

????第二種是interlaced,即隔行掃描。PNG和GIF在保存時可以選擇這種格式。

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

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

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


2 開發(fā)技巧

2.1 圖片縮放

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

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

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

//把圖片做等比縮放,生成一個新圖片

- (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)行裁剪,生成一個新圖片

- (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;//這個是設(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;

}


實際應(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)系,我們自己來添加一個。

定義縮放圖片的Category

//? UIImage+Scale.h

@interface UIImage (scale)

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


@end


實現(xiàn)這個Category的定義

// UIImage+Scale.m?

#import "UIImage+Scale.h"


@implementation UIImage (scale)


-(UIImage*)scaleToSize:(CGSize)size

{

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

?????UIGraphicsBeginImageContext(size);


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

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


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

?????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 圖片裁切的四種方法

///方法中會自動做縮放處理

+ (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)自動考慮了縮放因素,不需要額外處理

??????? [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的知識點總結(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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容