LabMxC.c revision 61b2299d
1/* $Xorg: LabMxC.c,v 1.3 2000/08/17 19:44:40 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 * 27 * 28 * NAME 29 * CIELabMxC.c 30 * 31 * DESCRIPTION 32 * Source for the XcmsCIELabQueryMaxC() gamut boundary 33 * querying routine. 34 * 35 */ 36/* $XFree86: xc/lib/X11/LabMxC.c,v 1.3 2001/01/17 19:41:39 dawes Exp $ */ 37 38#ifdef HAVE_CONFIG_H 39#include <config.h> 40#endif 41#include "Xlibint.h" 42#include "Xcmsint.h" 43#include <math.h> 44#include "Cv.h" 45 46/* 47 * DEFINES 48 */ 49#define MAXBISECTCOUNT 100 50#define EPS (XcmsFloat)0.001 51#define START_CHROMA (XcmsFloat)3.6 52#define TOPL (XcmsFloat)100.0 53 54 55/************************************************************************ 56 * * 57 * PUBLIC ROUTINES * 58 * * 59 ************************************************************************/ 60 61/* 62 * NAME 63 * XcmsCIELabQueryMaxC - max chroma for a hue_angle and L_star 64 * 65 * SYNOPSIS 66 */ 67Status 68XcmsCIELabQueryMaxC( 69 XcmsCCC ccc, 70 XcmsFloat hue_angle, /* hue angle in degrees */ 71 XcmsFloat L_star, 72 XcmsColor *pColor_return) 73/* 74 * DESCRIPTION 75 * Return the maximum chroma for a specific hue_angle and L_star. 76 * The returned format is in XcmsCIELabFormat. 77 * 78 * 79 * ASSUMPTIONS 80 * This routine assumes that the white point associated with 81 * the color specification is the Screen White Point. The 82 * Screen White Point will also be associated with the 83 * returned color specification. 84 * 85 * RETURNS 86 * XcmsFailure - Failure 87 * XcmsSuccess - Succeeded 88 * 89 */ 90{ 91 XcmsCCCRec myCCC; 92 XcmsColor tmp; 93 XcmsColor max_lc; 94 XcmsFloat n_L_star, last_L_star, prev_L_star; 95 XcmsFloat hue, lastaStar, lastbStar, /*lastChroma,*/ maxDist, nT, rFactor; 96 XcmsRGBi rgb_saved; 97 int nCount, nMaxCount; 98 99 /* 100 * Check Arguments 101 */ 102 if (ccc == NULL || pColor_return == NULL) { 103 return(XcmsFailure); 104 } 105 106 /* Use my own CCC and inherit screen white Pt */ 107 memcpy ((char *)&myCCC, (char *)ccc, sizeof(XcmsCCCRec)); 108 myCCC.clientWhitePt.format = XcmsUndefinedFormat; 109 myCCC.gamutCompProc = (XcmsCompressionProc)NULL;/* no gamut comp func */ 110 111 while (hue_angle < 0.0) { 112 hue_angle += 360.0; 113 } 114 while (hue_angle >= 360.0) { 115 hue_angle -= 360.0; 116 } 117 118 hue = radians(hue_angle); 119 tmp.spec.CIELab.L_star = L_star; 120 tmp.spec.CIELab.a_star = XCMS_CIEASTAROFHUE(hue, START_CHROMA); 121 tmp.spec.CIELab.b_star = XCMS_CIEBSTAROFHUE(hue, START_CHROMA); 122 tmp.pixel = pColor_return->pixel; 123 tmp.format = XcmsCIELabFormat; 124 125 /* Step 1: compute the maximum L_star and chroma for this hue. */ 126 memcpy((char *)&max_lc, (char *)&tmp, sizeof(XcmsColor)); 127 if (_XcmsCIELabQueryMaxLCRGB(&myCCC, hue, &max_lc, &rgb_saved) 128 == XcmsFailure) { 129 return(XcmsFailure); 130 } 131 132 /* 133 * Step 2: Do a bisection here to compute the maximum chroma 134 * Note the differences between when the point to be found 135 * is above the maximum LC point and when it is below. 136 */ 137 if (L_star <= max_lc.spec.CIELab.L_star) { 138 maxDist = max_lc.spec.CIELab.L_star; 139 } else { 140 maxDist = TOPL - max_lc.spec.CIELab.L_star; 141 } 142 143 n_L_star = L_star; 144 last_L_star = -1.0; 145 nMaxCount = MAXBISECTCOUNT; 146 rFactor = 1.0; 147 148 for (nCount = 0; nCount < nMaxCount; nCount++) { 149 prev_L_star = last_L_star; 150 last_L_star = tmp.spec.CIELab.L_star; 151/* lastChroma = XCMS_CIELAB_PMETRIC_CHROMA(tmp.spec.CIELab.a_star, */ 152/* tmp.spec.CIELab.b_star); */ 153 lastaStar = tmp.spec.CIELab.a_star; 154 lastbStar = tmp.spec.CIELab.b_star; 155 nT = (n_L_star - max_lc.spec.CIELab.L_star) / maxDist * rFactor; 156 if (nT > 0) { 157 tmp.spec.RGBi.red = rgb_saved.red * (1.0 - nT) + nT; 158 tmp.spec.RGBi.green = rgb_saved.green * (1.0 - nT) + nT; 159 tmp.spec.RGBi.blue = rgb_saved.blue * (1.0 - nT) + nT; 160 } else { 161 tmp.spec.RGBi.red = rgb_saved.red + (rgb_saved.red * nT); 162 tmp.spec.RGBi.green = rgb_saved.green + (rgb_saved.green * nT); 163 tmp.spec.RGBi.blue = rgb_saved.blue + (rgb_saved.blue * nT); 164 } 165 tmp.format = XcmsRGBiFormat; 166 167 /* convert from RGB to CIELab */ 168 if (_XcmsConvertColorsWithWhitePt(&myCCC, &tmp, 169 ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIELabFormat, 170 (Bool *) NULL) == XcmsFailure) { 171 return(XcmsFailure); 172 } 173 174 /* 175 * Now check if we've reached the target L_star 176 */ 177 /* printf("result Lstar = %lf\n", tmp.spec.CIELab.L_star); */ 178 if (tmp.spec.CIELab.L_star <= L_star + EPS && 179 tmp.spec.CIELab.L_star >= L_star - EPS) { 180 memcpy((char *)pColor_return, (char *)&tmp, sizeof(XcmsColor)); 181 return(XcmsSuccess); 182 } 183 if (nT > 0) { 184 n_L_star += ((TOPL - n_L_star) * 185 (L_star - tmp.spec.CIELab.L_star)) / (TOPL - L_star); 186 } else { 187 n_L_star *= L_star / tmp.spec.CIELuv.L_star; 188 } 189 if (tmp.spec.CIELab.L_star <= prev_L_star + EPS && 190 tmp.spec.CIELab.L_star >= prev_L_star - EPS) { 191 rFactor *= 0.5; /* selective relaxation employed */ 192 /* printf("rFactor = %lf\n", rFactor); */ 193 } 194 } 195 if (XCMS_FABS(last_L_star - L_star) < 196 XCMS_FABS(tmp.spec.CIELab.L_star - L_star)) { 197 tmp.spec.CIELab.a_star = lastaStar; 198 tmp.spec.CIELab.b_star = lastbStar; 199/* tmp.spec.CIELab.a_star = XCMS_CIEASTAROFHUE(hue, lastChroma); */ 200/* tmp.spec.CIELab.b_star = XCMS_CIEBSTAROFHUE(hue, lastChroma); */ 201 } 202 tmp.spec.CIELab.L_star = L_star; 203 memcpy((char *)pColor_return, (char *)&tmp, sizeof(XcmsColor)); 204 return(XcmsSuccess); 205} 206