3 * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc.
6 * This file is a component of an X Window System-specific implementation
7 * of XCMS based on the TekColor Color Management System. Permission is
8 * hereby granted to use, copy, modify, sell, and otherwise distribute this
9 * software and its documentation for any purpose and without fee, provided
10 * that this copyright, permission, and disclaimer notice is reproduced in
11 * all copies of this software and in supporting documentation. TekColor
12 * is a trademark of Tektronix, Inc.
14 * Tektronix makes no representation about the suitability of this software
15 * for any purpose. It is provided "as is" and with all faults.
17 * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE,
18 * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19 * PARTICULAR PURPOSE. IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY
20 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
21 * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF
22 * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
23 * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE.
31 * Source for the XcmsCIELabQueryMaxLC() gamut boundary
35 * "TekColor Color Management System, System Implementor's Manual"
37 * Fred W. Billmeyer & Max Saltzman, "Principles of Color
38 * Technology", John Wily & Sons, Inc, 1981.
51 #define MIN(x,y) ((x) > (y) ? (y) : (x))
52 #define MIN3(x,y,z) ((x) > (MIN((y), (z))) ? (MIN((y), (z))) : (x))
53 #define MAX(x,y) ((x) > (y) ? (x) : (y))
54 #define MAX3(x,y,z) ((x) > (MAX((y), (z))) ? (x) : (MAX((y), (z))))
55 #define START_LSTAR (XcmsFloat)40.0
56 #define START_CHROMA (XcmsFloat)3.6
59 /************************************************************************
61 * API PRIVATE ROUTINES *
63 ************************************************************************/
67 * _XcmsCIELabQueryMaxLCRGB - Compute maximum L* and chroma.
72 _XcmsCIELabQueryMaxLCRGB(
74 XcmsFloat hue, /* hue in radians */
75 XcmsColor *pColor_return,
76 XcmsRGBi *pRGB_return)
79 * Return the maximum psychometric chroma for a specified
80 * hue, and the corresponding L*. This is computed
81 * by a binary search of all possible chromas. An assumption
82 * is made that there are no local maxima. Use the unrounded
83 * Max psychometric chroma because the difference check can be
86 * NOTE: No local CCC is used because this is a private
87 * routine and all routines that call it are expected
88 * to behave properly, i.e. send a local CCC with
89 * no white adjust function and no gamut compression
92 * This routine only accepts hue in radians as input and outputs
96 * XcmsFailure - Failure
97 * XcmsSuccess - Succeeded
101 XcmsFloat nSmall, nLarge;
104 tmp.format = XcmsCIELabFormat;
105 /* Use some unreachable color on the given hue */
106 tmp.spec.CIELab.L_star = START_LSTAR;
107 tmp.spec.CIELab.a_star = XCMS_CIEASTAROFHUE(hue, START_CHROMA);
108 tmp.spec.CIELab.b_star = XCMS_CIEBSTAROFHUE(hue, START_CHROMA);
110 * Convert from Lab to RGB
112 * Note that the CIEXYZ to RGBi conversion routine must stuff the
113 * out of bounds RGBi values in tmp when the ccc->gamutCompProc
116 if ((_XcmsConvertColorsWithWhitePt(ccc, &tmp, ScreenWhitePointOfCCC(ccc),
117 (unsigned int)1, XcmsRGBiFormat, (Bool *) NULL)
118 == XcmsFailure) && tmp.format != XcmsRGBiFormat) {
119 return (XcmsFailure);
122 /* Now pick the smallest RGB */
123 nSmall = MIN3(tmp.spec.RGBi.red,
126 /* Make the smallest RGB equal to zero */
127 tmp.spec.RGBi.red -= nSmall;
128 tmp.spec.RGBi.green -= nSmall;
129 tmp.spec.RGBi.blue -= nSmall;
131 /* Now pick the largest RGB */
132 nLarge = MAX3(tmp.spec.RGBi.red,
135 /* Scale the RGB values based on the largest one */
136 tmp.spec.RGBi.red /= nLarge;
137 tmp.spec.RGBi.green /= nLarge;
138 tmp.spec.RGBi.blue /= nLarge;
139 tmp.format = XcmsRGBiFormat;
141 /* If the calling routine wants RGB value give them the ones used. */
143 pRGB_return->red = tmp.spec.RGBi.red;
144 pRGB_return->green = tmp.spec.RGBi.green;
145 pRGB_return->blue = tmp.spec.RGBi.blue;
148 /* Convert from RGBi to Lab */
149 if (_XcmsConvertColorsWithWhitePt(ccc, &tmp,
150 ScreenWhitePointOfCCC(ccc), 1, XcmsCIELabFormat, (Bool *) NULL)
152 return (XcmsFailure);
155 memcpy((char *)pColor_return, (char *)&tmp, sizeof(XcmsColor));
156 return (XcmsSuccess);
160 /************************************************************************
164 ************************************************************************/
168 * XcmsCIELabQueryMaxLC - Compute maximum L* and chroma.
173 XcmsCIELabQueryMaxLC (
175 XcmsFloat hue_angle, /* hue_angle in degrees */
176 XcmsColor *pColor_return)
180 * Return the point of maximum chroma for the specified
184 * This routine assumes that the white point associated with
185 * the color specification is the Screen White Point. The
186 * Screen White Point will also be associated with the
187 * returned color specification.
190 * XcmsFailure - Failure
191 * XcmsSuccess - Succeeded
200 if (ccc == NULL || pColor_return == NULL) {
205 memcpy ((char *)&myCCC, (char *)ccc, sizeof(XcmsCCCRec));
206 myCCC.clientWhitePt.format = XcmsUndefinedFormat;
207 myCCC.gamutCompProc = (XcmsCompressionProc)NULL;
209 while (hue_angle < 0.0) {
212 while (hue_angle >= 360.0) {
216 return(_XcmsCIELabQueryMaxLCRGB (&myCCC, radians(hue_angle), pColor_return,