1
2 /*
3 * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc.
4 * All Rights Reserved
5 *
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.
13 *
14 * Tektronix makes no representation about the suitability of this software
15 * for any purpose. It is provided "as is" and with all faults.
16 *
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.
24 *
25 *
26 *
27 * NAME
28 * CIELabMxVC.c
29 *
30 * DESCRIPTION
31 * Source for the XcmsCIELabQueryMaxLC() gamut boundary
32 * querying routine.
33 *
34 * DOCUMENTATION
35 * "TekColor Color Management System, System Implementor's Manual"
36 * and
37 * Fred W. Billmeyer & Max Saltzman, "Principles of Color
38 * Technology", John Wily & Sons, Inc, 1981.
39 */
40
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif
44 #include "Xlibint.h"
45 #include "Xcmsint.h"
46 #include "Cv.h"
47
48 /*
49 * DEFINES
50 */
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
57
58
59 /************************************************************************
60 * *
61 * API PRIVATE ROUTINES *
62 * *
63 ************************************************************************/
64
65 /*
66 * NAME
67 * _XcmsCIELabQueryMaxLCRGB - Compute maximum L* and chroma.
68 *
69 * SYNOPSIS
70 */
71 Status
_XcmsCIELabQueryMaxLCRGB(XcmsCCC ccc,XcmsFloat hue,XcmsColor * pColor_return,XcmsRGBi * pRGB_return)72 _XcmsCIELabQueryMaxLCRGB(
73 XcmsCCC ccc,
74 XcmsFloat hue, /* hue in radians */
75 XcmsColor *pColor_return,
76 XcmsRGBi *pRGB_return)
77 /*
78 * DESCRIPTION
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
84 * small.
85 *
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
90 * function.
91 *
92 * This routine only accepts hue in radians as input and outputs
93 * Lab and RGBi.
94 *
95 * RETURNS
96 * XcmsFailure - Failure
97 * XcmsSuccess - Succeeded
98 *
99 */
100 {
101 XcmsFloat nSmall, nLarge;
102 XcmsColor tmp;
103
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);
109 /*
110 * Convert from Lab to RGB
111 *
112 * Note that the CIEXYZ to RGBi conversion routine must stuff the
113 * out of bounds RGBi values in tmp when the ccc->gamutCompProc
114 * is NULL.
115 */
116 if ((_XcmsConvertColorsWithWhitePt(ccc, &tmp, ScreenWhitePointOfCCC(ccc),
117 (unsigned int)1, XcmsRGBiFormat, (Bool *) NULL)
118 == XcmsFailure) && tmp.format != XcmsRGBiFormat) {
119 return (XcmsFailure);
120 }
121
122 /* Now pick the smallest RGB */
123 nSmall = MIN3(tmp.spec.RGBi.red,
124 tmp.spec.RGBi.green,
125 tmp.spec.RGBi.blue);
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;
130
131 /* Now pick the largest RGB */
132 nLarge = MAX3(tmp.spec.RGBi.red,
133 tmp.spec.RGBi.green,
134 tmp.spec.RGBi.blue);
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;
140
141 /* If the calling routine wants RGB value give them the ones used. */
142 if (pRGB_return) {
143 pRGB_return->red = tmp.spec.RGBi.red;
144 pRGB_return->green = tmp.spec.RGBi.green;
145 pRGB_return->blue = tmp.spec.RGBi.blue;
146 }
147
148 /* Convert from RGBi to Lab */
149 if (_XcmsConvertColorsWithWhitePt(ccc, &tmp,
150 ScreenWhitePointOfCCC(ccc), 1, XcmsCIELabFormat, (Bool *) NULL)
151 == XcmsFailure) {
152 return (XcmsFailure);
153 }
154
155 memcpy((char *)pColor_return, (char *)&tmp, sizeof(XcmsColor));
156 return (XcmsSuccess);
157 }
158
159
160 /************************************************************************
161 * *
162 * PUBLIC ROUTINES *
163 * *
164 ************************************************************************/
165
166 /*
167 * NAME
168 * XcmsCIELabQueryMaxLC - Compute maximum L* and chroma.
169 *
170 * SYNOPSIS
171 */
172 Status
XcmsCIELabQueryMaxLC(XcmsCCC ccc,XcmsFloat hue_angle,XcmsColor * pColor_return)173 XcmsCIELabQueryMaxLC (
174 XcmsCCC ccc,
175 XcmsFloat hue_angle, /* hue_angle in degrees */
176 XcmsColor *pColor_return)
177
178 /*
179 * DESCRIPTION
180 * Return the point of maximum chroma for the specified
181 * hue_angle.
182 *
183 * ASSUMPTIONS
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.
188 *
189 * RETURNS
190 * XcmsFailure - Failure
191 * XcmsSuccess - Succeeded
192 *
193 */
194 {
195 XcmsCCCRec myCCC;
196
197 /*
198 * Check Arguments
199 */
200 if (ccc == NULL || pColor_return == NULL) {
201 return(XcmsFailure);
202 }
203
204 /* Use my own CCC */
205 memcpy ((char *)&myCCC, (char *)ccc, sizeof(XcmsCCCRec));
206 myCCC.clientWhitePt.format = XcmsUndefinedFormat;
207 myCCC.gamutCompProc = (XcmsCompressionProc)NULL;
208
209 while (hue_angle < 0.0) {
210 hue_angle += 360.0;
211 }
212 while (hue_angle >= 360.0) {
213 hue_angle -= 360.0;
214 }
215
216 return(_XcmsCIELabQueryMaxLCRGB (&myCCC, radians(hue_angle), pColor_return,
217 (XcmsRGBi *)NULL));
218 }
219