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 XcmsCIELuvQueryMaxC() gamut boundary
47 #define MAXBISECTCOUNT 100
48 #define EPS (XcmsFloat)0.001
49 #define START_CHROMA (XcmsFloat)2.2
50 #define TOPL (XcmsFloat)100.0
53 /************************************************************************
57 ************************************************************************/
61 * XcmsCIELuvQueryMaxC - max chroma for a hue_angle and L_star
68 XcmsFloat hue_angle, /* hue angle in degrees */
70 XcmsColor *pColor_return)
73 * Return the maximum chroma for a specific hue_angle and L_star.
74 * The returned format is in XcmsCIELuvFormat.
78 * This routine assumes that the white point associated with
79 * the color specification is the Screen White Point. The
80 * Screen White Point will also be associated with the
81 * returned color specification.
84 * XcmsFailure - Failure
85 * XcmsSuccess - Succeeded
92 XcmsFloat n_L_star, last_L_star, prev_L_star;
93 XcmsFloat hue, lastuStar, lastvStar, /*lastChroma,*/ maxDist, nT, rFactor;
95 int nCount, nMaxCount;
100 if (ccc == NULL || pColor_return == NULL) {
104 /* Use my own CCC and inherit screen white Pt */
105 memcpy ((char *)&myCCC, (char *)ccc, sizeof(XcmsCCCRec));
106 myCCC.clientWhitePt.format = XcmsUndefinedFormat;
107 myCCC.gamutCompProc = (XcmsCompressionProc)NULL;/* no gamut comp func */
109 while (hue_angle < 0.0) {
112 while (hue_angle >= 360.0) {
116 hue = radians(hue_angle);
117 tmp.spec.CIELuv.L_star = L_star;
118 tmp.spec.CIELuv.u_star = XCMS_CIEUSTAROFHUE(hue, START_CHROMA);
119 tmp.spec.CIELuv.v_star = XCMS_CIEVSTAROFHUE(hue, START_CHROMA);
120 tmp.pixel = pColor_return->pixel;
121 tmp.format = XcmsCIELuvFormat;
123 /* Step 1: compute the maximum L_star and chroma for this hue. */
124 memcpy((char *)&max_lc, (char *)&tmp, sizeof(XcmsColor));
125 if (_XcmsCIELuvQueryMaxLCRGB(&myCCC, hue, &max_lc, &rgb_saved)
131 * Step 2: Do a bisection here to compute the maximum chroma
132 * Note the differences between when the point to be found
133 * is above the maximum LC point and when it is below.
135 if (L_star <= max_lc.spec.CIELuv.L_star) {
136 maxDist = max_lc.spec.CIELuv.L_star;
138 maxDist = TOPL - max_lc.spec.CIELuv.L_star;
143 nMaxCount = MAXBISECTCOUNT;
146 for (nCount = 0; nCount < nMaxCount; nCount++) {
147 prev_L_star = last_L_star;
148 last_L_star = tmp.spec.CIELuv.L_star;
149 /* lastChroma = XCMS_CIELUV_PMETRIC_CHROMA(tmp.spec.CIELuv.u_star, */
150 /* tmp.spec.CIELuv.v_star); */
151 lastuStar = tmp.spec.CIELuv.u_star;
152 lastvStar = tmp.spec.CIELuv.v_star;
153 nT = (n_L_star - max_lc.spec.CIELuv.L_star) / maxDist * rFactor;
154 /* printf("(n_L_star, nT) = %lf %lf ", n_L_star, nT); */
156 tmp.spec.RGBi.red = rgb_saved.red * (1.0 - nT) + nT;
157 tmp.spec.RGBi.green = rgb_saved.green * (1.0 - nT) + nT;
158 tmp.spec.RGBi.blue = rgb_saved.blue * (1.0 - nT) + nT;
160 tmp.spec.RGBi.red = rgb_saved.red + (rgb_saved.red * nT);
161 tmp.spec.RGBi.green = rgb_saved.green + (rgb_saved.green * nT);
162 tmp.spec.RGBi.blue = rgb_saved.blue + (rgb_saved.blue * nT);
164 tmp.format = XcmsRGBiFormat;
166 /* convert from RGB to CIELuv */
167 if (_XcmsConvertColorsWithWhitePt(&myCCC, &tmp,
168 ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIELuvFormat,
169 (Bool *) NULL) == XcmsFailure) {
174 * Now check if we've reached the target L_star
176 /* printf("result Lstar = %lf\n", tmp.spec.CIELuv.L_star); */
177 if (tmp.spec.CIELuv.L_star <= L_star + EPS &&
178 tmp.spec.CIELuv.L_star >= L_star - EPS) {
179 memcpy((char *)pColor_return, (char *)&tmp, sizeof(XcmsColor));
183 n_L_star += ((TOPL - n_L_star) *
184 (L_star - tmp.spec.CIELuv.L_star)) / (TOPL - L_star);
186 n_L_star *= L_star / tmp.spec.CIELuv.L_star;
188 if (tmp.spec.CIELuv.L_star <= prev_L_star + EPS &&
189 tmp.spec.CIELuv.L_star >= prev_L_star - EPS) {
190 rFactor *= 0.5; /* selective relaxation employed */
191 /* printf("rFactor = %lf\n", rFactor); */
194 if (XCMS_FABS(last_L_star - L_star) <
195 XCMS_FABS(tmp.spec.CIELuv.L_star - L_star)) {
196 tmp.spec.CIELuv.u_star = lastuStar;
197 tmp.spec.CIELuv.v_star = lastvStar;
198 /* tmp.spec.CIELuv.u_star = XCMS_CIEUSTAROFHUE(hue, lastChroma); */
199 /* tmp.spec.CIELuv.v_star = XCMS_CIEVSTAROFHUE(hue, lastChroma); */
201 tmp.spec.CIELuv.L_star = L_star;
202 memcpy((char *)pColor_return, (char *)&tmp, sizeof(XcmsColor));