The difference and connection between UIColor, CGColor, and CIColor
I recently looked at CoreGraphics stuff and saw something about CGColor, so I thought about taking a look at UIColor, CIColor, and figuring out the differences and connections between them. Let's take a look at the three concepts:
1. UIColor
UIColor is an important class in UIKit that stores color information. A UIColor object contains the values of color and transparency, and its color space has been optimized for IOS. UIColor contains some class methods for creating some of the most common colors, such as white, black, red, transparent colors, etc. The color spaces of these colors are also different (white and black are kCGColorSpaceDeviceGray, and the color space of red is kCGColorSpaceDeviceRGB).
In addition, UIColor has two important properties: one is CGColor and the other is CIColor (added after 5.0). These two properties can connect the three objects of UIColor, CGColor, and CIColor. The conversion between these three will be described in detail later.
2. CGColor
CGColor is mainly used in the CoreGaphics framework. CGColor is actually a structure, and we usually use its reference type CGColorRef when using CGColor. CGColor is mainly composed of two parts: CGColorSapce and Color Components. The same color is composed of. If the color space is different, the parsed results may be different. This is just like when we process image data, we can imagine the results of treating RGBA format as BGRA format. In Quartz 2D, CGColor is often used to set the fill color of the context, set transparency, etc.
1. How to create a CGColor. The most commonly used function is CGColorCreate. This function has two parameters:
1) colorspace, specify the color space corresponding to CGColor, and Quartz will retain the object, so you can safely release the object after the call.
2) components, an array of CGFloats, the number of elements in the array is the number of color components n contained in the specified color space, plus the corresponding alpha value.
This function should return a newly created CGColorRef. When we no longer use the object, we use the CGColorRelease function to release the object.
2. Obtain CGColor data
When we create, we pass in two important parameters. When we get CGColorRef, we can of course get the corresponding ColorSpace and Components.
1) Get ColorSpace
Through the CGColorGetColorSpace function, we can get the ColorSpace corresponding to the current CGColorRef. This function only accepts one parameter, which is that you want to get the ColorSpace's CGColorRef. Here is a simple example:
CGColorRef cgColor = [UIColor redColor].CGColor;
CGColorSpaceRef colorSpace = CGColorGetColorSpace(cgColor);
NSLog(@"color space: %@", colorSpace);
2) Get Color Components
To get the color value corresponding to CGColorRef, we need to use two functions: CGColorGetNumberOfComponents and CGColorGetComponents. Let's first look at the function prototypes of two functions:
size_t CGColorGetNumberOfComponents (
CGColorRef color
);
const CGFloat * CGColorGetComponents (
CGColorRef color
);
The first function is to obtain the number of color components contained in CGColorRef, and the second function is to obtain the array of actual color components. Let's see a small example:
NSUInteger num = CGColorGetNumberOfComponents(cgColor);
const CGFloat *colorComponents = CGColorGetComponents(cgColor);
for (int i = 0; i < num; ++i) {
NSLog(@"color components %d: %f", i, colorComponents[i]);
}
3. CIColor
CIColor is mainly used with other classes in the Core Image framework, such as CIFilter, CIContext and CIImage. Today, the color value part we are mainly concerned about is the range of color values in CIColor between 0.0 and 1.0.0 means that the color component is the minimum value, and 1.0 means that the color component is the maximum value. The range of alpha values is also between 0.0 and 1.0, 0.0 means fully transparent, 1.0 means completely opaque, and CIColor's color components are usually not multiplied by the alpha value.
We can use the initWithCGColor: function to create a CIColor through CGColor. The incoming CGColorRef object can make any color space, but the Core Image framework will convert all color spaces to the core image working color space before passing in the filter kernel. The core image working color space uses three color components plus an alpha component (actually kCGColorSpaceDeviceRGB). In the following example, we verify this.
4. The difference and connection between UIColor, CGColor, and CIColor
1. Two attributes of UIColor CGColor, CIColor
UIColor's CGColor is always valid. Whether it is created through CGColor, CIColor, or other methods, the CGColor attribute is always valid; but the CIColor attribute is not always valid. It is only valid when UIColor is created through CIColor, otherwise an exception will be thrown when accessing the property. Here is a small example:
// test init uicolor with CGColor
UIColor *color = [UIColor colorWithCGColor:[UIColor whiteColor].CGColor];
// CGColor property is always valid
NSLog(@"CGColor from UIColor %@", );
// 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 %@", ); // crush
2. UIColor is initialized using CGColor
When UIColor is initialized using CGColor, all the information contained in CGColorRef will be retained intact, including Color space. And through the following small examples, we can also see that if UIColor is initialized using CGColor, UIColor actually directly retains a CGColorRef object. Examples are as follows:
// 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: %@", );
3. UIColor is initialized using CIColor
Let’s discuss below that when using CIColor to initialize a UIColor and then accessing the CGColor property of UIColor, we will find that the color space of CGColor is not exactly the same as the color space of CIColor. In this process, CIColor will make a conversion for us. Let's take a look at the three color spaces of kCGColorSpaceDeviceGray, kCGColorSpaceDeviceRGB, and kCGColorSpaceDeviceCMYK to initialize a CIColor, then use the CIColor to initialize a UIColor, and then access its CIColor attributes and CGColor attributes, view the color space and print the color information.
1) Initialize CIColor using kCGColorSpaceDeviceGray
First look at the code:
// test kCGColorSpaceDeviceGray
NSLog(@"CGColor white color:%@", [UIColor whiteColor].CGColor);
CIColor *ciColor = [CIColor colorWithCGColor:[UIColor whiteColor].CGColor];
NSLog(@"cicolor: %@", ciColor);
NSLog(@"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: %@", );
NSLog(@"cicolor's colorspace: %@", );
NSLog(@"color's CGColor: %@", );
By running the program, we can see that if we use a CGColor of the color space of the kCGColorSpaceDeviceGray to initialize the CIColor, we can see that the color space of the CIColor has always been kCGColorSpaceDeviceGray. By accessing the CIColor property of the UIColor, we can see that its color space is still kCGColorSpaceDeviceGray, but when accessing the CGColor property of the UIColor, we can find that its color space has been converted into a kCGColorSpaceDeviceRGB space, and the color value is correctly converted from the original color space to the new color space.
2) Initialize CIColor using kCGColorSpaceDeviceRGB
Let's look at the code the same:
//test kCGColorSpaceDeviceRGB
NSLog(@"CGColor red color:%@", [UIColor redColor].CGColor);
CIColor *ciColor = [CIColor colorWithCGColor:[UIColor redColor].CGColor];
NSLog(@"cicolor: %@", ciColor);
NSLog(@"cicolor colorspace: %@", );
UIColor *color = [UIColor colorWithCIColor:ciColor];
NSLog(@"color %@", color);
NSLog(@"cicolor from UIColor: %@", );
NSLog(@"cicolor's colorspace: %@", );
NSLog(@"color's CGColor: %@", );
During the whole process, the values accessed through the CGColor and CIColor properties of UIColor, we can print them and find that they are all kCGColorSpaceDeviceRGB space.
4. Initialize CIColor using kCGColorSpaceDeviceCMYK
Let's continue to see a piece of code:
// 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: %@", );
color = [UIColor colorWithCIColor:ciColor];
NSLog(@"UIColor with CIColor: %@", color);
NSLog(@"cicolor from UIColor: %@", );
NSLog(@"cicolor's colorspace: %@", );
// when UIColor init with CIColor, UIColor's CGColor will convert other colorspace to kCGColorSpaceDeviceRGB
NSLog(@"cgcolor from UIColor: %@", );
During the whole process, we can also find that when we use a CGColor of CMYK color space to initialize CIColor, the color space of CIColor is still CMYK, but the color value has been converted to RGB color value. When we use this CIColor to create a UIColor, when we print information through the CIColor and CGColor properties, we will find that the color space of CIColor is still CMYK, but the information obtained by printing CGColor means that it has been converted into RGB space.
5. UIColor extension, how to determine whether two colors are equal
As mentioned earlier, whether UIColor is initialized using CIColor, CGColor or other methods, its CGColor attribute is available. CoreGraphics provides a method to determine whether two CGColors are equal, so we can judge whether two UIColors are equal. Here is a simple example:
// 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!");
}
The first part in the example is to determine whether the two white UIColors are equal. Although they are both white, the color space is different. By running, we can find that "The two CGColor is not equal!" is printed. The second part of the example simply creates two RGB space UIColors, which can be seen by running the program that the two colors are the same.
Determine whether the color values of the two UIColors are equal
Two days ago, a friend asked me how to determine whether the values of two colors are equal. I thought it would be fine just to determine whether the RGBA values of the two colors are equal soon. So I started to search for the help document and found the UIColor class, which was easy to find the function:
- (BOOL)getRed:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)alpha;
This way, you can determine whether the colors of the two UIColor objects are equal. The code is as follows:
enum {
enEqual,
enNotEaual,
enCannotConvert,
};
typedef NSInteger KCompareResult;
+ (KCompareResult) isTheSameColor:(UIColor*)color
redValue:(CGFloat)rValue
greenValue:(CGFloat)gValue blueValue:(CGFloat)bValue
alphaValue:(CGFloat)aValue
{
if ([color respondsToSelector:@selector(getRed:green:blue:alpha:)]) {
CGFloat redValue, greenValue, blueValue, alphaValue;
if ([color getRed:&redValue green:&greenValue blue:&blueValue alpha:&alphaValue]) {
if (redValue == rValue && greenValue == gValue && blueValue == bValue && alphaValue == aValue) {
return enEqual;
}
else {
return enNotEaual;
}
}
else { // can not convert
return enCannotConvert;
}
}
}