HVCGcVC.c revision 61b2299d
1/* $Xorg: HVCGcVC.c,v 1.3 2000/08/17 19:44:36 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 * TekHVCGcVC.c 41 * 42 * DESCRIPTION 43 * Source for XcmsTekHVCClipVC() gamut 44 * compression function. 45 */ 46/* $XFree86: xc/lib/X11/HVCGcVC.c,v 1.3 2001/01/17 19:41:37 dawes Exp $ */ 47 48#ifdef HAVE_CONFIG_H 49#include <config.h> 50#endif 51#include "Xlibint.h" 52#include "Xcmsint.h" 53#include <math.h> 54#include "Cv.h" 55 56/* 57 * INTERNALS 58 * Internal defines that need NOT be exported to any package or 59 * program using this package. 60 */ 61#define MAXBISECTCOUNT 100 62 63 64/************************************************************************ 65 * * 66 * PUBLIC ROUTINES * 67 * * 68 ************************************************************************/ 69 70/* 71 * NAME 72 * XcmsTekHVCClipVC - Return the closest value and chroma 73 * 74 * SYNOPSIS 75 */ 76/* ARGSUSED */ 77Status 78XcmsTekHVCClipVC ( 79 XcmsCCC ccc, 80 XcmsColor *pColors_in_out, 81 unsigned int nColors, 82 unsigned int i, 83 Bool *pCompressed) 84/* 85 * DESCRIPTION 86 * This routine will find the closest value and chroma 87 * for a specific hue. The color input is converted to 88 * HVC format and returned as CIE XYZ format. 89 * 90 * Since this routine works with the value within 91 * pColor_in_out intermediate results may be returned 92 * even though it may be invalid. 93 * 94 * RETURNS 95 * XcmsFailure - Failure 96 * XcmsSuccess - Succeeded 97 * 98 */ 99{ 100 Status retval; 101 XcmsCCCRec myCCC; 102 XcmsColor *pColor; 103 XcmsColor hvc_max; 104 XcmsRGBi rgb_max; 105 int nCount, nMaxCount, nI, nILast; 106 XcmsFloat Chroma, Value, bestChroma, bestValue, nT, saveDist, tmpDist; 107 108 /* 109 * Insure TekHVC installed 110 */ 111 if (XcmsAddColorSpace(&XcmsTekHVCColorSpace) == XcmsFailure) { 112 return(XcmsFailure); 113 } 114 115 /* Use my own CCC */ 116 memcpy ((char *)&myCCC, (char *)ccc, sizeof(XcmsCCCRec)); 117 myCCC.clientWhitePt.format = XcmsUndefinedFormat;/* inherit screen white pt */ 118 myCCC.gamutCompProc = (XcmsCompressionProc)NULL;/* no gamut compression func */ 119 120 /* 121 * Color specification passed as input can be assumed to: 122 * 1. Be in XcmsCIEXYZFormat 123 * 2. Already be white point adjusted for the Screen White Point. 124 * This means that the white point now associated with this 125 * color spec is the Screen White Point (even if the 126 * ccc->clientWhitePt differs). 127 */ 128 129 pColor = pColors_in_out + i; 130 131 if (ccc->visual->class < StaticColor && 132 FunctionSetOfCCC(ccc) != (XPointer) &XcmsLinearRGBFunctionSet) { 133 /* 134 * GRAY ! 135 */ 136 _XcmsDIConvertColors(ccc, pColor, &ccc->pPerScrnInfo->screenWhitePt, 137 1, XcmsTekHVCFormat); 138 pColor->spec.TekHVC.H = pColor->spec.TekHVC.C = 0.0; 139 _XcmsDIConvertColors(ccc, pColor, &ccc->pPerScrnInfo->screenWhitePt, 140 1, XcmsCIEXYZFormat); 141 if (pCompressed) { 142 *(pCompressed + i) = True; 143 } 144 return(XcmsSuccess); 145 } else { 146 /* Convert from CIEXYZ to TekHVC format */ 147 if (_XcmsDIConvertColors(&myCCC, pColor, 148 &myCCC.pPerScrnInfo->screenWhitePt, 1, XcmsTekHVCFormat) 149 == XcmsFailure) { 150 return(XcmsFailure); 151 } 152 153 if (!_XcmsTekHVC_CheckModify(pColor)) { 154 return (XcmsFailure); 155 } 156 157 /* Step 1: compute the maximum value and chroma for this hue. */ 158 /* This copy may be overkill but it preserves the pixel etc. */ 159 memcpy((char *)&hvc_max, (char *)pColor, sizeof(XcmsColor)); 160 if (_XcmsTekHVCQueryMaxVCRGB (&myCCC, hvc_max.spec.TekHVC.H, &hvc_max, 161 &rgb_max) == XcmsFailure) { 162 return (XcmsFailure); 163 } 164 165 /* Now check and return the appropriate value */ 166 if (pColor->spec.TekHVC.V == hvc_max.spec.TekHVC.V) { 167 /* When the value input is equal to the maximum value */ 168 /* merely return the chroma for that value. */ 169 pColor->spec.TekHVC.C = hvc_max.spec.TekHVC.C; 170 retval = _XcmsDIConvertColors(&myCCC, pColor, 171 &myCCC.pPerScrnInfo->screenWhitePt, 1, XcmsCIEXYZFormat); 172 } 173 174 if (pColor->spec.TekHVC.V < hvc_max.spec.TekHVC.V) { 175 /* return the intersection of the perpindicular line through */ 176 /* the value and chroma given and the line from 0,0 and hvc_max. */ 177 Chroma = pColor->spec.TekHVC.C; 178 Value = pColor->spec.TekHVC.V; 179 pColor->spec.TekHVC.C = 180 (Value + (hvc_max.spec.TekHVC.C / hvc_max.spec.TekHVC.V * Chroma)) / 181 ((hvc_max.spec.TekHVC.V / hvc_max.spec.TekHVC.C) + 182 (hvc_max.spec.TekHVC.C / hvc_max.spec.TekHVC.V)); 183 if (pColor->spec.TekHVC.C >= hvc_max.spec.TekHVC.C) { 184 pColor->spec.TekHVC.C = hvc_max.spec.TekHVC.C; 185 pColor->spec.TekHVC.V = hvc_max.spec.TekHVC.V; 186 } else { 187 pColor->spec.TekHVC.V = pColor->spec.TekHVC.C * 188 hvc_max.spec.TekHVC.V / hvc_max.spec.TekHVC.C; 189 } 190 retval = _XcmsDIConvertColors(&myCCC, pColor, 191 &myCCC.pPerScrnInfo->screenWhitePt, 1, XcmsCIEXYZFormat); 192 193 if (retval != XcmsFailure && pCompressed != NULL) { 194 *(pCompressed + i) = True; 195 } 196 return (retval); 197 } 198 199 /* return the closest point on the upper part of the hue leaf. */ 200 /* must do a bisection here to compute the delta e. */ 201 nMaxCount = MAXBISECTCOUNT; 202 nI = nMaxCount / 2; 203 bestValue = Value = pColor->spec.TekHVC.V; 204 bestChroma = Chroma = pColor->spec.TekHVC.C; 205 saveDist = (XcmsFloat) XCMS_SQRT ((double) (((Chroma - hvc_max.spec.TekHVC.C) * 206 (Chroma - hvc_max.spec.TekHVC.C)) + 207 ((Value - hvc_max.spec.TekHVC.V) * 208 (Value - hvc_max.spec.TekHVC.V)))); 209 for (nCount = 0; nCount < nMaxCount; nCount++) { 210 nT = (XcmsFloat) nI / (XcmsFloat) nMaxCount; 211 pColor->spec.RGBi.red = rgb_max.red * (1.0 - nT) + nT; 212 pColor->spec.RGBi.green = rgb_max.green * (1.0 - nT) + nT; 213 pColor->spec.RGBi.blue = rgb_max.blue * (1.0 - nT) + nT; 214 pColor->format = XcmsRGBiFormat; 215 216 /* Convert from RGBi to HVC */ 217 if (_XcmsConvertColorsWithWhitePt(&myCCC, pColor, 218 &myCCC.pPerScrnInfo->screenWhitePt, 1, XcmsTekHVCFormat, 219 (Bool *) NULL) 220 == XcmsFailure) { 221 return (XcmsFailure); 222 } 223 if (!_XcmsTekHVC_CheckModify(pColor)) { 224 return (XcmsFailure); 225 } 226 tmpDist = (XcmsFloat) XCMS_SQRT ((double) 227 (((Chroma - pColor->spec.TekHVC.C) * 228 (Chroma - pColor->spec.TekHVC.C)) + 229 ((Value - pColor->spec.TekHVC.V) * 230 (Value - pColor->spec.TekHVC.V)))); 231 nILast = nI; 232 if (tmpDist > saveDist) { 233 nI /= 2; 234 } else { 235 nI = (nMaxCount + nI) / 2; 236 saveDist = tmpDist; 237 bestValue = pColor->spec.TekHVC.V; 238 bestChroma = pColor->spec.TekHVC.C; 239 } 240 if (nI == nILast || nI == 0) { 241 break; 242 } 243 244 } 245 246 if (bestChroma >= hvc_max.spec.TekHVC.C) { 247 pColor->spec.TekHVC.C = hvc_max.spec.TekHVC.C; 248 pColor->spec.TekHVC.V = hvc_max.spec.TekHVC.V; 249 } else { 250 pColor->spec.TekHVC.C = bestChroma; 251 pColor->spec.TekHVC.V = bestValue; 252 } 253 if (!_XcmsTekHVC_CheckModify(pColor)) { 254 return (XcmsFailure); 255 } 256 retval = _XcmsDIConvertColors(&myCCC, pColor, 257 &myCCC.pPerScrnInfo->screenWhitePt, 1, XcmsCIEXYZFormat); 258 259 if (retval != XcmsFailure && pCompressed != NULL) { 260 *(pCompressed + i) = True; 261 } 262 return(retval); 263 } 264} 265