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