Tizen 2.1 base
[framework/uifw/xorg/lib/libx11.git] / src / xcms / LuvGcLC.c
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  *      NAME
26  *              CIELuvGcLC.c
27  *
28  *      DESCRIPTION
29  *              Source for XcmsCIELuvClipLuv() gamut
30  *              compression function.
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
36 #include "Xlibint.h"
37 #include "Xcmsint.h"
38 #include <math.h>
39 #include "Cv.h"
40
41 /*
42  *      INTERNALS
43  *              Internal defines that need NOT be exported to any package or
44  *              program using this package.
45  */
46 #define MAXBISECTCOUNT  100
47
48 \f
49 /************************************************************************
50  *                                                                      *
51  *                       PUBLIC ROUTINES                                *
52  *                                                                      *
53  ************************************************************************/
54
55 /*
56  *      NAME
57  *              XcmsCIELuvClipLuv - Return the closest L* and chroma
58  *
59  *      SYNOPSIS
60  */
61 /* ARGSUSED */
62 Status
63 XcmsCIELuvClipLuv (
64     XcmsCCC ccc,
65     XcmsColor *pColors_in_out,
66     unsigned int nColors,
67     unsigned int i,
68     Bool *pCompressed)
69 /*
70  *      DESCRIPTION
71  *              This routine will find the closest L* and chroma
72  *              for a specific hue.  The color input is converted to
73  *              CIE L*u*v* format and returned as CIE XYZ format.
74  *
75  *              Since this routine works with the L* within
76  *              pColor_in_out intermediate results may be returned
77  *              even though it may be invalid.
78  *
79  *      RETURNS
80  *              XcmsFailure - Failure
81  *              XcmsSuccess - Succeeded
82  *
83  */
84 {
85     Status retval;
86     XcmsCCCRec  myCCC;
87     XcmsColor   *pColor;
88     XcmsColor   Luv_max;
89     XcmsFloat   hue, chroma, maxChroma;
90     XcmsFloat   Chroma, bestChroma, Lstar, maxLstar, saveLstar;
91     XcmsFloat   bestLstar, bestustar, bestvstar;
92     XcmsFloat   nT, saveDist, tmpDist;
93     XcmsRGBi    rgb_max;
94     int         nCount, nMaxCount, nI, nILast;
95
96     /* Use my own CCC */
97     memcpy ((char *)&myCCC, (char *)ccc, sizeof(XcmsCCCRec));
98     myCCC.clientWhitePt.format = XcmsUndefinedFormat;/* inherit screen white */
99     myCCC.gamutCompProc = (XcmsCompressionProc)NULL;/* no gamut compression func */
100
101     /*
102      * Color specification passed as input can be assumed to:
103      *  1. Be in XcmsCIEXYZFormat
104      *  2. Already be white point adjusted for the Screen White Point.
105      *      This means that the white point now associated with this
106      *      color spec is the Screen White Point (even if the
107      *      ccc->clientWhitePt differs).
108      */
109
110     pColor = pColors_in_out + i;
111
112     if (ccc->visual->class < StaticColor) {
113         /*
114          * GRAY !
115          */
116         _XcmsDIConvertColors(ccc, pColor, ScreenWhitePointOfCCC(ccc),
117                 1, XcmsCIELuvFormat);
118         _XcmsDIConvertColors(ccc, pColor, ScreenWhitePointOfCCC(ccc),
119                 1, XcmsCIEXYZFormat);
120         if (pCompressed) {
121             *(pCompressed + i) = True;
122         }
123         return(XcmsSuccess);
124     }
125
126     /* Convert from CIEXYZ to CIELuv format */
127     if (_XcmsDIConvertColors(&myCCC, pColor,
128                             ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIELuvFormat)
129                 == XcmsFailure) {
130         return(XcmsFailure);
131     }
132
133     /* Step 1: compute the maximum L* and chroma for this hue. */
134     /*         This copy may be overkill but it preserves the pixel etc. */
135     saveLstar = pColor->spec.CIELuv.L_star;
136     hue = XCMS_CIELUV_PMETRIC_HUE(pColor->spec.CIELuv.u_star,
137                                   pColor->spec.CIELuv.v_star);
138     chroma = XCMS_CIELUV_PMETRIC_CHROMA(pColor->spec.CIELuv.u_star,
139                                         pColor->spec.CIELuv.v_star);
140     memcpy((char *)&Luv_max, (char *)pColor, sizeof(XcmsColor));
141     if (_XcmsCIELuvQueryMaxLCRGB (&myCCC, hue, &Luv_max, &rgb_max)
142             == XcmsFailure) {
143         return (XcmsFailure);
144     }
145     maxLstar = Luv_max.spec.CIELuv.L_star;
146
147     /* Now check and return the appropriate L* */
148     if (saveLstar == maxLstar) {
149         /* When the L* input is equal to the maximum L* */
150         /* merely return the maximum Luv point. */
151         memcpy((char *)pColor, (char *)&Luv_max, sizeof(XcmsColor));
152         retval = _XcmsDIConvertColors(&myCCC, pColor,
153                            ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIEXYZFormat);
154     } else {
155         /* return the closest point on the hue leaf. */
156         /* must do a bisection here to compute the delta e. */
157         maxChroma = XCMS_CIELUV_PMETRIC_CHROMA(Luv_max.spec.CIELuv.u_star,
158                                                Luv_max.spec.CIELuv.v_star);
159         nMaxCount = MAXBISECTCOUNT;
160         nI = nMaxCount / 2;
161         bestLstar = Lstar = pColor->spec.CIELuv.L_star;
162         bestustar = pColor->spec.CIELuv.u_star;
163         bestvstar = pColor->spec.CIELuv.v_star;
164         bestChroma = Chroma = chroma;
165         saveDist = XCMS_SQRT(((Chroma - maxChroma) * (Chroma - maxChroma)) +
166                              ((Lstar - maxLstar) * (Lstar - maxLstar)));
167         for (nCount = 0; nCount < nMaxCount; nCount++) {
168             nT = (XcmsFloat) nI / (XcmsFloat) nMaxCount;
169             if (saveLstar > maxLstar) {
170                 pColor->spec.RGBi.red   = rgb_max.red * (1.0 - nT) + nT;
171                 pColor->spec.RGBi.green = rgb_max.green * (1.0 - nT) + nT;
172                 pColor->spec.RGBi.blue  = rgb_max.blue * (1.0 - nT) + nT;
173             } else {
174                 pColor->spec.RGBi.red   = rgb_max.red - (rgb_max.red * nT);
175                 pColor->spec.RGBi.green = rgb_max.green - (rgb_max.green * nT);
176                 pColor->spec.RGBi.blue  = rgb_max.blue - (rgb_max.blue * nT);
177             }
178             pColor->format = XcmsRGBiFormat;
179
180             /* Convert from RGBi to CIE Luv */
181             if (_XcmsConvertColorsWithWhitePt(&myCCC, pColor,
182                             ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIELuvFormat,
183                             (Bool *) NULL) == XcmsFailure) {
184                 return (XcmsFailure);
185             }
186             chroma = XCMS_CIELUV_PMETRIC_CHROMA(pColor->spec.CIELuv.u_star,
187                                                 pColor->spec.CIELuv.v_star);
188             tmpDist = XCMS_SQRT(((Chroma - chroma) * (Chroma - chroma)) +
189                                 ((Lstar - pColor->spec.CIELuv.L_star) *
190                                  (Lstar - pColor->spec.CIELuv.L_star)));
191             nILast = nI;
192             if (tmpDist > saveDist) {
193                 nI /= 2;
194             } else {
195                 nI = (nMaxCount + nI) / 2;
196                 saveDist = tmpDist;
197                 bestLstar = pColor->spec.CIELuv.L_star;
198                 bestustar = pColor->spec.CIELuv.u_star;
199                 bestvstar = pColor->spec.CIELuv.v_star;
200                 bestChroma = chroma;
201             }
202             if (nI == nILast || nI == 0) {
203                 break;
204             }
205         }
206         if (bestChroma >= maxChroma) {
207             pColor->spec.CIELuv.L_star = maxLstar;
208             pColor->spec.CIELuv.u_star = Luv_max.spec.CIELuv.u_star;
209             pColor->spec.CIELuv.v_star = Luv_max.spec.CIELuv.v_star;
210         } else {
211             pColor->spec.CIELuv.L_star = bestLstar;
212             pColor->spec.CIELuv.u_star = bestustar;
213             pColor->spec.CIELuv.v_star = bestvstar;
214         }
215         retval = _XcmsDIConvertColors(&myCCC, pColor,
216                            ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIEXYZFormat);
217
218         if (retval != XcmsFailure && pCompressed != NULL) {
219             *(pCompressed + i) = True;
220         }
221     }
222     return(retval);
223 }