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