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 * CIELuvMxC.c 29 * 30 * DESCRIPTION 31 * Source for the XcmsCIELuvQueryMaxC() 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)2.2 50#define TOPL (XcmsFloat)100.0 51 52 53/************************************************************************ 54 * * 55 * PUBLIC ROUTINES * 56 * * 57 ************************************************************************/ 58 59/* 60 * NAME 61 * XcmsCIELuvQueryMaxC - max chroma for a hue_angle and L_star 62 * 63 * SYNOPSIS 64 */ 65Status 66XcmsCIELuvQueryMaxC( 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 XcmsCIELuvFormat. 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, lastuStar, lastvStar, /*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.CIELuv.L_star = L_star; 118 tmp.spec.CIELuv.u_star = XCMS_CIEUSTAROFHUE(hue, START_CHROMA); 119 tmp.spec.CIELuv.v_star = XCMS_CIEVSTAROFHUE(hue, START_CHROMA); 120 tmp.pixel = pColor_return->pixel; 121 tmp.format = XcmsCIELuvFormat; 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 (_XcmsCIELuvQueryMaxLCRGB(&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.CIELuv.L_star) { 136 maxDist = max_lc.spec.CIELuv.L_star; 137 } else { 138 maxDist = TOPL - max_lc.spec.CIELuv.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.CIELuv.L_star; 149/* lastChroma = XCMS_CIELUV_PMETRIC_CHROMA(tmp.spec.CIELuv.u_star, */ 150/* tmp.spec.CIELuv.v_star); */ 151 lastuStar = tmp.spec.CIELuv.u_star; 152 lastvStar = tmp.spec.CIELuv.v_star; 153 nT = (n_L_star - max_lc.spec.CIELuv.L_star) / maxDist * rFactor; 154 /* printf("(n_L_star, nT) = %lf %lf ", n_L_star, nT); */ 155 if (nT > 0) { 156 tmp.spec.RGBi.red = rgb_saved.red * (1.0 - nT) + nT; 157 tmp.spec.RGBi.green = rgb_saved.green * (1.0 - nT) + nT; 158 tmp.spec.RGBi.blue = rgb_saved.blue * (1.0 - nT) + nT; 159 } else { 160 tmp.spec.RGBi.red = rgb_saved.red + (rgb_saved.red * nT); 161 tmp.spec.RGBi.green = rgb_saved.green + (rgb_saved.green * nT); 162 tmp.spec.RGBi.blue = rgb_saved.blue + (rgb_saved.blue * nT); 163 } 164 tmp.format = XcmsRGBiFormat; 165 166 /* convert from RGB to CIELuv */ 167 if (_XcmsConvertColorsWithWhitePt(&myCCC, &tmp, 168 ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIELuvFormat, 169 (Bool *) NULL) == XcmsFailure) { 170 return(XcmsFailure); 171 } 172 173 /* 174 * Now check if we've reached the target L_star 175 */ 176 /* printf("result Lstar = %lf\n", tmp.spec.CIELuv.L_star); */ 177 if (tmp.spec.CIELuv.L_star <= L_star + EPS && 178 tmp.spec.CIELuv.L_star >= L_star - EPS) { 179 memcpy((char *)pColor_return, (char *)&tmp, sizeof(XcmsColor)); 180 return(XcmsSuccess); 181 } 182 if (nT > 0) { 183 n_L_star += ((TOPL - n_L_star) * 184 (L_star - tmp.spec.CIELuv.L_star)) / (TOPL - L_star); 185 } else { 186 n_L_star *= L_star / tmp.spec.CIELuv.L_star; 187 } 188 if (tmp.spec.CIELuv.L_star <= prev_L_star + EPS && 189 tmp.spec.CIELuv.L_star >= prev_L_star - EPS) { 190 rFactor *= 0.5; /* selective relaxation employed */ 191 /* printf("rFactor = %lf\n", rFactor); */ 192 } 193 } 194 if (XCMS_FABS(last_L_star - L_star) < 195 XCMS_FABS(tmp.spec.CIELuv.L_star - L_star)) { 196 tmp.spec.CIELuv.u_star = lastuStar; 197 tmp.spec.CIELuv.v_star = lastvStar; 198/* tmp.spec.CIELuv.u_star = XCMS_CIEUSTAROFHUE(hue, lastChroma); */ 199/* tmp.spec.CIELuv.v_star = XCMS_CIEVSTAROFHUE(hue, lastChroma); */ 200 } 201 tmp.spec.CIELuv.L_star = L_star; 202 memcpy((char *)pColor_return, (char *)&tmp, sizeof(XcmsColor)); 203 return(XcmsSuccess); 204} 205