While creating profiles using different profile white points, I noticed a pattern that suggests a rounding error. For example, running the command "xicclu -ir -pl -s255 profile.icc" on the following 7 profiles produces these results:
Apple-CCT 100.000000 -0.002638 0.000000 Apple-D65code 100.000000 0.000000 0.000000 perfect CIE-RGB-CCT 100.000000 0.000000 0.001233 CIE-RGB-E_5454K 100.000000 0.000000 0.001233 Clay-CCT 100.000000 -0.002638 0.001233 Clay-D65_old 100.000000 0.000000 0.001233 NTSC-CCT 100.000000 0.000000 0.001233 NTSC-C_6774K 100.000000 0.000000 0.001233 SMPTE-CCT 100.000000 0.000000 -0.001233 SMPTE-D65_old 100.000000 -0.002638 0.001233 sRGB-CCT 99.999410 0.002543 -0.001017 sRGB-D65code 100.000000 0.000000 0.001233 Widegamut-CCT 100.000590 -0.005181 0.001017 Widegamut-D50_lcms 100.000000 0.000000 0.001233 Profile white point key: "CCT" = lcms correlated color temp; I used 6503.6 for D65. D65code = (0.31271, 0.32912) E_5454K = (0.333608970, 0.348572909) Robertson equations D65_old = (0.312700, 0.329000) C_6774K = (0.308548930, 0.324928102) Robertson equations D50_lcms = (0.345702915, 0.358538597) In the profiles above, the value +/- 0.001233 shows up ten times over a diverse set of profile white points. Including results from other profiles, 0.002543, 0.001017 and 0.002638 also show up multiple times, though not as frequently as 0.001233. For R=G=B=255, no deviation from 0 in the Lab "a" channel plus a deviation of 0.001233 in the Lab "b" channel corresponds to a deviation of 0.000015 (+0.001233) or 0.000016 (-0.001233) in the Z XYZ channel (the X value deviation is 0 in either case). The values "0.000015" and "0.000016" are important numbers when converting from XYZ to hexadecimal: 0.000015 (and any smaller value), multiplied by 65535 and converted to hex, is 0. 0.000016, multiplied by 65535 and converted to hex, is 1. This might be purely coincidental, but it suggests a decimal to hexadecimal rounding error. So I looked for a possible source of a "1 hex unit" error and perhaps found one. The following lines are in the "lcms2.h" file: // D50 XYZ normalized to Y=1.0 #define cmsD50X 0.9642 #define cmsD50Y 1.0 #define cmsD50Z 0.8249 Using these cmsD50X and cmsD50Z values, here's the round-trip conversion through hex: starting values: (0.964200000, 1.0, 0.824900000) convert to hex: (F6D4, FFFF, D32B) convert back to decimal: (0.964187076, 1.0, 0.824887465) absolute difference: (0.000012924, 0.0, 0.000012535) According to iccToXml, for profiles generated by lcms the profile header illuminant value is (0.964202881, 1, 0.824905396). The corresponding round-trip conversion through hex values are: starting values: (0.964202881, 1.0, 0.824905396) convert to hex: (F6D5, FFFF, D32C) convert back to decimal: (0.824902724, 1.0, 0.964202335) absolute difference: (0.000000546, 0.0, 0.000002672) Notice that the iccToXml illuminant values convert to hex and back with a smaller error, and also the resulting hex values are larger by 1 hex unit (F6D4->F6D5, D32B->D32C). So what happens if the D50 XYZ values in lcms2.h are changed to match the iccToXml illuminant values? // D50 XYZ normalized to Y=1.0 #define cmsD50X 0.96420288 //iccToXml header illuminant value #define cmsD50Y 1.0 #define cmsD50Z 0.82490540 //iccToXml header illuminant value To find out, I *Changed the D50 values in lcms2.h to equal the header illuminant value reported by iccToXml *Recompiled lcms *Recompiled my profile-making code *Recreated all the profiles using the exact same white points as before Here are the new xicclu results: Apple-mod-CCT 100.000000 0.002638 0.000000 flipped sign Apple-mod-D65code 100.000000 0.000000 0.000000 perfect CIE-RGB-mod-CCT 100.000000 0.000000 0.000000 perfect CIE-mod-RGB-E_5454 100.000000 0.000000 0.000000 perfect Clay-mod-CCT 100.000000 0.000000 0.001233 improved Clay-mod-D65_old 100.000000 0.000000 0.000000 perfect NTSC-mod-CCT 100.000000 0.000000 0.000000 perfect NTSC-mod-C_6774 100.000000 0.000000 0.000000 perfect SMPTE-mod-CCT 100.000000 0.000000 -0.001233 no change SMPTE-mod-D65_old 100.000000 0.000000 0.000000 perfect sRGB-mod-CCT 99.999410 0.002543 -0.001017 no change sRGB-mod-D65code 100.000000 0.000000 0.000000 perfect Widegamut-mod-CCT 100.000590 -0.005181 0.001017 no change Widegamut-mod-D50_lcms 100.000000 0.000000 0.000000 perfect I've checked many more profiles than are listed above, and the results are 100% consistent. "Color balanced" isn't everything! I checked all the profiles against the Lindbloom xyY values by calculating the sum of the absolute differences in the x,y,Y values for the red, blue, and green channels. In most cases, the profiles produced by the modified lcms2.h file are slightly closer to the Lindbloom values than the profiles produced by the unmodified lcms2.h file. Widegamut and CIE-RGB values are slightly farther away. In all cases the change is very small. So if you actually had the patience to read all the way through this post, does it look like there might be something in the lcms source code that is systematically introducing small rounding errors that are independent of the profile white point? Elle ------------------------------------------------------------------------------ Learn the latest--Visual Studio 2012, SharePoint 2013, SQL 2012, more! Discover the easy way to master current and previous Microsoft technologies and advance your career. Get an incredible 1,500+ hours of step-by-step tutorial videos with LearnDevNow. Subscribe today and save! http://pubads.g.doubleclick.net/gampad/clk?id=58040911&iu=/4140/ostg.clktrk _______________________________________________ Lcms-user mailing list Lcms-user@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/lcms-user