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