UIImage,CGImage和CGImageRef釋疑
UIImage雖然可以加載糯累、顯示各種格式的位圖沙咏,甚至可以同時(shí)加載圖片肮疗,接下來依次播放多張圖片形成動(dòng)畫。但UIImage不能對(duì)圖片進(jìn)行縮放童番、旋轉(zhuǎn)精钮,不能"挖取"源圖片的指定區(qū)域等,這些功能可借助Quartz 2D的CGImageRef來實(shí)現(xiàn)剃斧。UIImage與CGImageRef之間可以相互轉(zhuǎn)換轨香,CGImageRef并不是面向?qū)ο蟮腁PI,也不是類悯衬,只是一個(gè)指針類型弹沽,Quartz 2D對(duì)CGImageRef的定義為:
typedef struct CGImage *CGImageRef;
CGImage和CGImageRef是用來重繪圖形的類,它們?cè)趹?yīng)用時(shí)是按照?qǐng)D像的像素矩陣來繪制圖片的筋粗,它們可以用來處理bitmap策橘。
//CGImageRef轉(zhuǎn)換成UIImage
CGContextRef context = UIGraphicsGetCurrentContext();
CGImageRef ic = CGBitmapContextCreateImage(context);
UIImage* image = [UIImage imageWithCGImage: ic];
//UIImage轉(zhuǎn)換成CGImageRef
UIImage *loadImage=[UIImage imageNamed:@"c.png"];
CGImageRef cgimage=loadImage.CGImage;
系統(tǒng)會(huì)維護(hù)一個(gè)CGContextRef的棧,而UIGraphicsGetCurrentContext()會(huì)取棧頂?shù)腃GContextRef娜亿,正確的做法是只在drawRect里調(diào)用UIGraphicsGetCurrentContext()丽已,因?yàn)樵赿rawRect之前,系統(tǒng)會(huì)往棧里面壓入一個(gè)valid的CGContextRef买决,除非自己去維護(hù)一個(gè)CGContextRef沛婴,否則不應(yīng)該在其他地方取CGContextRef。
UIColor督赤,CGColor嘁灯,CIColor區(qū)別和聯(lián)系
UIColor是UIKit中存儲(chǔ)顏色信息的一個(gè)重要的類,一個(gè)UIColor對(duì)象包含了顏色和透明度的值躲舌,它的顏色空間已經(jīng)針對(duì)iOS進(jìn)行了優(yōu)化丑婿。UIColor包含了一些類方法用于創(chuàng)建一些最常見的顏色,如白色没卸,黑色羹奉,紅色,透明色等约计,這些顏色的色彩空間也不盡相同(白色和黑色是kCGColorSpaceDeviceGray诀拭,紅色的色彩空間是kCGColorSpaceDeviceRGB)。UIColor有兩個(gè)重要的屬性:一個(gè)是CGColor煤蚌,一個(gè)是CIColor(5.0之后添加)耕挨。
CGColor主要用于CoreGaphics框架之中,CGColor其實(shí)是個(gè)結(jié)構(gòu)體铺然,而我們通常在使用的CGColor的時(shí)候使用的是它的引用類型CGColorRef俗孝。CGColor主要由CGColorSapce和Color Components兩個(gè)部分組成,同樣的顏色組成魄健,如果顏色空間不同的話赋铝,解析出來的結(jié)果可能會(huì)有所不同。這就像我們?cè)谔幚韴D片數(shù)據(jù)的時(shí)候沽瘦,如果把RGBA格式當(dāng)成BGRA格式處理的結(jié)果可想而知革骨。在Quartz 2D中CGColor常用來設(shè)置context的填充顏色农尖,設(shè)置透明度等。
CIColor主要用于和Core Image框架中其他類交互良哲,比如CIFilter盛卡,CIContext以及CIImage。CIColor中顏色值的范圍是0.0-1.0之間筑凫,0.0代表該顏色分量為最小值滑沧,1.0代表改顏色分量為最大值。其中alpha值的范圍也是0.0到1.0之間巍实,0.0代表全透明滓技,1.0代表完全不透明,CIColor的顏色分量通常都是沒有乘以alpha值棚潦×钇可以使用initWithCGColor:函數(shù),通過CGColor創(chuàng)建一個(gè)CIColor丸边。其中傳入的CGColorRef對(duì)象可以使任何任何顏色空間叠必,但是Core Image框架會(huì)在傳入filter kernel之前把所有的顏色空間轉(zhuǎn)換到Core Image工作顏色空間。Core Image工作顏色空間使用三個(gè)顏色分量加上一個(gè)alpha分量組成(其實(shí)就是kCGColorSpaceDeviceRGB)妹窖。
UIColor的CGColor總是有效的纬朝,不管它是通過CGColor,CIColor骄呼,還是其他方法創(chuàng)建的玄组,CGColor屬性都總是有效的;但是CIColor屬性就不總是有效的谒麦,只有當(dāng)UIColor是通過CIColor創(chuàng)建的時(shí)候,它才是有效的哆致,否則訪問該屬性將會(huì)拋出異常绕德。
// test init uicolor with CGColor
UIColor *color = [UIColor colorWithCGColor:[UIColor whiteColor].CGColor];
// CGColor property is always valid
NSLog(@"CGColor from UIColor %@", color.CGColor);
// don't use CIColor property
// This property throws an exception if the color object was not initialized with a Core Image color.
NSLog(@"CIColor from UIColor %@", color.CIColor); // crush
當(dāng)UIColor使用CGColor初始化的時(shí)候,所有CGColorRef包含的信息摊阀,都會(huì)被原封不動(dòng)的保留耻蛇,其中就包括Color space,而且通過下面的小例子我們還可以看到如果使用CGColor初始化UIColor的時(shí)候胞此,UIColor其實(shí)是直接保留了一份這個(gè)CGColorRef對(duì)象臣咖。
// test kCGColorSpaceDeviceCMYK
CGColorSpaceRef cmykSpace = CGColorSpaceCreateDeviceCMYK();
CGFloat cmykValue[] = {1, 1, 0, 0, 1}; // blue
CGColorRef colorCMYK = CGColorCreate(cmykSpace, cmykValue);
CGColorSpaceRelease(cmykSpace);
NSLog(@"colorCMYK: %@", colorCMYK);
// color with CGColor, uicolor will just retain it
UIColor *color = [UIColor colorWithCGColor:colorCMYK];
NSLog(@"CGColor from UIColor: %@", color.CGColor);
當(dāng)使用CIColor來初始化一個(gè)UIColor的時(shí)候,再去訪問UIColor的CGColor屬性的時(shí)候漱牵,我們會(huì)發(fā)現(xiàn)CGColor的color Space和設(shè)置CIColor的color space的是不完全一樣的夺蛇,在這個(gè)過程中CIColor會(huì)為我們做一個(gè)轉(zhuǎn)換。使用kCGColorSpaceDeviceGray酣胀,kCGColorSpaceDeviceRGB刁赦,kCGColorSpaceDeviceCMYK三種顏色空間來初始化一個(gè)CIColor的時(shí)候娶聘,再去使用該CIColor去初始化一個(gè)UIColor,然后在去訪問其CIColor屬甚脉,CGColor屬性丸升,查看顏色空間并打印顏色信息。
-
使用kCGColorSpaceDeviceGray初始化CIColor
// test kCGColorSpaceDeviceGray NSLog(@"CGColor white color:%@", [UIColor whiteColor].CGColor); CIColor *ciColor = [CIColor colorWithCGColor:[UIColor whiteColor].CGColor]; NSLog(@"cicolor: %@", ciColor); NSLog(@"cicolor colorspace: %@", ciColor.colorSpace); color = [UIColor colorWithCIColor:ciColor]; NSLog(@"color %@", color); // Core Image converts all color spaces to the Core Image working color // space before it passes the color space to the filter kernel. // kCGColorSpaceDeviceGray ---> kCGColorSpaceDeviceRGB NSLog(@"cicolor from UIColor: %@", color.CIColor); NSLog(@"cicolor's colorspace: %@", color.CIColor.colorSpace); NSLog(@"color's CGColor: %@", color.CGColor);
通過運(yùn)行程序牺氨,我們看出來狡耻,如果使用一個(gè)kCGColorSpaceDeviceGray的顏色空間的CGColor來初始化CIColor的時(shí)候,我們可以看到CIColor的色彩空間一直是kCGColorSpaceDeviceGray猴凹,通過訪問UIColor的CIColor屬性夷狰,我們可以看到其顏色空間仍然是kCGColorSpaceDeviceGray,但是當(dāng)訪問UIColor的CGColor屬性的時(shí)候精堕,通過打印可以發(fā)現(xiàn)其色彩空間已經(jīng)轉(zhuǎn)變成了kCGColorSpaceDeviceRGB空間了孵淘,而顏色值也正確的從原來的顏色空間轉(zhuǎn)換到了新的顏色空間。
-
使用kCGColorSpaceDeviceRGB初始化CIColor
//test kCGColorSpaceDeviceRGB NSLog(@"CGColor red color:%@", [UIColor redColor].CGColor); CIColor *ciColor = [CIColor colorWithCGColor:[UIColor redColor].CGColor]; NSLog(@"cicolor: %@", ciColor); NSLog(@"cicolor colorspace: %@", ciColor.colorSpace); UIColor *color = [UIColor colorWithCIColor:ciColor]; NSLog(@"color %@", color); NSLog(@"cicolor from UIColor: %@", color.CIColor); NSLog(@"cicolor's colorspace: %@", color.CIColor.colorSpace); NSLog(@"color's CGColor: %@", color.CGColor);
整個(gè)過程中CIColor歹篓,以及通過UIColor的CGColor和CIColor屬性訪問到的值瘫证,打印出來我們可以發(fā)現(xiàn)它們都是kCGColorSpaceDeviceRGB空間的。
-
使用kCGColorSpaceDeviceCMYK初始化CIColor
// test kCGColorSpaceDeviceCMYK CGColorSpaceRef cmykSpace = CGColorSpaceCreateDeviceCMYK(); NSLog(@"Components number: %zu", CGColorSpaceGetNumberOfComponents(cmykSpace)); CGFloat cmykValue[] = {1, 1, 0, 0, 1}; // blue CGColorRef colorCMYK = CGColorCreate(cmykSpace, cmykValue); CGColorSpaceRelease(cmykSpace); NSLog(@"colorCMYK: %@", colorCMYK); ciColor = [CIColor colorWithCGColor:colorCMYK]; NSLog(@"cicolor: %@", ciColor); // in fact庄撮,the color value of CIColor has converted to RGB Colorspace NSLog(@"cicolor colorspace: %@", ciColor.colorSpace); color = [UIColor colorWithCIColor:ciColor]; NSLog(@"UIColor with CIColor: %@", color); NSLog(@"cicolor from UIColor: %@", color.CIColor); NSLog(@"cicolor's colorspace: %@", color.CIColor.colorSpace); // when UIColor init with CIColor, UIColor's CGColor will convert other colorspace to kCGColorSpaceDeviceRGB NSLog(@"cgcolor from UIColor: %@", color.CGColor);
當(dāng)我們用一個(gè)CMYK顏色空間的CGColor來初始化CIColor的時(shí)候背捌,CIColor的顏色空間依然是CMYK,但是顏色值已經(jīng)轉(zhuǎn)換成RGB的顏色值洞斯。當(dāng)使用該CIColor創(chuàng)建一個(gè)UIColor的時(shí)候毡庆,我們?cè)偻ㄟ^CIColor和CGColor屬性打印信息的時(shí)候,我們會(huì)發(fā)現(xiàn)CIColor的色彩空間依然是CMYK烙如,但是CGColor打印所得到的信息說明它已經(jīng)被轉(zhuǎn)換成RGB空間了么抗。
關(guān)于創(chuàng)建一個(gè)CGColor
最常用的函數(shù)是CGColorCreate,該函數(shù)有兩個(gè)參數(shù):
- colorspace亚铁,指定CGColor對(duì)應(yīng)的顏色空間蝇刀,Quartz就會(huì)retain該對(duì)象,因此調(diào)用完之后你就可以安全的釋放該對(duì)象徘溢。
- components吞琐,一個(gè)CGFloat的數(shù)組,該數(shù)組的元素個(gè)數(shù)是指定色彩空間包含的顏色分量數(shù)n然爆,加上對(duì)應(yīng)的alpha值站粟。
該函數(shù)該返回一個(gè)新創(chuàng)建的CGColorRef,當(dāng)我們不再使用該對(duì)象的時(shí)候使用CGColorRelease函數(shù)釋放該對(duì)象曾雕。
獲取CGColor的數(shù)據(jù)
在我們創(chuàng)建的時(shí)候傳入兩個(gè)重要的參數(shù)進(jìn)去奴烙,當(dāng)我們獲取到了CGColorRef以后當(dāng)然就可以拿到對(duì)應(yīng)的ColorSpace以及Components。
-
獲取ColorSpace
通過CGColorGetColorSpace函數(shù)我們可以獲取到當(dāng)前CGColorRef對(duì)應(yīng)的ColorSpace,該函數(shù)只接受一個(gè)參數(shù)就是你要獲取ColorSpace的CGColorRef缸沃。CGColorRef cgColor = [UIColor redColor].CGColor; CGColorSpaceRef colorSpace = CGColorGetColorSpace(cgColor); NSLog(@"color space: %@", colorSpace);
-
獲取Color Components
要獲取到CGColorRef對(duì)應(yīng)的顏色值恰起,我們需要用到CGColorGetNumberOfComponents和CGColorGetComponents兩個(gè)函數(shù)。我們先來看看兩個(gè)函數(shù)的函數(shù)原型:size_t CGColorGetNumberOfComponents ( CGColorRef color ); const CGFloat * CGColorGetComponents ( CGColorRef color );
第一個(gè)函數(shù)是獲得CGColorRef的中包含的顏色組成部分的個(gè)數(shù)趾牧,第二個(gè)函數(shù)就是獲取實(shí)際的顏色組成部分的數(shù)組检盼。
NSUInteger num = CGColorGetNumberOfComponents(cgColor);
const CGFloat *colorComponents = CGColorGetComponents(cgColor);
for (int i = 0; i < num; ++i) {
NSLog(@"color components %d: %f", i, colorComponents[i]);
}
判斷兩個(gè)顏色是否相等
不管UIColor使用CIColor,CGColor還是其他方式初始化的翘单,其CGColor屬性都是可用的吨枉。CoreGraphics中提供一個(gè)方法可以判斷兩個(gè)CGColor是否相等,因此我們可以通過判斷兩個(gè)UIColor是否相等哄芜。
// judge two CGColor is equal
if (CGColorEqualToColor([UIColor whiteColor].CGColor, [UIColor colorWithRed:1 green:1 blue:1 alpha:1].CGColor)) {
NSLog(@"The two CGColor is equal!");
}
else {
NSLog(@"The two CGColor is not equal!");
}
if (CGColorEqualToColor([UIColor colorWithRed:1 green:1 blue:1 alpha:1].CGColor, [UIColor colorWithRed:1 green:1 blue:1 alpha:1].CGColor)) {
NSLog(@"The two CGColor is equal!");
}
else {
NSLog(@"The two CGColor is not equal!");
}
例子中第一部分是判斷兩個(gè)白色的UIColor是否相等貌亭,雖然都是白色,但是顏色空間是不一樣的认臊。例子的第二部分簡(jiǎn)單的創(chuàng)建了兩個(gè)RGB空間的UIColor圃庭,運(yùn)行程序可以看出,這兩種顏色是相同的失晴。