今天博主有一個圖片及處理的需求,遇到了一些困難點,在此和你們分享,但願可以共同進步.python
UIImage對象是iOS中用來顯示圖像數據的高級接口。咱們能夠從文件,NSData,Quartz圖片對象中建立UIImage對象。能夠說這個類是咱們接觸頻率很是高的一個類。ios
UIImage對象是不可變的,因此一旦建立後,咱們就不能再改變它的屬性。這也就意味着,咱們只能在初始化方法中提供屬性值或依賴於圖片自身的屬性值。一樣,因爲其不可變,因此在任何線程中均可以安全地使用它。swift
若是咱們想修改UIImage對象的一些屬性,則可使用便捷方法和自定義的參數值來建立圖像的一份拷貝。數組
另外,因爲UIImage對象是不可變的,因此它沒有提供訪問底層圖片數據的方法。不過咱們可使用UIImagePNGRepresentation或UIImageJPEGRepresentation方法來獲取包含PNG或JPG格式的數據的NSData對象。以下代碼所示:緩存
let image = UIImage(named: "swift"); let imageData:NSData? = UIImageJPEGRepresentation(image!, 1.0)
對於一個UIImage對象來講,它的數據源主要有如下幾種:安全
文件:咱們可使用init(contentsOfFile:)方法來從指定文件中建立對象。ruby
純圖片數據(NSData):若是在內存中有圖片的原始數據(表示爲NSData對象),則可使用init(data:)來建立。須要注意的是這個方法會對象圖片數據作緩存。app
CGImage對象:若是咱們有一個CGImage對象,則可使用init(CGImage:)或init(CGImage:scale:orientation:)建立UIImage對象。性能
CIImage對象:若是咱們有一個CIImage對象,則可使用init(CIImage:)或init(CIImage:scale:orientation:)建立UIImage對象。優化
須要注意的是,若是是從文件或者純圖片數據中建立UIImage對象,則要求對應的圖片格式是系統支持的圖片類型。
對於Objective-C來講,UIImage對象也提供了這些初始化方法對應的便捷類方法來建立對象。
在實際的應用中,特別是圖片類應用中,咱們可能須要使用大量的圖片。咱們都知道,圖片一般都是很是佔內存的。若是同一時間加載大量的圖片,就可能佔用大量的系統內存。
爲此,Apple採用了一種比較巧妙的策略。在低內存的狀況下,系統會強制清除UIImage對象所指向的圖片數據,以釋放部份內存。注意,這種清除行爲影響到的只是圖片數據,而不會影響到UIImage對象自己。當咱們須要繪製那些圖片數據已經被清除的UIImage對象時,對象會自動從源文件中從新加載數據。固然,這是以時間換空間的一種策略,會致使必定的性能損耗。
說到這裏,咱們不得不提一下init(named:)方法了。能夠說咱們平時建立UIImage對象用得最多的應該就是這個方法。這個方法主要是使用bundle中的文件建立圖片的快捷方式。關於這個方法,有幾點須要注意:
緩存:這個方法會首先去系統緩存中查找是否有圖片名對應的圖片。若是有就返回緩存中的圖片;若是沒有,則該方法從磁盤或者asset catalog中加載圖片並返回,同時將圖片緩存到系統中。緩存的圖片只有在收到內存警告時纔會釋放。所以,若是圖片的使用頻率比較低,則能夠考慮使用imageWithContentsOfFile:方法來加載圖片,這樣能夠減小內存資源的消耗。固然,這須要權衡考慮,畢竟讀寫磁盤也是有性能消耗的,並且如今的高端機內存已經不小了。
多分辨率圖片處理:在iOS 4.0後,該方法會根據屏幕的分辨率來查找對應尺寸的圖片。即咱們使用時,只須要寫圖片名,而不須要指定是1x, 2x仍是3x圖,該方法會本身判斷。
png圖片後綴:在iOS 4.0之後,若是圖片是png格式的,則圖片文件名不須要附帶擴展名。
線程安全性:該方法在iOS 9.0以前並非線程安全的,在二級線程中調用可能會致使崩潰。在iOS 9.0以後,Apple做了優化處理,將其改成線程安全的方法。爲了不沒必要要的麻煩,儘可能在主線程中調用這個方法。
當咱們的圖片比所要填充的區域小時,會致使圖片變形。如如下圖片,原始大小爲100*30,將其放到一個300*50的UIImageView中時,整個圖片被拉伸。
原始圖片
拉伸後的圖片
這時咱們就須要作特殊的處理。
Android的同窗應該都知道.9圖,這種圖片能夠只拉伸中間的部分,而保持四個角不變形。在iOS中也支持這種操做。在早期的iOS版本中,UIImage提供了以下方法來執行此操做:
func stretchableImageWithLeftCapWidth(_ leftCapWidth: Int, topCapHeight topCapHeight: Int) -> UIImage
這個方法經過leftCapWidth和topCapHeight兩個參數來定義四個角的大小。不過這個方法在iOS 5中就被Deprecated了,對應的兩個屬性leftCapWidth和topCapHeight也是相同的命運。因此如今不建議使用它們。另外,對於如何解釋leftCapWidth和topCapHeight,你們能夠參考一下@M了個J的 iOS圖片拉伸技巧 。
在iOS 5中,咱們可使用如下方法來執行相同的操做:
func resizableImageWithCapInsets(_ capInsets: UIEdgeInsets) -> UIImage
這個方法經過一個UIEdgeInsets來指定上下左右不變形的寬度或高度。它會返回一個新的圖像。而若是圖像被拉伸,則會以平鋪的方式來處理中間的拉伸區域。
咱們對上面的圖片作以下處理:
let resizedButtonImageView = UIImageView(image: normalButtonImage?.resizableImageWithCapInsets(UIEdgeInsets(top: 15, left: 15, bottom: 15, right: 15))) resizedButtonImageView.frame = CGRectMake(0, 60, 300, 50)
其獲得的結果以下所示:
在iOS 6,Apple又爲咱們提供了一個新的方法,相較於上面這個方法,只是多一個resizingMode參數,容許咱們指定拉伸模式。
func resizableImageWithCapInsets(_ capInsets: UIEdgeInsets, resizingMode resizingMode: UIImageResizingMode) -> UIImage
這個方法的拉伸模式分兩種:平鋪(Tile)和拉伸(Stretch)。若是是平鋪模式,則跟前一個方法是同樣的效果。
若是咱們有一組大小和縮放因子相同的圖片,就能夠將這些圖片加載到同一個UIImage對象中,造成一個動態的UIImage對象。爲此,UIImage提供瞭如下方法:
class func animatedImageNamed(_ name: String, duration duration: NSTimeInterval) -> UIImage?
這個方法會加載以name爲基準文件名的一系列文件。如,假設咱們的name參數值爲」swift」,則這個方法會加載諸如」swift0」, 「swift1」,…, 「swift1024」這樣的一系列的文件。
這裏有兩個問題須要注意:
文件的序號必須是從0開始的連續數字,若是不從0開始,則在Playground中是會報錯的。而若是中間序號有斷,而中斷後的圖片是不會被加載的。
全部文件的大小和縮放因子應該是相同的,不然顯示時會有不可預期的結果,這種結果主要表現爲播放的順序多是雜亂的。
若是咱們有一組基準文件名不一樣的文件,但其大小和縮放因子相同,則可能使用如下方法:
class func animatedImageWithImages(_ images: [UIImage], duration duration: NSTimeInterval) -> UIImage?
傳入一個UIImage數組來拼裝一個動效UIImage對象。
另外,UIImage也提供了resizable版本的動效方法,以下所示:
class func animatedResizableImageNamed(_ name: String, capInsets capInsets: UIEdgeInsets, duration duration: NSTimeInterval) -> UIImage? class func animatedResizableImageNamed(_ name: String, capInsets capInsets: UIEdgeInsets, resizingMode resizingMode: UIImageResizingMode, duration duration: NSTimeInterval) -> UIImage?
第一個方法的UIImageResizingMode默認是UIImageResizingModeTile,因此若是想對圖片作拉伸處理,可使用第二個的方法,並傳入UIImageResizingModeStretch。
UIImage對象使用的圖片大小盡可能小於1024*1024。由於這麼大的圖片消耗的內存過大,在將其做爲OpenGL中的貼圖或者是繪製到view/layer中時,能夠會出現問題。若是僅僅是代碼層面的操做的話,則沒有這個限制。好比,將一個大於1024*1024的圖片繪製到位圖圖形上下文中以從新設定其大小。事實上,咱們須要經過這種操做來改變圖片大小,以將其繪製到視圖中。
UIImage支持的圖片格式在 UIImage Class Reference 中列出來了,你們能夠直接參考。
須要注意的一點是RGB-565格式的BMP文件在加載時會被轉換成ARGB-1555格式
http://blog.ibireme.com/2015/11/02/ios_image_tips/