The distinction between iOS's UIColor class and its associated classes and the method for judging equality

  • 2020-05-12 06:15:47
  • OfStack

Differences and connections between UIColor, CGColor, CIColor3

Recently, I looked at CoreGraphics and saw something about CGColor, so I thought to look at UIColor and CIColor by the way and figure out the differences and connections between them. Let's take a look at each of these three concepts:

1. UIColor

UIColor is an important class for storing color information in UIKit. An UIColor object contains values for color and transparency. Its color space has been optimized for IOS. UIColor contains a number of class methods for creating the most common colors, such as white, black, red, transparent, etc., which also have different color Spaces (kCGColorSpaceDeviceGray for white and black, kCGColorSpaceDeviceRGB for red).

In addition, UIColor has two important properties: 1 is CGColor and 1 is CIColor(added after 5.0). These two properties can connect UIColor, CGColor and CIColor objects, and the conversion between these three objects will be described in detail later.



2. CGColor

CGColor is mainly used in the CoreGaphics framework. CGColor is actually a structure, while we usually use CGColor with its reference type CGColorRef. CGColor is mainly composed of CGColorSapce and Color Components. If the color space is different, the result may be different. This is just like when we are processing image data, if the RGBA format as BGRA format processing results can be expected. In Quartz 2D, CGColor is often used to set the fill color of context, set the transparency, etc.

1. How to create an CGColor? The most commonly used function is CGColorCreate, which has two parameters:

1) colorspace, specify the corresponding color space of CGColor, Quartz will retain this object, so you can safely release this object after calling it.

2) components, an array of CGFloat, the number of elements of which 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, which is released by the CGColorRelease function when we no longer use the object.

2. Get the data of CGColor

We pass in two important parameters when we create it, and when we get CGColorRef, of course we can get the corresponding ColorSpace and Components.

1) obtain ColorSpace

We can get the ColorSpace corresponding to the current CGColorRef through the CGColorGetColorSpace function, which only accepts one parameter, that is, you want to get the CGColorRef of ColorSpace. Here's 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 of CGColorRef, we need to use the functions CGColorGetNumberOfComponents and CGColorGetComponents. Let's look at the function prototype of two functions:


size_t CGColorGetNumberOfComponents (
   CGColorRef color
); const CGFloat * CGColorGetComponents (
   CGColorRef color
);


The first function is to get the number of color components contained in CGColorRef. The second function is to get the array of actual color components. Here is 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 for other classes in the Core Image framework, such as CIFilter, CIContext, and CIImage. Today we are mainly concerned with the color value part. The color value in CIColor ranges from 0.0 to 1.0, 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, with 0.0 representing full transparency and 1.0 representing total opacity, and the color component of CIColor is usually not multiplied by the alpha value.

We can use the initWithCGColor: function to create an CIColor using CGColor. Where the incoming CGColorRef object can make any color space, but the Core Image framework converts all color Spaces to the core image working color space before passing filter kernel. The core image working color space consists of three color components plus one alpha component (kCGColorSpaceDeviceRGB), which we will verify in the following example.



4. Differences and connections between UIColor, CGColor, CIColor

1. Two properties of UIColor, CGColor and CIColor

UIColor's CGColor is always valid, whether it is created by CGColor, CIColor, or some other method, the CGColor property is always valid; However, the CIColor property is not always valid. It is only valid if UIColor is created through CIColor. Otherwise, accessing the property will throw an exception.


// 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


2. UIColor is initialized with CGColor

When UIColor is initialized with CGColor, all the information contained in CGColorRef will be retained intact, including Color space. Besides, we can also see from the following small example that if CGColor is used to initialize UIColor, UIColor actually directly retains a copy of the 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: %@", color.CGColor);


3. UIColor is initialized with CIColor

Next, we will discuss 1. When using CIColor to initialize 1 UIColor, and then accessing UIColor's CGColor property, we will find that color Space of CGColor and CIColor color space are incomplete, and CIColor will do a conversion for us in this process. Next, when we use kCGColorSpaceDeviceGray, kCGColorSpaceDeviceRGB, kCGColorSpaceDeviceCMYK three color Spaces to initialize an CIColor, we will use CIColor to initialize an UIColor, and then visit its CIColor genus and CGColor properties to view the color space and print the color information.

1) initialize CIColor with 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: %@", 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);


Through running the program, we see that if you use a CGColor kCGColorSpaceDeviceGray color space to initialize the CIColor, we can see the color space of CIColor 1 straight is kCGColorSpaceDeviceGray, by visiting UIColor CIColor attributes, we can see the color space is still a kCGColorSpaceDeviceGray, but when visiting UIColor CGColor attribute by print can be found that the color space has been transformed kCGColorSpaceDeviceRGB space, And the color value is also correctly converted from the original color space to the new color space.

2) initialize CIColor with kCGColorSpaceDeviceRGB

Similarly, let's look at the code:


 //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);


All the way through CIColor, and the values accessed through CGColor and CIColor properties of UIColor, we can print them out and find that they are all in kCGColorSpaceDeviceRGB space.

4. Initialize CIColor using kCGColorSpaceDeviceCMYK

Here's another 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: %@", 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);


During the whole process, we can also find through running that when we initialize CIColor with CGColor of 1 CMYK color space, the color space of CIColor is still CMYK, but the color value has been converted to RGB color value. When using CIColor to create an UIColor, and printing information through CIColor and CGColor properties, we will find that the color space of CIColor is still CMYK, but the information obtained by printing CGColor indicates that it has been converted to RGB space.



5. UIColor extension, how to determine if two colors are equal

As mentioned above, the CGColor property of UIColor is available whether it is initialized using CIColor, CGColor or otherwise. A method is provided in CoreGraphics to judge whether two CGColor are equal or not. Therefore, we can judge whether two UIColor are equal or not. 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 of the example is to judge whether the two white UIColor are equal or not. Although they are both white, the color space is not the same. Through running, we can find that "The two CGColor is not equal! . Part 2 of the example simply creates UIColor for two RGB Spaces. Running the program shows that the two colors are the same.

Determine if the color values of two UIColor are equal
Two days ago, a friend asked me how to judge whether the values of two colors are equal to each other. I think it will be ok to judge whether the values of RGBA of two colors are equal to each other soon. So I began to search for help documents and found the UIColor class.


- (BOOL)getRed:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)alpha;

In this way, we can judge whether the colors of the two UIColor objects are the same or not. The code is as follows:

size_t CGColorGetNumberOfComponents (
   CGColorRef color
); const CGFloat * CGColorGetComponents (
   CGColorRef color
);
0


Related articles: