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 * TekHVCMxC.c 40 * 41 * DESCRIPTION 42 * Source for the XcmsTekHVCQueryMaxC() 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 * XcmsTekHVCQueryMaxC - Compute the maximum chroma for a hue and value 71 * 72 * SYNOPSIS 73 */ 74Status 75XcmsTekHVCQueryMaxC( 76 XcmsCCC ccc, 77 XcmsFloat hue, 78 XcmsFloat value, 79 XcmsColor *pColor_return) 80/* 81 * DESCRIPTION 82 * Return the maximum chroma for a specific hue and value. 83 * The returned format is in XcmsTekHVCFormat. 84 * 85 * 86 * ASSUMPTIONS 87 * This routine assumes that the white point associated with 88 * the color specification is the Screen White Point. The 89 * Screen White Point will also be associated with the 90 * returned color specification. 91 * 92 * RETURNS 93 * XcmsFailure - Failure 94 * XcmsSuccess - Succeeded 95 * 96 */ 97{ 98 XcmsCCCRec myCCC; 99 XcmsColor tmp; 100 XcmsColor max_vc; 101 XcmsRGBi rgb_saved; 102 int nCount, nMaxCount; 103 XcmsFloat nValue, savedValue, lastValue, lastChroma, prevValue; 104 XcmsFloat maxDist, nT, rFactor; 105 XcmsFloat ftmp1, ftmp2; 106 107 /* 108 * Check Arguments 109 */ 110 if (ccc == NULL || pColor_return == NULL) { 111 return(XcmsFailure); 112 } 113 114 /* 115 * Insure TekHVC installed 116 */ 117 if (XcmsAddColorSpace(&XcmsTekHVCColorSpace) == XcmsFailure) { 118 return(XcmsFailure); 119 } 120 121 /* Use my own CCC */ 122 memcpy ((char *)&myCCC, (char *)ccc, sizeof(XcmsCCCRec)); 123 myCCC.clientWhitePt.format = XcmsUndefinedFormat; /* inherit screen white Pt */ 124 myCCC.gamutCompProc = (XcmsCompressionProc)NULL;/* no gamut comp func */ 125 126 tmp.spec.TekHVC.H = hue; 127 tmp.spec.TekHVC.V = value; 128 tmp.spec.TekHVC.C = 100.0; 129 tmp.pixel = pColor_return->pixel; 130 tmp.format = XcmsTekHVCFormat; 131 132 /* check to make sure we have a valid TekHVC number */ 133 if (!_XcmsTekHVC_CheckModify(&tmp)) { 134 return(XcmsFailure); 135 } 136 137 /* Step 1: compute the maximum value and chroma for this hue. */ 138 memcpy((char *)&max_vc, (char *)&tmp, sizeof(XcmsColor)); 139 if (_XcmsTekHVCQueryMaxVCRGB(&myCCC, hue, &max_vc, &rgb_saved) 140 == XcmsFailure) { 141 return(XcmsFailure); 142 } 143 144 /* Step 2: If the value is less than the value for the maximum */ 145 /* value, chroma point then the chroma is on the line */ 146 /* from max_vc to 0,0. */ 147 if (value <= max_vc.spec.TekHVC.V) { 148 tmp.spec.TekHVC.C = value 149 * max_vc.spec.TekHVC.C / max_vc.spec.TekHVC.V; 150 if (_XcmsTekHVC_CheckModify (&tmp)) { 151 memcpy((char *)pColor_return, (char *)&tmp, sizeof(XcmsColor)); 152 return(XcmsSuccess); 153 } else { 154 return(XcmsFailure); 155 } 156 } else { 157 /* must do a bisection here to compute the maximum chroma */ 158 /* save the structure input so that any elements that */ 159 /* are not touched are recopied later in the routine. */ 160 nValue = savedValue = value; 161 lastChroma = -1.0; 162 lastValue = -1.0; 163 nMaxCount = MAXBISECTCOUNT; 164 maxDist = 100.0 - max_vc.spec.TekHVC.V; 165 rFactor = 1.0; 166 167 for (nCount = 0; nCount < nMaxCount; nCount++) { 168 prevValue = lastValue; 169 lastValue = tmp.spec.TekHVC.V; 170 lastChroma = tmp.spec.TekHVC.C; 171 nT = (nValue - max_vc.spec.TekHVC.V) / maxDist * rFactor; 172 tmp.spec.RGBi.red = rgb_saved.red * (1.0 - nT) + nT; 173 tmp.spec.RGBi.green = rgb_saved.green * (1.0 - nT) + nT; 174 tmp.spec.RGBi.blue = rgb_saved.blue * (1.0 - nT) + nT; 175 tmp.format = XcmsRGBiFormat; 176 177 /* convert from RGB to HVC */ 178 if (_XcmsConvertColorsWithWhitePt(&myCCC, &tmp, 179 &myCCC.pPerScrnInfo->screenWhitePt, 1, XcmsTekHVCFormat, 180 (Bool *) NULL) == XcmsFailure) { 181 return(XcmsFailure); 182 } 183 184 /* Now check the return against what is expected */ 185 if (tmp.spec.TekHVC.V <= savedValue + EPS && 186 tmp.spec.TekHVC.V >= savedValue - EPS) { 187 /* make sure to return the input hue */ 188 tmp.spec.TekHVC.H = hue; 189 if (_XcmsTekHVC_CheckModify (&tmp)) { 190 memcpy((char *)pColor_return, (char *)&tmp, sizeof(XcmsColor)); 191 return(XcmsSuccess); 192 } else { 193 return(XcmsFailure); 194 } 195 } 196 nValue += savedValue - tmp.spec.TekHVC.V; 197 if (nValue < max_vc.spec.TekHVC.V) { 198 nValue = max_vc.spec.TekHVC.V; 199 rFactor *= 0.5; /* selective relaxation employed */ 200 } else if (nValue > 100.0) { 201 /* make sure to return the input hue */ 202 tmp.spec.TekHVC.H = hue; 203 /* avoid using fabs */ 204 ftmp1 = lastValue - savedValue; 205 if (ftmp1 < 0.0) 206 ftmp1 = -ftmp1; 207 ftmp2 = tmp.spec.TekHVC.V - savedValue; 208 if (ftmp2 < 0.0) 209 ftmp2 = -ftmp2; 210 if (ftmp1 < ftmp2) { 211 tmp.spec.TekHVC.V = lastValue; 212 tmp.spec.TekHVC.C = lastChroma; 213 } 214 if (_XcmsTekHVC_CheckModify (&tmp)) { 215 memcpy((char *)pColor_return, (char *)&tmp, sizeof(XcmsColor)); 216 return(XcmsSuccess); 217 } else { 218 return(XcmsFailure); 219 } 220 } else if (tmp.spec.TekHVC.V <= prevValue + EPS && 221 tmp.spec.TekHVC.V >= prevValue - EPS) { 222 rFactor *= 0.5; /* selective relaxation employed */ 223 } 224 } 225 if (nCount >= nMaxCount) { 226 /* avoid using fabs */ 227 ftmp1 = lastValue - savedValue; 228 if (ftmp1 < 0.0) 229 ftmp1 = -ftmp1; 230 ftmp2 = tmp.spec.TekHVC.V - savedValue; 231 if (ftmp2 < 0.0) 232 ftmp2 = -ftmp2; 233 if (ftmp1 < ftmp2) { 234 tmp.spec.TekHVC.V = lastValue; 235 tmp.spec.TekHVC.C = lastChroma; 236 } 237 } 238 } 239 /* make sure to return the input hue */ 240 tmp.spec.TekHVC.H = hue; 241 memcpy((char *)pColor_return, (char *)&tmp, sizeof(XcmsColor)); 242 return(XcmsSuccess); 243} 244