HVCMxV.c revision 61b2299d
11ab64890Smrg/* $Xorg: HVCMxV.c,v 1.3 2000/08/17 19:44:37 cpqbld Exp $ */ 21ab64890Smrg 31ab64890Smrg/* 41ab64890Smrg * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc. 51ab64890Smrg * All Rights Reserved 661b2299dSmrg * 71ab64890Smrg * This file is a component of an X Window System-specific implementation 81ab64890Smrg * of Xcms based on the TekColor Color Management System. TekColor is a 91ab64890Smrg * trademark of Tektronix, Inc. The term "TekHVC" designates a particular 101ab64890Smrg * color space that is the subject of U.S. Patent No. 4,985,853 (equivalent 111ab64890Smrg * foreign patents pending). Permission is hereby granted to use, copy, 121ab64890Smrg * modify, sell, and otherwise distribute this software and its 131ab64890Smrg * documentation for any purpose and without fee, provided that: 1461b2299dSmrg * 151ab64890Smrg * 1. This copyright, permission, and disclaimer notice is reproduced in 161ab64890Smrg * all copies of this software and any modification thereof and in 1761b2299dSmrg * supporting documentation; 181ab64890Smrg * 2. Any color-handling application which displays TekHVC color 191ab64890Smrg * cooordinates identifies these as TekHVC color coordinates in any 201ab64890Smrg * interface that displays these coordinates and in any associated 211ab64890Smrg * documentation; 221ab64890Smrg * 3. The term "TekHVC" is always used, and is only used, in association 231ab64890Smrg * with the mathematical derivations of the TekHVC Color Space, 241ab64890Smrg * including those provided in this file and any equivalent pathways and 251ab64890Smrg * mathematical derivations, regardless of digital (e.g., floating point 261ab64890Smrg * or integer) representation. 2761b2299dSmrg * 281ab64890Smrg * Tektronix makes no representation about the suitability of this software 291ab64890Smrg * for any purpose. It is provided "as is" and with all faults. 3061b2299dSmrg * 311ab64890Smrg * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE, 321ab64890Smrg * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 331ab64890Smrg * PARTICULAR PURPOSE. IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY 341ab64890Smrg * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 351ab64890Smrg * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF 361ab64890Smrg * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 371ab64890Smrg * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE. 381ab64890Smrg * 391ab64890Smrg * NAME 401ab64890Smrg * TekHVCMxV.c 411ab64890Smrg * 421ab64890Smrg * DESCRIPTION 431ab64890Smrg * Source for the XcmsTekHVCQueryMaxV() gamut boundary 441ab64890Smrg * querying routine. 451ab64890Smrg * 461ab64890Smrg */ 471ab64890Smrg/* $XFree86: xc/lib/X11/HVCMxV.c,v 1.4 2003/04/13 19:22:16 dawes Exp $ */ 481ab64890Smrg 491ab64890Smrg#ifdef HAVE_CONFIG_H 501ab64890Smrg#include <config.h> 511ab64890Smrg#endif 521ab64890Smrg#include "Xlibint.h" 531ab64890Smrg#include "Xcmsint.h" 541ab64890Smrg#include <math.h> 551ab64890Smrg#include "Cv.h" 561ab64890Smrg 571ab64890Smrg/* 581ab64890Smrg * DEFINES 591ab64890Smrg */ 601ab64890Smrg#define MAXBISECTCOUNT 100 611ab64890Smrg#define EPS 0.001 621ab64890Smrg 631ab64890Smrg 641ab64890Smrg/************************************************************************ 651ab64890Smrg * * 661ab64890Smrg * PUBLIC ROUTINES * 671ab64890Smrg * * 681ab64890Smrg ************************************************************************/ 691ab64890Smrg 701ab64890Smrg/* 711ab64890Smrg * NAME 721ab64890Smrg * XcmsTekHVCQueryMaxV - Compute maximum value for a hue and chroma 731ab64890Smrg * 741ab64890Smrg * SYNOPSIS 751ab64890Smrg */ 761ab64890SmrgStatus 771ab64890SmrgXcmsTekHVCQueryMaxV( 781ab64890Smrg XcmsCCC ccc, 791ab64890Smrg XcmsFloat hue, 801ab64890Smrg XcmsFloat chroma, 811ab64890Smrg XcmsColor *pColor_return) 821ab64890Smrg/* 831ab64890Smrg * DESCRIPTION 841ab64890Smrg * Return the maximum value for a specified hue and chroma. 851ab64890Smrg * 861ab64890Smrg * ASSUMPTIONS 871ab64890Smrg * This routine assumes that the white point associated with 881ab64890Smrg * the color specification is the Screen White Point. The 891ab64890Smrg * Screen White Point will also be associated with the 901ab64890Smrg * returned color specification. 911ab64890Smrg * 921ab64890Smrg * RETURNS 931ab64890Smrg * XcmsFailure - Failure 941ab64890Smrg * XcmsSuccess - Succeeded with no modifications 951ab64890Smrg * 961ab64890Smrg */ 971ab64890Smrg{ 981ab64890Smrg XcmsCCCRec myCCC; 991ab64890Smrg XcmsColor tmp; 1001ab64890Smrg XcmsColor max_vc; 1011ab64890Smrg XcmsRGBi rgb_saved; 1021ab64890Smrg int nCount, nMaxCount; 1031ab64890Smrg XcmsFloat nT, nChroma, savedChroma, lastValue, lastChroma, prevChroma; 1041ab64890Smrg XcmsFloat rFactor; 1051ab64890Smrg XcmsFloat ftmp1, ftmp2; 1061ab64890Smrg 1071ab64890Smrg /* 1081ab64890Smrg * Check Arguments 1091ab64890Smrg */ 1101ab64890Smrg if (ccc == NULL || pColor_return == NULL) { 1111ab64890Smrg return(XcmsFailure); 1121ab64890Smrg } 1131ab64890Smrg 1141ab64890Smrg /* 1151ab64890Smrg * Insure TekHVC installed 1161ab64890Smrg */ 1171ab64890Smrg if (XcmsAddColorSpace(&XcmsTekHVCColorSpace) == XcmsFailure) { 1181ab64890Smrg return(XcmsFailure); 1191ab64890Smrg } 1201ab64890Smrg 1211ab64890Smrg /* setup the CCC to use for the conversions. */ 1221ab64890Smrg memcpy ((char *) &myCCC, (char *) ccc, sizeof(XcmsCCCRec)); 1231ab64890Smrg myCCC.clientWhitePt.format = XcmsUndefinedFormat; 1241ab64890Smrg myCCC.gamutCompProc = (XcmsCompressionProc) NULL; 1251ab64890Smrg 1261ab64890Smrg tmp.spec.TekHVC.H = hue; 1271ab64890Smrg tmp.spec.TekHVC.V = 0.0; 1281ab64890Smrg tmp.spec.TekHVC.C = chroma; 1291ab64890Smrg tmp.pixel = pColor_return->pixel; 1301ab64890Smrg tmp.format = XcmsTekHVCFormat; 1311ab64890Smrg 1321ab64890Smrg if (!_XcmsTekHVC_CheckModify (&tmp)) { 1331ab64890Smrg return(XcmsFailure); 1341ab64890Smrg } 1351ab64890Smrg 1361ab64890Smrg /* Step 1: compute the maximum value and chroma for this hue. */ 1371ab64890Smrg /* This copy may be overkill but it preserves the pixel etc. */ 1381ab64890Smrg memcpy((char *)&max_vc, (char *)&tmp, sizeof(XcmsColor)); 1391ab64890Smrg hue = max_vc.spec.TekHVC.H; 1401ab64890Smrg if (_XcmsTekHVCQueryMaxVCRGB(&myCCC, max_vc.spec.TekHVC.H, &max_vc, &rgb_saved) 1411ab64890Smrg == XcmsFailure) { 1421ab64890Smrg return(XcmsFailure); 1431ab64890Smrg } 1441ab64890Smrg 1451ab64890Smrg if (max_vc.spec.TekHVC.C < tmp.spec.TekHVC.C) { 1461ab64890Smrg /* 14761b2299dSmrg * If the chroma is greater than the chroma for the 1481ab64890Smrg * maximum value/chroma point then the value is the 1491ab64890Smrg * the value for the maximum value, chroma point. 1501ab64890Smrg * This is an error but it I return the best approximation I can. 1511ab64890Smrg * Thus the inconsistency. 1521ab64890Smrg */ 1531ab64890Smrg tmp.spec.TekHVC.C = max_vc.spec.TekHVC.C; 1541ab64890Smrg tmp.spec.TekHVC.V = max_vc.spec.TekHVC.V; 1551ab64890Smrg memcpy ((char *) pColor_return, (char *) &tmp, sizeof (XcmsColor)); 1561ab64890Smrg return(XcmsSuccess); 1571ab64890Smrg } else if (max_vc.spec.TekHVC.C == tmp.spec.TekHVC.C) { 1581ab64890Smrg /* 15961b2299dSmrg * If the chroma is equal to the chroma for the 1601ab64890Smrg * maximum value/chroma point then the value is the 1611ab64890Smrg * the value for the maximum value, chroma point. 1621ab64890Smrg */ 1631ab64890Smrg tmp.spec.TekHVC.V = max_vc.spec.TekHVC.V; 1641ab64890Smrg memcpy ((char *) pColor_return, (char *) &tmp, sizeof (XcmsColor)); 1651ab64890Smrg return(XcmsSuccess); 1661ab64890Smrg } else { 1671ab64890Smrg /* must do a bisection here to compute the maximum value */ 1681ab64890Smrg /* save the structure input so that any elements that */ 1691ab64890Smrg /* are not touched are recopied later in the routine. */ 1701ab64890Smrg nChroma = savedChroma = tmp.spec.TekHVC.C; 1711ab64890Smrg tmp.spec.TekHVC.C = max_vc.spec.TekHVC.C; 1721ab64890Smrg tmp.spec.TekHVC.V = max_vc.spec.TekHVC.V; 1731ab64890Smrg lastChroma = -1.0; 1741ab64890Smrg lastValue = -1.0; 1751ab64890Smrg nMaxCount = MAXBISECTCOUNT; 1761ab64890Smrg rFactor = 1.0; 1771ab64890Smrg 1781ab64890Smrg for (nCount = 0; nCount < nMaxCount; nCount++) { 1791ab64890Smrg prevChroma = lastChroma; 1801ab64890Smrg lastValue = tmp.spec.TekHVC.V; 1811ab64890Smrg lastChroma = tmp.spec.TekHVC.C; 1821ab64890Smrg nT = (1.0 - (nChroma / max_vc.spec.TekHVC.C)) * rFactor; 1831ab64890Smrg tmp.spec.RGBi.red = rgb_saved.red * (1.0 - nT) + nT; 1841ab64890Smrg tmp.spec.RGBi.green = rgb_saved.green * (1.0 - nT) + nT; 1851ab64890Smrg tmp.spec.RGBi.blue = rgb_saved.blue * (1.0 - nT) + nT; 1861ab64890Smrg tmp.format = XcmsRGBiFormat; 1871ab64890Smrg 1881ab64890Smrg /* convert from RGB to HVC */ 1891ab64890Smrg if (_XcmsConvertColorsWithWhitePt(&myCCC, &tmp, 1901ab64890Smrg &myCCC.pPerScrnInfo->screenWhitePt, 1, XcmsTekHVCFormat, 1911ab64890Smrg (Bool *) NULL) == XcmsFailure) { 1921ab64890Smrg return(XcmsFailure); 1931ab64890Smrg } 1941ab64890Smrg 1951ab64890Smrg /* Now check the return against what is expected */ 1961ab64890Smrg if (tmp.spec.TekHVC.C <= savedChroma + EPS && 1971ab64890Smrg tmp.spec.TekHVC.C >= savedChroma - EPS) { 1981ab64890Smrg tmp.spec.TekHVC.H = hue; /* use the saved hue */ 1991ab64890Smrg memcpy ((char *) pColor_return, (char *) &tmp, sizeof (XcmsColor)); 2001ab64890Smrg return(XcmsSuccess); 20161b2299dSmrg } 2021ab64890Smrg nChroma += savedChroma - tmp.spec.TekHVC.C; 2031ab64890Smrg if (nChroma > max_vc.spec.TekHVC.C) { 2041ab64890Smrg nChroma = max_vc.spec.TekHVC.C; 2051ab64890Smrg rFactor *= 0.5; /* selective relaxation employed */ 2061ab64890Smrg } else if (nChroma < 0.0) { 2071ab64890Smrg /* avoid using fabs */ 2081ab64890Smrg ftmp1 = lastChroma - savedChroma; 2091ab64890Smrg if (ftmp1 < 0.0) 2101ab64890Smrg ftmp1 = -ftmp1; 2111ab64890Smrg ftmp2 = tmp.spec.TekHVC.C - savedChroma; 2121ab64890Smrg if (ftmp2 < 0.0) 2131ab64890Smrg ftmp2 = -ftmp2; 2141ab64890Smrg if (ftmp1 < ftmp2) { 2151ab64890Smrg tmp.spec.TekHVC.V = lastValue; 2161ab64890Smrg tmp.spec.TekHVC.C = lastChroma; 2171ab64890Smrg } 2181ab64890Smrg /* make sure to return the input hue */ 2191ab64890Smrg tmp.spec.TekHVC.H = hue; 2201ab64890Smrg if (!_XcmsTekHVC_CheckModify(&tmp)) { 2211ab64890Smrg return(XcmsFailure); 2221ab64890Smrg } 2231ab64890Smrg memcpy ((char *) pColor_return, (char *) &tmp, sizeof (XcmsColor)); 2241ab64890Smrg return(XcmsSuccess); 2251ab64890Smrg } else if (tmp.spec.TekHVC.C <= prevChroma + EPS && 2261ab64890Smrg tmp.spec.TekHVC.C >= prevChroma - EPS) { 2271ab64890Smrg rFactor *= 0.5; /* selective relaxation employed */ 2281ab64890Smrg } 2291ab64890Smrg } 2301ab64890Smrg if (nCount >= nMaxCount) { 2311ab64890Smrg /* avoid using fabs */ 2321ab64890Smrg ftmp1 = lastChroma - savedChroma; 2331ab64890Smrg if (ftmp1 < 0.0) 2341ab64890Smrg ftmp1 = -ftmp1; 2351ab64890Smrg ftmp2 = tmp.spec.TekHVC.C - savedChroma; 2361ab64890Smrg if (ftmp2 < 0.0) 2371ab64890Smrg ftmp2 = -ftmp2; 2381ab64890Smrg if (ftmp1 < ftmp2) { 2391ab64890Smrg tmp.spec.TekHVC.V = lastValue; 2401ab64890Smrg tmp.spec.TekHVC.C = lastChroma; 2411ab64890Smrg } 2421ab64890Smrg } 2431ab64890Smrg } 2441ab64890Smrg 2451ab64890Smrg /* make sure to return the input hue */ 2461ab64890Smrg tmp.spec.TekHVC.H = hue; 2471ab64890Smrg memcpy ((char *) pColor_return, (char *) &tmp, sizeof (XcmsColor)); 2481ab64890Smrg return(XcmsSuccess); 2491ab64890Smrg} 250