LuvMnL.c revision 61b2299d
1/* $Xorg: LuvMnL.c,v 1.3 2000/08/17 19:44:41 cpqbld Exp $ */ 2 3/* 4 * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc. 5 * All Rights Reserved 6 * 7 * This file is a component of an X Window System-specific implementation 8 * of XCMS based on the TekColor Color Management System. Permission is 9 * hereby granted to use, copy, modify, sell, and otherwise distribute this 10 * software and its documentation for any purpose and without fee, provided 11 * that this copyright, permission, and disclaimer notice is reproduced in 12 * all copies of this software and in supporting documentation. TekColor 13 * is a trademark of Tektronix, Inc. 14 * 15 * Tektronix makes no representation about the suitability of this software 16 * for any purpose. It is provided "as is" and with all faults. 17 * 18 * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE, 19 * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 20 * PARTICULAR PURPOSE. IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY 21 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 22 * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF 23 * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 24 * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE. 25 * 26 * NAME 27 * CIELuvMnL.c 28 * 29 * DESCRIPTION 30 * Source for the XcmsCIELuvQueryMinL() gamut boundary 31 * querying routine. 32 * 33 */ 34/* $XFree86: xc/lib/X11/LuvMnL.c,v 1.3 2001/01/17 19:41:39 dawes Exp $ */ 35 36#ifdef HAVE_CONFIG_H 37#include <config.h> 38#endif 39#include "Xlibint.h" 40#include "Xcmsint.h" 41#include <math.h> 42#include "Cv.h" 43 44/* 45 * DEFINES 46 */ 47#define MAXBISECTCOUNT 100 48#define EPS (XcmsFloat)0.001 49#define START_L_STAR (XcmsFloat)40.0 50 51 52/************************************************************************ 53 * * 54 * PUBLIC ROUTINES * 55 * * 56 ************************************************************************/ 57 58/* 59 * NAME 60 * XcmsCIELuvQueryMinL - Compute max Lstar for a hue and chroma 61 * 62 * SYNOPSIS 63 */ 64Status 65XcmsCIELuvQueryMinL( 66 XcmsCCC ccc, 67 XcmsFloat hue_angle, /* hue angle in degrees */ 68 XcmsFloat chroma, 69 XcmsColor *pColor_return) 70/* 71 * DESCRIPTION 72 * Return the maximum Lstar for a specified hue_angle and chroma. 73 * 74 * ASSUMPTIONS 75 * This routine assumes that the white point associated with 76 * the color specification is the Screen White Point. The 77 * Screen White Point will also be associated with the 78 * returned color specification. 79 * 80 * RETURNS 81 * XcmsFailure - Failure 82 * XcmsSuccess - Succeeded with no modifications 83 * 84 */ 85{ 86 XcmsCCCRec myCCC; 87 XcmsColor max_lc, tmp, prev; 88 XcmsFloat max_chroma, tmp_chroma; 89 XcmsFloat hue, nT, nChroma, lastChroma, prevChroma; 90 XcmsFloat rFactor; 91 XcmsRGBi rgb_saved; 92 int nCount, nMaxCount; 93 94 /* 95 * Check Arguments 96 */ 97 if (ccc == NULL || pColor_return == NULL) { 98 return(XcmsFailure); 99 } 100 101 /* setup the CCC to use for the conversions. */ 102 memcpy ((char *) &myCCC, (char *) ccc, sizeof(XcmsCCCRec)); 103 myCCC.clientWhitePt.format = XcmsUndefinedFormat; 104 myCCC.gamutCompProc = (XcmsCompressionProc) NULL; 105 106 while (hue_angle < 0.0) { 107 hue_angle += 360.0; 108 } 109 while (hue_angle >= 360.0) { 110 hue_angle -= 360.0; 111 } 112 113 hue = radians(hue_angle); 114 tmp.spec.CIELuv.L_star = START_L_STAR; 115 tmp.spec.CIELuv.u_star = XCMS_CIEUSTAROFHUE(hue, chroma); 116 tmp.spec.CIELuv.v_star = XCMS_CIEVSTAROFHUE(hue, chroma); 117 tmp.pixel = pColor_return->pixel; 118 tmp.format = XcmsCIELuvFormat; 119 120 /* Step 1: Obtain the maximum L_star and chroma for this hue. */ 121 if (_XcmsCIELuvQueryMaxLCRGB(&myCCC, hue, &max_lc, &rgb_saved) 122 == XcmsFailure) { 123 return(XcmsFailure); 124 } 125 126 max_chroma = XCMS_CIELUV_PMETRIC_CHROMA(max_lc.spec.CIELuv.u_star, 127 max_lc.spec.CIELuv.v_star); 128 129 if (max_chroma <= chroma) { 130 /* 131 * If the chroma is greater than the chroma for the 132 * maximum L/chroma point then the L_star is the 133 * the L_star for the maximum L_star/chroma point. 134 * This is an error but I return the best approximation I can. 135 * Thus the inconsistency. 136 */ 137 memcpy ((char *) pColor_return, (char *) &max_lc, sizeof (XcmsColor)); 138 return(XcmsSuccess); 139 } 140 141 /* 142 * If the chroma is equal to the chroma for the 143 * maximum L_star/chroma point then the L_star is the 144 * the L_star for the maximum L* and chroma point. 145 */ 146 /* if (max_chroma == chroma) { 147 * memcpy ((char *) pColor_return, (char *) &max_lc, sizeof (XcmsColor)); 148 * return(XcmsSuccess); 149 * } 150 */ 151 152 /* must do a bisection here to compute the maximum L* */ 153 /* save the structure input so that any elements that */ 154 /* are not touched are recopied later in the routine. */ 155 nChroma = chroma; 156 tmp_chroma = max_chroma; 157 lastChroma = -1.0; 158 nMaxCount = MAXBISECTCOUNT; 159 rFactor = 1.0; 160 161 for (nCount = 0; nCount < nMaxCount; nCount++) { 162 prevChroma = lastChroma; 163 lastChroma = tmp_chroma; 164 nT = (nChroma - max_chroma) / max_chroma * rFactor; 165 memcpy ((char *)&prev, (char *)&tmp, sizeof(XcmsColor)); 166 tmp.spec.RGBi.red = rgb_saved.red + (rgb_saved.red * nT); 167 tmp.spec.RGBi.green = rgb_saved.green + (rgb_saved.green * nT); 168 tmp.spec.RGBi.blue = rgb_saved.blue + (rgb_saved.blue * nT); 169 tmp.format = XcmsRGBiFormat; 170 171 /* convert from RGB to CIELuv */ 172 if (_XcmsConvertColorsWithWhitePt(&myCCC, &tmp, 173 ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIELuvFormat, 174 (Bool *) NULL) == XcmsFailure) { 175 return(XcmsFailure); 176 } 177 178 /* Now check the return against what is expected */ 179 tmp_chroma = XCMS_CIELUV_PMETRIC_CHROMA(tmp.spec.CIELuv.u_star, 180 tmp.spec.CIELuv.v_star); 181 if (tmp_chroma <= chroma + EPS && tmp_chroma >= chroma - EPS) { 182 /* Found It! */ 183 memcpy ((char *) pColor_return, (char *) &tmp, sizeof (XcmsColor)); 184 return(XcmsSuccess); 185 } 186 nChroma += chroma - tmp_chroma; 187 if (nChroma > max_chroma) { 188 nChroma = max_chroma; 189 rFactor *= 0.5; /* selective relaxation employed */ 190 } else if (nChroma < 0.0) { 191 if (XCMS_FABS(lastChroma - chroma) < 192 XCMS_FABS(tmp_chroma - chroma)) { 193 memcpy ((char *)pColor_return, (char *)&prev, 194 sizeof(XcmsColor)); 195 } else { 196 memcpy ((char *)pColor_return, (char *)&tmp, 197 sizeof(XcmsColor)); 198 } 199 return(XcmsSuccess); 200 } else if (tmp_chroma <= prevChroma + EPS && 201 tmp_chroma >= prevChroma - EPS) { 202 rFactor *= 0.5; /* selective relaxation employed */ 203 } 204 } 205 206 if (nCount >= nMaxCount) { 207 if (XCMS_FABS(lastChroma - chroma) < 208 XCMS_FABS(tmp_chroma - chroma)) { 209 memcpy ((char *)pColor_return, (char *)&prev, 210 sizeof(XcmsColor)); 211 } else { 212 memcpy ((char *)pColor_return, (char *)&tmp, 213 sizeof(XcmsColor)); 214 } 215 } 216 memcpy ((char *) pColor_return, (char *) &tmp, sizeof (XcmsColor)); 217 return(XcmsSuccess); 218} 219