P3 Display to XYZ Color Space Conversion

When I use the ColorSync Utility to convert Display P3 color (1, 0, 0) to an XYZ color, the result is (0.5151, 0.2412, -0.0011). I expected that result because that is identical to the red colorant tristimulus value in the Display P3.icc file.


When I use the CGColor converted method to do the same, the XYZ color is approximately (0.5151, 0.2412, 0.0). Note that the third element is 0.0 whereas it is -0.0011 when using the ColorSync Utility. I have printed out the Z component to 16 digits of precision, and Z is all 0s. It appears that the CGColor converted method is clamping the result from 0 to 1.


My questions are:


1. Which conversion is correct? The ColorSync utility or the CGColor converted method?


2. I am not a color specialist, but I thought that the XYZ components should never be negative. If so, is the colorant tristimulus value in the Display P3.icc file wrong?


3. Because CGColor clamped the Z component to 0, the XYZ color cannot be converted back exactly or closely to the Display P3 color (1, 0, 0). I would have expected to be able to go back and forth between the two color spaces when starting from a valid P3 Display color especially since the XYZ color space completely encompasses the P3 Display color space. Is that not true?


4. Is (1, 0, 0) an invalid Display P3 color? If so, I can understand the peculiar results. I'm not sure how I would know if a Display P3 color is valid or not. (I only know that the component values must be from 0 to 1.) I think it is valid because Apple uses that color in the UIColor API Reference in an example.

Accepted Answer

Hello. Came across this posting looking for some colour details pertaining to the Apple P3 displays.


> 1. Which conversion is correct? The ColorSync utility or the CGColor converted method?


Depends on what you mean by correct. Having just rolled my own set of matrices unadapted and left at D65, the quantisation limits of hexadecimal in the ICC might provide some explanation. Technically the negative value is the "correct" byproduct of the values encoded in the ICC. The issue is likely from the small non-zero and negative value for one of the XYZ positions of the primaries. If I had to speculate, Apple was using ICC based calculations, which revolve around a D50 PCS and forgot to deal with hexadecimal rounding. As a result, when they round tripped the values back to the illuminant relative XYZ, they ended up with a small negative value for the Z coordinate due to using specification white point versus the actual hexadecimal value. The actual hexadecimal values from the ICC profile are as follows, with an interesting note that the PCS illuminant for D50 seems off by a value compared to most standard implementations:

PCS Illuminant White:
0000f6d6
00010000
0000d32d

White:
0000f316
00010000
000116ca

Red:
00008387
00003da9
ffffffbb

Green:
00004be5
0000b3ef
00000add

Blue:
0000276a
00000e68
0000c895


> 2. I am not a color specialist, but I thought that the XYZ components should never be negative. If so, is the colorant tristimulus value in the Display P3.icc file wrong?


XYZ covers the entire standard observer spectral locus, and as a result, values should never be negative. Again, this is very likely a result of hexadecimal quantisation.


> 3. Because CGColor clamped the Z component to 0, the XYZ color cannot be converted back exactly or closely to the Display P3 color (1, 0, 0). I would have expected to be able to go back and forth between the two color spaces when starting from a valid P3 Display color especially since the XYZ color space completely encompasses the P3 Display color space. Is that not true?


You could easily go back and forth between two colour spaces using a 3x3 matrix and the values provided. The clamped version would of course yield incorrect results as compared to the quantised hexidecimal values provided in the ICC.


> 4. Is (1, 0, 0) an invalid Display P3 color? If so, I can understand the peculiar results. I'm not sure how I would know if a Display P3 color is valid or not. (I only know that the component values must be from 0 to 1.) I think it is valid because Apple uses that color in the UIColor API Reference in an example.


It's valid; it represents the red Apple P3 emitter at the transfer characteristic of the encoded value, which happens to end up being 1.0. The issue is more in the abstract math quantisation domain due to the limits of precision in hexadecimal and the need to exchange between the CIE 1931 XYZ model.


With respect,

TJS

Thanks for your detailed anwswer. It's claried all the issues for me.


Also, I was having a problem with OpenGL ES shader code that converted Display P3 colors to/from the Lab and IPT color spaces. In particular, my results did not match the ColorSync Utility when converting Display P3 to/from Lab. Your mention of D50 caused me to use that reference rather than D65 and now my results match. Switching to D50 also corrected the IPT results.


Thanks again!

P3 Display to XYZ Color Space Conversion
 
 
Q