In Quartz 2D, the CGColorSpaceCreateLab()
function takes a range
parameter defined as follows:
CGFloat range[4]: An array of 4 numbers that specify the range of valid values for the a* and b* components of the color space. The a* component represents values running from green to red, and the b* component represents values running from blue to yellow.
The question is, what does this parameter actually do?
I can think of at least three possible scenarios.
Option 1: Maybe it scales the component values
Say I have two color spaces with different ranges:
CGFloat range1[] = { -10, 10, -10, 10 };
CGFloat range2[] = { -100, 100, -100, 100 };
CGColorSpaceRef space1 = CGColorSpaceCreateLab(whitePoint, blackPoint, range1);
CGColorSpaceRef space2 = CGColorSpaceCreateLab(whitePoint, blackPoint, range2);
I create colors with the same component values and within the specified range of each space:
CGFloat components[] = { 50, 10, 10, 1 };
CGColorRef color1 = CGColorCreate(space1, components);
CGColorRef color2 = CGColorCreate(space2, components);
Do color1
and color2
represent the same color? Or does the range
parameter scale the components in some way, making these two different colors? (If the latter, what value for range
corresponds to the standard CIELAB coordinate scaling?
Option 2: Maybe it clips the component values
Given the two spaces defined above, say I create the following colors instead:
CGFloat components[] = { 50, 50, 50, 1 };
CGColorRef color1 = CGColorCreate(space1, components);
CGColorRef color2 = CGColorCreate(space2, components);
Now do color1
and color2
represent the same color? Or does the range
parameter clip the components of color1
to { 50, 10, 10, 1 }? (If the latter, what's the point? An extremely rough approximation of a gamut definition? Making sure values stay within a range compatible with another data type?)
Option 3: Maybe it's used elsewhere, like when doing gamut mapping with a perceptual rendering intent
Having some idea of the range of L*a*b* values to expect might assist with gamut mapping, particularly in the perceptual case, but again, this seems like such a rough approximation that I don't see why it would be particularly useful.
Option 4: Something else?
I did some testing, and it looks like the answer is:
The range
parameter scales the a* and b* component values.
Also, the component values do not appear to be clipped to the specified range.
So in the following example:
CGFloat range1[] = { -10, 10, -10, 10 };
CGFloat range2[] = { -100, 100, -100, 100 };
CGColorSpaceRef space1 = CGColorSpaceCreateLab(whitePoint, blackPoint, range1);
CGColorSpaceRef space2 = CGColorSpaceCreateLab(whitePoint, blackPoint, range2);
CGFloat components1[] = { 50, 10, 10, 1 };
CGColorRef color1 = CGColorCreate(space1, components1);
CGFloat components2[] = { 50, 100, 100, 1 };
CGColorRef color2 = CGColorCreate(space2, components2);
CGColorRef color3 = CGColorCreate(space1, components2);
color1
and color2
represent the same color.color3
appears to retain the specified component values, even though they're outside the range specified by the color space.Finally, it looks like a range specification of { -127, 127, -127, 127 } results in a color space with the standard CIELAB scales for the a* and b* axes.
If anyone has a more authoritative answer, please post!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With