11ab64890Smrg 21ab64890Smrg/* 31ab64890Smrg * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc. 41ab64890Smrg * All Rights Reserved 561b2299dSmrg * 61ab64890Smrg * This file is a component of an X Window System-specific implementation 71ab64890Smrg * of Xcms based on the TekColor Color Management System. TekColor is a 81ab64890Smrg * trademark of Tektronix, Inc. The term "TekHVC" designates a particular 91ab64890Smrg * color space that is the subject of U.S. Patent No. 4,985,853 (equivalent 101ab64890Smrg * foreign patents pending). Permission is hereby granted to use, copy, 111ab64890Smrg * modify, sell, and otherwise distribute this software and its 121ab64890Smrg * documentation for any purpose and without fee, provided that: 1361b2299dSmrg * 141ab64890Smrg * 1. This copyright, permission, and disclaimer notice is reproduced in 151ab64890Smrg * all copies of this software and any modification thereof and in 1661b2299dSmrg * supporting documentation; 171ab64890Smrg * 2. Any color-handling application which displays TekHVC color 181ab64890Smrg * cooordinates identifies these as TekHVC color coordinates in any 191ab64890Smrg * interface that displays these coordinates and in any associated 201ab64890Smrg * documentation; 211ab64890Smrg * 3. The term "TekHVC" is always used, and is only used, in association 221ab64890Smrg * with the mathematical derivations of the TekHVC Color Space, 231ab64890Smrg * including those provided in this file and any equivalent pathways and 241ab64890Smrg * mathematical derivations, regardless of digital (e.g., floating point 251ab64890Smrg * or integer) representation. 2661b2299dSmrg * 271ab64890Smrg * Tektronix makes no representation about the suitability of this software 281ab64890Smrg * for any purpose. It is provided "as is" and with all faults. 2961b2299dSmrg * 301ab64890Smrg * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE, 311ab64890Smrg * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 321ab64890Smrg * PARTICULAR PURPOSE. IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY 331ab64890Smrg * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 341ab64890Smrg * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF 351ab64890Smrg * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 361ab64890Smrg * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE. 371ab64890Smrg * 381ab64890Smrg * NAME 391ab64890Smrg * TekHVCGcVC.c 401ab64890Smrg * 411ab64890Smrg * DESCRIPTION 421ab64890Smrg * Source for XcmsTekHVCClipVC() gamut 431ab64890Smrg * compression function. 441ab64890Smrg */ 451ab64890Smrg 461ab64890Smrg#ifdef HAVE_CONFIG_H 471ab64890Smrg#include <config.h> 481ab64890Smrg#endif 491ab64890Smrg#include "Xlibint.h" 501ab64890Smrg#include "Xcmsint.h" 511ab64890Smrg#include <math.h> 521ab64890Smrg#include "Cv.h" 531ab64890Smrg 541ab64890Smrg/* 551ab64890Smrg * INTERNALS 561ab64890Smrg * Internal defines that need NOT be exported to any package or 571ab64890Smrg * program using this package. 581ab64890Smrg */ 591ab64890Smrg#define MAXBISECTCOUNT 100 601ab64890Smrg 611ab64890Smrg 621ab64890Smrg/************************************************************************ 631ab64890Smrg * * 641ab64890Smrg * PUBLIC ROUTINES * 651ab64890Smrg * * 661ab64890Smrg ************************************************************************/ 671ab64890Smrg 681ab64890Smrg/* 691ab64890Smrg * NAME 701ab64890Smrg * XcmsTekHVCClipVC - Return the closest value and chroma 711ab64890Smrg * 721ab64890Smrg * SYNOPSIS 731ab64890Smrg */ 741ab64890Smrg/* ARGSUSED */ 751ab64890SmrgStatus 761ab64890SmrgXcmsTekHVCClipVC ( 7761b2299dSmrg XcmsCCC ccc, 7861b2299dSmrg XcmsColor *pColors_in_out, 791ab64890Smrg unsigned int nColors, 801ab64890Smrg unsigned int i, 811ab64890Smrg Bool *pCompressed) 821ab64890Smrg/* 831ab64890Smrg * DESCRIPTION 8461b2299dSmrg * This routine will find the closest value and chroma 851ab64890Smrg * for a specific hue. The color input is converted to 861ab64890Smrg * HVC format and returned as CIE XYZ format. 871ab64890Smrg * 881ab64890Smrg * Since this routine works with the value within 891ab64890Smrg * pColor_in_out intermediate results may be returned 901ab64890Smrg * even though it may be invalid. 911ab64890Smrg * 921ab64890Smrg * RETURNS 931ab64890Smrg * XcmsFailure - Failure 941ab64890Smrg * XcmsSuccess - Succeeded 951ab64890Smrg * 961ab64890Smrg */ 971ab64890Smrg{ 981ab64890Smrg Status retval; 991ab64890Smrg XcmsCCCRec myCCC; 1001ab64890Smrg XcmsColor *pColor; 1011ab64890Smrg XcmsColor hvc_max; 1021ab64890Smrg XcmsRGBi rgb_max; 1031ab64890Smrg int nCount, nMaxCount, nI, nILast; 1041ab64890Smrg XcmsFloat Chroma, Value, bestChroma, bestValue, nT, saveDist, tmpDist; 1051ab64890Smrg 1061ab64890Smrg /* 1071ab64890Smrg * Insure TekHVC installed 1081ab64890Smrg */ 1091ab64890Smrg if (XcmsAddColorSpace(&XcmsTekHVCColorSpace) == XcmsFailure) { 1101ab64890Smrg return(XcmsFailure); 1111ab64890Smrg } 1121ab64890Smrg 1131ab64890Smrg /* Use my own CCC */ 1141ab64890Smrg memcpy ((char *)&myCCC, (char *)ccc, sizeof(XcmsCCCRec)); 1151ab64890Smrg myCCC.clientWhitePt.format = XcmsUndefinedFormat;/* inherit screen white pt */ 1161ab64890Smrg myCCC.gamutCompProc = (XcmsCompressionProc)NULL;/* no gamut compression func */ 1171ab64890Smrg 1181ab64890Smrg /* 1191ab64890Smrg * Color specification passed as input can be assumed to: 1201ab64890Smrg * 1. Be in XcmsCIEXYZFormat 1211ab64890Smrg * 2. Already be white point adjusted for the Screen White Point. 1221ab64890Smrg * This means that the white point now associated with this 1231ab64890Smrg * color spec is the Screen White Point (even if the 1241ab64890Smrg * ccc->clientWhitePt differs). 1251ab64890Smrg */ 1261ab64890Smrg 1271ab64890Smrg pColor = pColors_in_out + i; 1281ab64890Smrg 1291ab64890Smrg if (ccc->visual->class < StaticColor && 1301ab64890Smrg FunctionSetOfCCC(ccc) != (XPointer) &XcmsLinearRGBFunctionSet) { 1311ab64890Smrg /* 1321ab64890Smrg * GRAY ! 1331ab64890Smrg */ 1341ab64890Smrg _XcmsDIConvertColors(ccc, pColor, &ccc->pPerScrnInfo->screenWhitePt, 1351ab64890Smrg 1, XcmsTekHVCFormat); 1361ab64890Smrg pColor->spec.TekHVC.H = pColor->spec.TekHVC.C = 0.0; 1371ab64890Smrg _XcmsDIConvertColors(ccc, pColor, &ccc->pPerScrnInfo->screenWhitePt, 1381ab64890Smrg 1, XcmsCIEXYZFormat); 1391ab64890Smrg if (pCompressed) { 1401ab64890Smrg *(pCompressed + i) = True; 1411ab64890Smrg } 1421ab64890Smrg return(XcmsSuccess); 1431ab64890Smrg } else { 1441ab64890Smrg /* Convert from CIEXYZ to TekHVC format */ 1451ab64890Smrg if (_XcmsDIConvertColors(&myCCC, pColor, 1461ab64890Smrg &myCCC.pPerScrnInfo->screenWhitePt, 1, XcmsTekHVCFormat) 1471ab64890Smrg == XcmsFailure) { 1481ab64890Smrg return(XcmsFailure); 1491ab64890Smrg } 1501ab64890Smrg 1511ab64890Smrg if (!_XcmsTekHVC_CheckModify(pColor)) { 1521ab64890Smrg return (XcmsFailure); 1531ab64890Smrg } 1541ab64890Smrg 1551ab64890Smrg /* Step 1: compute the maximum value and chroma for this hue. */ 1561ab64890Smrg /* This copy may be overkill but it preserves the pixel etc. */ 1571ab64890Smrg memcpy((char *)&hvc_max, (char *)pColor, sizeof(XcmsColor)); 1581ab64890Smrg if (_XcmsTekHVCQueryMaxVCRGB (&myCCC, hvc_max.spec.TekHVC.H, &hvc_max, 1591ab64890Smrg &rgb_max) == XcmsFailure) { 1601ab64890Smrg return (XcmsFailure); 1611ab64890Smrg } 1621ab64890Smrg 1631ab64890Smrg /* Now check and return the appropriate value */ 1641ab64890Smrg if (pColor->spec.TekHVC.V == hvc_max.spec.TekHVC.V) { 1651ab64890Smrg /* When the value input is equal to the maximum value */ 1661ab64890Smrg /* merely return the chroma for that value. */ 1671ab64890Smrg pColor->spec.TekHVC.C = hvc_max.spec.TekHVC.C; 1681ab64890Smrg retval = _XcmsDIConvertColors(&myCCC, pColor, 1691ab64890Smrg &myCCC.pPerScrnInfo->screenWhitePt, 1, XcmsCIEXYZFormat); 1701ab64890Smrg } 1711ab64890Smrg 1721ab64890Smrg if (pColor->spec.TekHVC.V < hvc_max.spec.TekHVC.V) { 1739c019ec5Smaya /* return the intersection of the perpendicular line through */ 1741ab64890Smrg /* the value and chroma given and the line from 0,0 and hvc_max. */ 1751ab64890Smrg Chroma = pColor->spec.TekHVC.C; 1761ab64890Smrg Value = pColor->spec.TekHVC.V; 17761b2299dSmrg pColor->spec.TekHVC.C = 1781ab64890Smrg (Value + (hvc_max.spec.TekHVC.C / hvc_max.spec.TekHVC.V * Chroma)) / 1791ab64890Smrg ((hvc_max.spec.TekHVC.V / hvc_max.spec.TekHVC.C) + 1801ab64890Smrg (hvc_max.spec.TekHVC.C / hvc_max.spec.TekHVC.V)); 1811ab64890Smrg if (pColor->spec.TekHVC.C >= hvc_max.spec.TekHVC.C) { 1821ab64890Smrg pColor->spec.TekHVC.C = hvc_max.spec.TekHVC.C; 1831ab64890Smrg pColor->spec.TekHVC.V = hvc_max.spec.TekHVC.V; 1841ab64890Smrg } else { 1851ab64890Smrg pColor->spec.TekHVC.V = pColor->spec.TekHVC.C * 1861ab64890Smrg hvc_max.spec.TekHVC.V / hvc_max.spec.TekHVC.C; 1871ab64890Smrg } 1881ab64890Smrg retval = _XcmsDIConvertColors(&myCCC, pColor, 1891ab64890Smrg &myCCC.pPerScrnInfo->screenWhitePt, 1, XcmsCIEXYZFormat); 1901ab64890Smrg 1911ab64890Smrg if (retval != XcmsFailure && pCompressed != NULL) { 1921ab64890Smrg *(pCompressed + i) = True; 1931ab64890Smrg } 1941ab64890Smrg return (retval); 1951ab64890Smrg } 1961ab64890Smrg 1971ab64890Smrg /* return the closest point on the upper part of the hue leaf. */ 1981ab64890Smrg /* must do a bisection here to compute the delta e. */ 1991ab64890Smrg nMaxCount = MAXBISECTCOUNT; 2001ab64890Smrg nI = nMaxCount / 2; 2011ab64890Smrg bestValue = Value = pColor->spec.TekHVC.V; 2021ab64890Smrg bestChroma = Chroma = pColor->spec.TekHVC.C; 2031ab64890Smrg saveDist = (XcmsFloat) XCMS_SQRT ((double) (((Chroma - hvc_max.spec.TekHVC.C) * 2041ab64890Smrg (Chroma - hvc_max.spec.TekHVC.C)) + 2051ab64890Smrg ((Value - hvc_max.spec.TekHVC.V) * 2061ab64890Smrg (Value - hvc_max.spec.TekHVC.V)))); 2071ab64890Smrg for (nCount = 0; nCount < nMaxCount; nCount++) { 2081ab64890Smrg nT = (XcmsFloat) nI / (XcmsFloat) nMaxCount; 2091ab64890Smrg pColor->spec.RGBi.red = rgb_max.red * (1.0 - nT) + nT; 2101ab64890Smrg pColor->spec.RGBi.green = rgb_max.green * (1.0 - nT) + nT; 2111ab64890Smrg pColor->spec.RGBi.blue = rgb_max.blue * (1.0 - nT) + nT; 2121ab64890Smrg pColor->format = XcmsRGBiFormat; 2131ab64890Smrg 2141ab64890Smrg /* Convert from RGBi to HVC */ 2151ab64890Smrg if (_XcmsConvertColorsWithWhitePt(&myCCC, pColor, 2161ab64890Smrg &myCCC.pPerScrnInfo->screenWhitePt, 1, XcmsTekHVCFormat, 2171ab64890Smrg (Bool *) NULL) 2181ab64890Smrg == XcmsFailure) { 2191ab64890Smrg return (XcmsFailure); 2201ab64890Smrg } 2211ab64890Smrg if (!_XcmsTekHVC_CheckModify(pColor)) { 2221ab64890Smrg return (XcmsFailure); 2231ab64890Smrg } 22461b2299dSmrg tmpDist = (XcmsFloat) XCMS_SQRT ((double) 2251ab64890Smrg (((Chroma - pColor->spec.TekHVC.C) * 2261ab64890Smrg (Chroma - pColor->spec.TekHVC.C)) + 2271ab64890Smrg ((Value - pColor->spec.TekHVC.V) * 2281ab64890Smrg (Value - pColor->spec.TekHVC.V)))); 2291ab64890Smrg nILast = nI; 2301ab64890Smrg if (tmpDist > saveDist) { 2311ab64890Smrg nI /= 2; 2321ab64890Smrg } else { 2331ab64890Smrg nI = (nMaxCount + nI) / 2; 2341ab64890Smrg saveDist = tmpDist; 2351ab64890Smrg bestValue = pColor->spec.TekHVC.V; 23661b2299dSmrg bestChroma = pColor->spec.TekHVC.C; 2371ab64890Smrg } 2381ab64890Smrg if (nI == nILast || nI == 0) { 2391ab64890Smrg break; 2401ab64890Smrg } 2411ab64890Smrg 2421ab64890Smrg } 2431ab64890Smrg 2441ab64890Smrg if (bestChroma >= hvc_max.spec.TekHVC.C) { 2451ab64890Smrg pColor->spec.TekHVC.C = hvc_max.spec.TekHVC.C; 2461ab64890Smrg pColor->spec.TekHVC.V = hvc_max.spec.TekHVC.V; 2471ab64890Smrg } else { 2481ab64890Smrg pColor->spec.TekHVC.C = bestChroma; 2491ab64890Smrg pColor->spec.TekHVC.V = bestValue; 2501ab64890Smrg } 2511ab64890Smrg if (!_XcmsTekHVC_CheckModify(pColor)) { 2521ab64890Smrg return (XcmsFailure); 2531ab64890Smrg } 2541ab64890Smrg retval = _XcmsDIConvertColors(&myCCC, pColor, 2551ab64890Smrg &myCCC.pPerScrnInfo->screenWhitePt, 1, XcmsCIEXYZFormat); 2561ab64890Smrg 2571ab64890Smrg if (retval != XcmsFailure && pCompressed != NULL) { 2581ab64890Smrg *(pCompressed + i) = True; 2591ab64890Smrg } 2601ab64890Smrg return(retval); 2611ab64890Smrg } 2621ab64890Smrg} 263