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. TekColor is a 8 * trademark of Tektronix, Inc. The term "TekHVC" designates a particular 9 * color space that is the subject of U.S. Patent No. 4,985,853 (equivalent 10 * foreign patents pending). Permission is hereby granted to use, copy, 11 * modify, sell, and otherwise distribute this software and its 12 * documentation for any purpose and without fee, provided that: 13 * 14 * 1. This copyright, permission, and disclaimer notice is reproduced in 15 * all copies of this software and any modification thereof and in 16 * supporting documentation; 17 * 2. Any color-handling application which displays TekHVC color 18 * cooordinates identifies these as TekHVC color coordinates in any 19 * interface that displays these coordinates and in any associated 20 * documentation; 21 * 3. The term "TekHVC" is always used, and is only used, in association 22 * with the mathematical derivations of the TekHVC Color Space, 23 * including those provided in this file and any equivalent pathways and 24 * mathematical derivations, regardless of digital (e.g., floating point 25 * or integer) representation. 26 * 27 * Tektronix makes no representation about the suitability of this software 28 * for any purpose. It is provided "as is" and with all faults. 29 * 30 * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE, 31 * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 32 * PARTICULAR PURPOSE. IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY 33 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 34 * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF 35 * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 36 * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE. 37 * 38 * NAME 39 * TekHVCMxV.c 40 * 41 * DESCRIPTION 42 * Source for the XcmsTekHVCQueryMaxV() gamut boundary 43 * querying routine. 44 * 45 */ 46 47#ifdef HAVE_CONFIG_H 48#include <config.h> 49#endif 50#include "Xlibint.h" 51#include "Xcmsint.h" 52#include <math.h> 53#include "Cv.h" 54 55/* 56 * DEFINES 57 */ 58#define MAXBISECTCOUNT 100 59#define EPS 0.001 60 61 62/************************************************************************ 63 * * 64 * PUBLIC ROUTINES * 65 * * 66 ************************************************************************/ 67 68/* 69 * NAME 70 * XcmsTekHVCQueryMaxV - Compute maximum value for a hue and chroma 71 * 72 * SYNOPSIS 73 */ 74Status 75XcmsTekHVCQueryMaxV( 76 XcmsCCC ccc, 77 XcmsFloat hue, 78 XcmsFloat chroma, 79 XcmsColor *pColor_return) 80/* 81 * DESCRIPTION 82 * Return the maximum value for a specified hue and chroma. 83 * 84 * ASSUMPTIONS 85 * This routine assumes that the white point associated with 86 * the color specification is the Screen White Point. The 87 * Screen White Point will also be associated with the 88 * returned color specification. 89 * 90 * RETURNS 91 * XcmsFailure - Failure 92 * XcmsSuccess - Succeeded with no modifications 93 * 94 */ 95{ 96 XcmsCCCRec myCCC; 97 XcmsColor tmp; 98 XcmsColor max_vc; 99 XcmsRGBi rgb_saved; 100 int nCount, nMaxCount; 101 XcmsFloat nT, nChroma, savedChroma, lastValue, lastChroma, prevChroma; 102 XcmsFloat rFactor; 103 XcmsFloat ftmp1, ftmp2; 104 105 /* 106 * Check Arguments 107 */ 108 if (ccc == NULL || pColor_return == NULL) { 109 return(XcmsFailure); 110 } 111 112 /* 113 * Insure TekHVC installed 114 */ 115 if (XcmsAddColorSpace(&XcmsTekHVCColorSpace) == XcmsFailure) { 116 return(XcmsFailure); 117 } 118 119 /* setup the CCC to use for the conversions. */ 120 memcpy ((char *) &myCCC, (char *) ccc, sizeof(XcmsCCCRec)); 121 myCCC.clientWhitePt.format = XcmsUndefinedFormat; 122 myCCC.gamutCompProc = (XcmsCompressionProc) NULL; 123 124 tmp.spec.TekHVC.H = hue; 125 tmp.spec.TekHVC.V = 0.0; 126 tmp.spec.TekHVC.C = chroma; 127 tmp.pixel = pColor_return->pixel; 128 tmp.format = XcmsTekHVCFormat; 129 130 if (!_XcmsTekHVC_CheckModify (&tmp)) { 131 return(XcmsFailure); 132 } 133 134 /* Step 1: compute the maximum value and chroma for this hue. */ 135 /* This copy may be overkill but it preserves the pixel etc. */ 136 memcpy((char *)&max_vc, (char *)&tmp, sizeof(XcmsColor)); 137 hue = max_vc.spec.TekHVC.H; 138 if (_XcmsTekHVCQueryMaxVCRGB(&myCCC, max_vc.spec.TekHVC.H, &max_vc, &rgb_saved) 139 == XcmsFailure) { 140 return(XcmsFailure); 141 } 142 143 if (max_vc.spec.TekHVC.C < tmp.spec.TekHVC.C) { 144 /* 145 * If the chroma is greater than the chroma for the 146 * maximum value/chroma point then the value is the 147 * the value for the maximum value, chroma point. 148 * This is an error but it I return the best approximation I can. 149 * Thus the inconsistency. 150 */ 151 tmp.spec.TekHVC.C = max_vc.spec.TekHVC.C; 152 tmp.spec.TekHVC.V = max_vc.spec.TekHVC.V; 153 memcpy ((char *) pColor_return, (char *) &tmp, sizeof (XcmsColor)); 154 return(XcmsSuccess); 155 } else if (max_vc.spec.TekHVC.C == tmp.spec.TekHVC.C) { 156 /* 157 * If the chroma is equal to the chroma for the 158 * maximum value/chroma point then the value is the 159 * the value for the maximum value, chroma point. 160 */ 161 tmp.spec.TekHVC.V = max_vc.spec.TekHVC.V; 162 memcpy ((char *) pColor_return, (char *) &tmp, sizeof (XcmsColor)); 163 return(XcmsSuccess); 164 } else { 165 /* must do a bisection here to compute the maximum value */ 166 /* save the structure input so that any elements that */ 167 /* are not touched are recopied later in the routine. */ 168 nChroma = savedChroma = tmp.spec.TekHVC.C; 169 tmp.spec.TekHVC.C = max_vc.spec.TekHVC.C; 170 tmp.spec.TekHVC.V = max_vc.spec.TekHVC.V; 171 lastChroma = -1.0; 172 lastValue = -1.0; 173 nMaxCount = MAXBISECTCOUNT; 174 rFactor = 1.0; 175 176 for (nCount = 0; nCount < nMaxCount; nCount++) { 177 prevChroma = lastChroma; 178 lastValue = tmp.spec.TekHVC.V; 179 lastChroma = tmp.spec.TekHVC.C; 180 nT = (1.0 - (nChroma / max_vc.spec.TekHVC.C)) * rFactor; 181 tmp.spec.RGBi.red = rgb_saved.red * (1.0 - nT) + nT; 182 tmp.spec.RGBi.green = rgb_saved.green * (1.0 - nT) + nT; 183 tmp.spec.RGBi.blue = rgb_saved.blue * (1.0 - nT) + nT; 184 tmp.format = XcmsRGBiFormat; 185 186 /* convert from RGB to HVC */ 187 if (_XcmsConvertColorsWithWhitePt(&myCCC, &tmp, 188 &myCCC.pPerScrnInfo->screenWhitePt, 1, XcmsTekHVCFormat, 189 (Bool *) NULL) == XcmsFailure) { 190 return(XcmsFailure); 191 } 192 193 /* Now check the return against what is expected */ 194 if (tmp.spec.TekHVC.C <= savedChroma + EPS && 195 tmp.spec.TekHVC.C >= savedChroma - EPS) { 196 tmp.spec.TekHVC.H = hue; /* use the saved hue */ 197 memcpy ((char *) pColor_return, (char *) &tmp, sizeof (XcmsColor)); 198 return(XcmsSuccess); 199 } 200 nChroma += savedChroma - tmp.spec.TekHVC.C; 201 if (nChroma > max_vc.spec.TekHVC.C) { 202 nChroma = max_vc.spec.TekHVC.C; 203 rFactor *= 0.5; /* selective relaxation employed */ 204 } else if (nChroma < 0.0) { 205 /* avoid using fabs */ 206 ftmp1 = lastChroma - savedChroma; 207 if (ftmp1 < 0.0) 208 ftmp1 = -ftmp1; 209 ftmp2 = tmp.spec.TekHVC.C - savedChroma; 210 if (ftmp2 < 0.0) 211 ftmp2 = -ftmp2; 212 if (ftmp1 < ftmp2) { 213 tmp.spec.TekHVC.V = lastValue; 214 tmp.spec.TekHVC.C = lastChroma; 215 } 216 /* make sure to return the input hue */ 217 tmp.spec.TekHVC.H = hue; 218 if (!_XcmsTekHVC_CheckModify(&tmp)) { 219 return(XcmsFailure); 220 } 221 memcpy ((char *) pColor_return, (char *) &tmp, sizeof (XcmsColor)); 222 return(XcmsSuccess); 223 } else if (tmp.spec.TekHVC.C <= prevChroma + EPS && 224 tmp.spec.TekHVC.C >= prevChroma - EPS) { 225 rFactor *= 0.5; /* selective relaxation employed */ 226 } 227 } 228 if (nCount >= nMaxCount) { 229 /* avoid using fabs */ 230 ftmp1 = lastChroma - savedChroma; 231 if (ftmp1 < 0.0) 232 ftmp1 = -ftmp1; 233 ftmp2 = tmp.spec.TekHVC.C - savedChroma; 234 if (ftmp2 < 0.0) 235 ftmp2 = -ftmp2; 236 if (ftmp1 < ftmp2) { 237 tmp.spec.TekHVC.V = lastValue; 238 tmp.spec.TekHVC.C = lastChroma; 239 } 240 } 241 } 242 243 /* make sure to return the input hue */ 244 tmp.spec.TekHVC.H = hue; 245 memcpy ((char *) pColor_return, (char *) &tmp, sizeof (XcmsColor)); 246 return(XcmsSuccess); 247} 248