views:

329

answers:

1

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?

+1  A: 

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!

SWB