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