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 * CIELuvMxL.c 27 * 28 * DESCRIPTION 29 * Source for the XcmsCIELuvQueryMaxL() gamut boundary 30 * querying routine. 31 * 32 */ 33 34 #ifdef HAVE_CONFIG_H 35 #include <config.h> 36 #endif 37 #include "Xlibint.h" 38 #include "Xcmsint.h" 39 #include <math.h> 40 #include "Cv.h" 41 42 /* 43 * DEFINES 44 */ 45 #define MAXBISECTCOUNT 100 46 #define EPS (XcmsFloat)0.001 47 #define START_L_STAR (XcmsFloat)40.0 48 49 50 /************************************************************************ 52 * * 53 * PUBLIC ROUTINES * 54 * * 55 ************************************************************************/ 56 57 /* 58 * NAME 59 * XcmsCIELuvQueryMaxL - Compute max Lstar for a hue and chroma 60 * 61 * SYNOPSIS 62 */ 63 Status 64 XcmsCIELuvQueryMaxL( 65 XcmsCCC ccc, 66 XcmsFloat hue_angle, /* hue angle in degrees */ 67 XcmsFloat chroma, 68 XcmsColor *pColor_return) 69 /* 70 * DESCRIPTION 71 * Return the maximum Lstar for a specified hue_angle and chroma. 72 * 73 * ASSUMPTIONS 74 * This routine assumes that the white point associated with 75 * the color specification is the Screen White Point. The 76 * Screen White Point will also be associated with the 77 * returned color specification. 78 * 79 * RETURNS 80 * XcmsFailure - Failure 81 * XcmsSuccess - Succeeded with no modifications 82 * 83 */ 84 { 85 XcmsCCCRec myCCC; 86 XcmsColor max_lc, tmp, prev; 87 XcmsFloat max_chroma, tmp_chroma; 88 XcmsFloat hue, nT, nChroma, lastChroma, prevChroma; 89 XcmsFloat rFactor; 90 XcmsRGBi rgb_saved; 91 int nCount, nMaxCount; 92 93 /* 94 * Check Arguments 95 */ 96 if (ccc == NULL || pColor_return == NULL) { 97 return(XcmsFailure); 98 } 99 100 /* setup the CCC to use for the conversions. */ 101 memcpy ((char *) &myCCC, (char *) ccc, sizeof(XcmsCCCRec)); 102 myCCC.clientWhitePt.format = XcmsUndefinedFormat; 103 myCCC.gamutCompProc = (XcmsCompressionProc) NULL; 104 105 while (hue_angle < 0.0) { 106 hue_angle += 360.0; 107 } 108 while (hue_angle >= 360.0) { 109 hue_angle -= 360.0; 110 } 111 112 hue = radians(hue_angle); 113 tmp.spec.CIELuv.L_star = START_L_STAR; 114 tmp.spec.CIELuv.u_star = XCMS_CIEUSTAROFHUE(hue, chroma); 115 tmp.spec.CIELuv.v_star = XCMS_CIEVSTAROFHUE(hue, chroma); 116 tmp.pixel = pColor_return->pixel; 117 tmp.format = XcmsCIELuvFormat; 118 119 /* Step 1: Obtain the maximum L_star and chroma for this hue. */ 120 if (_XcmsCIELuvQueryMaxLCRGB(&myCCC, hue, &max_lc, &rgb_saved) 121 == XcmsFailure) { 122 return(XcmsFailure); 123 } 124 125 max_chroma = XCMS_CIELUV_PMETRIC_CHROMA(max_lc.spec.CIELuv.u_star, 126 max_lc.spec.CIELuv.v_star); 127 128 if (max_chroma <= chroma) { 129 /* 130 * If the chroma is greater than the chroma for the 131 * maximum L/chroma point then the L_star is the 132 * the L_star for the maximum L_star/chroma point. 133 * This is an error but I return the best approximation I can. 134 * Thus the inconsistency. 135 */ 136 memcpy ((char *) pColor_return, (char *) &max_lc, sizeof (XcmsColor)); 137 return(XcmsSuccess); 138 } 139 140 /* 141 * If the chroma is equal to the chroma for the 142 * maximum L_star/chroma point then the L_star is the 143 * the L_star for the maximum L* and chroma point. 144 */ 145 /* if (max_chroma == chroma) { 146 * memcpy ((char *) pColor_return, (char *) &max_lc, sizeof (XcmsColor)); 147 * return(XcmsSuccess); 148 * } 149 */ 150 151 /* must do a bisection here to compute the maximum L* */ 152 /* save the structure input so that any elements that */ 153 /* are not touched are recopied later in the routine. */ 154 nChroma = chroma; 155 tmp_chroma = max_chroma; 156 lastChroma = -1.0; 157 nMaxCount = MAXBISECTCOUNT; 158 rFactor = 1.0; 159 160 for (nCount = 0; nCount < nMaxCount; nCount++) { 161 prevChroma = lastChroma; 162 lastChroma = tmp_chroma; 163 nT = (1.0 - (nChroma / max_chroma)) * rFactor; 164 memcpy ((char *)&prev, (char *)&tmp, sizeof(XcmsColor)); 165 tmp.spec.RGBi.red = rgb_saved.red * (1.0 - nT) + nT; 166 tmp.spec.RGBi.green = rgb_saved.green * (1.0 - nT) + nT; 167 tmp.spec.RGBi.blue = rgb_saved.blue * (1.0 - nT) + nT; 168 tmp.format = XcmsRGBiFormat; 169 170 /* convert from RGB to CIELuv */ 171 if (_XcmsConvertColorsWithWhitePt(&myCCC, &tmp, 172 ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIELuvFormat, 173 (Bool *) NULL) == XcmsFailure) { 174 return(XcmsFailure); 175 } 176 177 /* Now check the return against what is expected */ 178 tmp_chroma = XCMS_CIELUV_PMETRIC_CHROMA(tmp.spec.CIELuv.u_star, 179 tmp.spec.CIELuv.v_star); 180 if (tmp_chroma <= chroma + EPS && tmp_chroma >= chroma - EPS) { 181 /* Found It! */ 182 memcpy ((char *) pColor_return, (char *) &tmp, sizeof (XcmsColor)); 183 return(XcmsSuccess); 184 } 185 nChroma += chroma - tmp_chroma; 186 if (nChroma > max_chroma) { 187 nChroma = max_chroma; 188 rFactor *= 0.5; /* selective relaxation employed */ 189 } else if (nChroma < 0.0) { 190 if (XCMS_FABS(lastChroma - chroma) < 191 XCMS_FABS(tmp_chroma - chroma)) { 192 memcpy ((char *)pColor_return, (char *)&prev, 193 sizeof(XcmsColor)); 194 } else { 195 memcpy ((char *)pColor_return, (char *)&tmp, 196 sizeof(XcmsColor)); 197 } 198 return(XcmsSuccess); 199 } else if (tmp_chroma <= prevChroma + EPS && 200 tmp_chroma >= prevChroma - EPS) { 201 rFactor *= 0.5; /* selective relaxation employed */ 202 } 203 } 204 205 if (nCount >= nMaxCount) { 206 if (XCMS_FABS(lastChroma - chroma) < 207 XCMS_FABS(tmp_chroma - chroma)) { 208 memcpy ((char *)pColor_return, (char *)&prev, 209 sizeof(XcmsColor)); 210 } else { 211 memcpy ((char *)pColor_return, (char *)&tmp, 212 sizeof(XcmsColor)); 213 } 214 } 215 memcpy ((char *) pColor_return, (char *) &tmp, sizeof (XcmsColor)); 216 return(XcmsSuccess); 217 } 218