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