有一段時間沒有寫博客了,中間隔了個五一假,算一下差不多20天,這段時間准備組內的一個分享,所以就耽擱了,今天准備寫一些UIImage方面的東西。
UIImage是IOS中層級比較高的一個用來加載和繪制圖像的一個類,更底層的類還有CGImage,以及IOS5.0以后新增加的CIImage。今天我們主要聊一聊UIImage的三個屬性: imageOrientation, size, scale,幾個初始化的方法: imageNamed,imageWithContentsOfFile,以及繪制Image的幾個draw開頭的方法。
一、UIImage的size,scale屬性
先想一個問題“一個圖像的尺寸到底是多大呢?”
第一反應可能就是image.size,恭喜你答錯了,正確的答案是圖像的實際的尺寸(像素)等於image.size乘以image.scale。如果做過界面貼圖的話你可能經常會需要准備至少兩套圖,一套1倍圖,一套圖已@2x命名的二倍圖。這樣當我們的程序運行在retina屏幕的時候系統就會自動的去加載@2x的圖片,它的size將和一倍圖加載進來的size相等,但是scale卻置為2,這點大家可以做個簡單的小測試驗證一下。然我們再深入一點兒為什么不直接加載到成二倍的尺寸呢,原因很簡單因為我們在界面布局中邏輯坐標系中的(單位是point),而實際的繪制都是在設備坐標系(單位是pixel)進行的,系統會自動幫我們完成從point到pixel之間的轉化。其實這個比例也就剛好和UIScreen中的scale對應,這樣整條scale的線就可以串通了。
二、UIImage的幾種初始化方法的對比
1、imageNamed:方法
imageNamed:是UIImage的一個類方法,它做的事情比我們看到的要稍微多一些。它的加載流程如下:
a. 系統回去檢查系統緩存中是否存在該名字的圖像,如果存在則直接返回。
b. 如果系統緩存中不存在該名字的圖像,則會先加載到緩存中,在返回該對象。
觀察上面的操作我們發現系統會緩存我們使用imageNamed:方法加載的圖像時候,系統會自動幫我們緩存。這種機制適合於那種頻繁用到界面貼圖累的加載,但如果我們需要短時間內頻繁的加載一些一次性的圖像的話,最好不要使用這種方法。
2、imageWithContentsOfFile:和initWithContentsOfFile:方法
這兩個方法跟前一個方法一樣都是完成從文件加載圖像的功能。但是不會經過系統緩存,直接從文件系統中加載並返回。
順便提一下,當收到內存警告的時候,系統可能會將UIImage內部的存儲圖像的內存釋放,下一次需要繪制的時候會重新去加載。
3、imageWithCGImage:scale:orientation:方法
該方面使用一個CGImageRef創建UIImage,在創建時還可以指定方法倍數以及旋轉方向。當scale設置為1的時候,新創建的圖像將和原圖像尺寸一摸一樣,而orientaion則可以指定新的圖像的繪制方向。
三、UIImage的imageOrientation屬性
UIImage有一個imageOrientation的屬性,主要作用是控制image的繪制方向,共有以下8中方向:
typedef NS_ENUM(NSInteger, UIImageOrientation) { UIImageOrientationUp, // default orientationUIImageOrientationDown, // 180 deg rotation
UIImageOrientationLeft, // 90 deg CCW
(編程發現官方文檔中,left和right圖像標反了,此處更正過來) UIImageOrientationRight, // 90 deg CW
UIImageOrientationUpMirrored, // as above but image mirrored along other axis. horizontal flipUIImageOrientationDownMirrored, // horizontal flip
UIImageOrientationLeftMirrored, // vertical flip
UIImageOrientationRightMirrored, // vertical flip
};
默認的方向是UIImageOrientationUp,這8種方向對應的繪制方如上面所示。我們在日常使用中經常會碰到把iPhone相冊中的照片導入到windows中,發現方向不對的問題就是與這個屬性有關,因為導出照片的時候,寫exif中的方向信息時候沒有考慮該方向的原因。既然這個屬性可以控制image的繪制方向,那我們能不能通過改過這個屬性來完成UIImage的旋轉和翻轉呢?帶着這個問題我們繼續往下看。
四、UIImage的幾個draw方法
UIImage的幾個draw方法是用來繪制圖像的利器,為什么這樣說呢?因為它們在繪制圖像的時候會考慮當前圖像的方向,即根據的imageOrientation繪制出不同的方向。由於圖像是繪制在當前context中的,它同時還會考慮到當前context的transform的變化。利於這兩點我們就可以玩轉圖像的旋轉和翻轉了。
搜索了一些,目前網上大部分圖像旋轉都是通過創建CGBitmapContext,然后根據圖像方向設置context的transform來實現的,這種方法要求對整個矩陣變化的過程都非常清楚,一個參數設置不多,出來的結果就會有問題。
下面我介紹一種實現起來簡單方便的圖像旋轉方法,這種方法主要就是利用imageWithCGImage:scale:orientation:方法,指定不同的orientation來完成所需要的功能,先舉個簡單的例子:
假設一副圖片顯示為 ,我們要向左旋轉90°,那么轉過之后應該就會顯示為
,即將原圖從orientationUP轉到orientationLeft即可。以此類推為不同的方向旋轉,只需要注意看R的顯示即可,這樣整個旋轉和翻轉的實現過程中完全可以不用考慮Transform那些東西,是不是很簡單。
下面是圖像旋轉和翻轉的完整代碼:

// // UIImage+Rotate_Flip.h // SvImageEdit // // Created by maple on 5/14/13. // Copyright (c) 2013 smileEvday. All rights reserved. // // #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.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
以上只是實現了圖像的順時針90°,逆時針90°,180°旋轉,以及水平翻轉,數值翻轉等。至於任意角度旋轉怎么實現?其實也很簡單,留着給大家思考吧。雖然我們可以通過orientation這種方法簡單的完成圖像旋轉,但是如果有時間的話還是建議大家盡量的看一下那種通過transform來完成旋轉的代碼,你會徹底搞清楚旋轉矩陣是怎么回事兒。當然程序中使用的時候推薦使用我上面提供的這種方法,因為不涉及真實的旋轉操作,速度會快很多。
通過上面的小例子,我們可以看出越高級別的API幫助我們做的事情就越多,越底層的API提供了更多的靈活性,但同時也帶來了很多需要我們處理的東西。再編程的過程中盡量的使用高級別的API,同時最好能搞懂底層的實現機制。這樣我們的程序才會更高效,出了問題才知道去哪里查找。
注:轉載請注明出處!歡迎大家一起討論,共同進步。