LuvGcLC.c revision 61b2299d
11ab64890Smrg/* $Xorg: LuvGcLC.c,v 1.3 2000/08/17 19:44:41 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. Permission is 91ab64890Smrg * hereby granted to use, copy, modify, sell, and otherwise distribute this 101ab64890Smrg * software and its documentation for any purpose and without fee, provided 111ab64890Smrg * that this copyright, permission, and disclaimer notice is reproduced in 121ab64890Smrg * all copies of this software and in supporting documentation. TekColor 131ab64890Smrg * is a trademark of Tektronix, Inc. 1461b2299dSmrg * 151ab64890Smrg * Tektronix makes no representation about the suitability of this software 161ab64890Smrg * for any purpose. It is provided "as is" and with all faults. 1761b2299dSmrg * 181ab64890Smrg * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE, 191ab64890Smrg * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 201ab64890Smrg * PARTICULAR PURPOSE. IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY 211ab64890Smrg * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 221ab64890Smrg * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF 231ab64890Smrg * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 241ab64890Smrg * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE. 251ab64890Smrg * 261ab64890Smrg * NAME 271ab64890Smrg * CIELuvGcLC.c 281ab64890Smrg * 291ab64890Smrg * DESCRIPTION 301ab64890Smrg * Source for XcmsCIELuvClipLuv() gamut 311ab64890Smrg * compression function. 321ab64890Smrg */ 331ab64890Smrg/* $XFree86: xc/lib/X11/LuvGcLC.c,v 1.3 2001/01/17 19:41:39 dawes Exp $ */ 341ab64890Smrg 351ab64890Smrg#ifdef HAVE_CONFIG_H 361ab64890Smrg#include <config.h> 371ab64890Smrg#endif 381ab64890Smrg#include "Xlibint.h" 391ab64890Smrg#include "Xcmsint.h" 401ab64890Smrg#include <math.h> 411ab64890Smrg#include "Cv.h" 421ab64890Smrg 431ab64890Smrg/* 441ab64890Smrg * INTERNALS 451ab64890Smrg * Internal defines that need NOT be exported to any package or 461ab64890Smrg * program using this package. 471ab64890Smrg */ 481ab64890Smrg#define MAXBISECTCOUNT 100 491ab64890Smrg 501ab64890Smrg 511ab64890Smrg/************************************************************************ 521ab64890Smrg * * 531ab64890Smrg * PUBLIC ROUTINES * 541ab64890Smrg * * 551ab64890Smrg ************************************************************************/ 561ab64890Smrg 571ab64890Smrg/* 581ab64890Smrg * NAME 591ab64890Smrg * XcmsCIELuvClipLuv - Return the closest L* and chroma 601ab64890Smrg * 611ab64890Smrg * SYNOPSIS 621ab64890Smrg */ 631ab64890Smrg/* ARGSUSED */ 641ab64890SmrgStatus 651ab64890SmrgXcmsCIELuvClipLuv ( 661ab64890Smrg XcmsCCC ccc, 671ab64890Smrg XcmsColor *pColors_in_out, 681ab64890Smrg unsigned int nColors, 691ab64890Smrg unsigned int i, 701ab64890Smrg Bool *pCompressed) 711ab64890Smrg/* 721ab64890Smrg * DESCRIPTION 7361b2299dSmrg * This routine will find the closest L* and chroma 741ab64890Smrg * for a specific hue. The color input is converted to 751ab64890Smrg * CIE L*u*v* format and returned as CIE XYZ format. 761ab64890Smrg * 771ab64890Smrg * Since this routine works with the L* within 781ab64890Smrg * pColor_in_out intermediate results may be returned 791ab64890Smrg * even though it may be invalid. 801ab64890Smrg * 811ab64890Smrg * RETURNS 821ab64890Smrg * XcmsFailure - Failure 831ab64890Smrg * XcmsSuccess - Succeeded 841ab64890Smrg * 851ab64890Smrg */ 861ab64890Smrg{ 871ab64890Smrg Status retval; 881ab64890Smrg XcmsCCCRec myCCC; 891ab64890Smrg XcmsColor *pColor; 901ab64890Smrg XcmsColor Luv_max; 911ab64890Smrg XcmsFloat hue, chroma, maxChroma; 921ab64890Smrg XcmsFloat Chroma, bestChroma, Lstar, maxLstar, saveLstar; 931ab64890Smrg XcmsFloat bestLstar, bestustar, bestvstar; 941ab64890Smrg XcmsFloat nT, saveDist, tmpDist; 951ab64890Smrg XcmsRGBi rgb_max; 961ab64890Smrg int nCount, nMaxCount, nI, nILast; 971ab64890Smrg 981ab64890Smrg /* Use my own CCC */ 991ab64890Smrg memcpy ((char *)&myCCC, (char *)ccc, sizeof(XcmsCCCRec)); 1001ab64890Smrg myCCC.clientWhitePt.format = XcmsUndefinedFormat;/* inherit screen white */ 1011ab64890Smrg myCCC.gamutCompProc = (XcmsCompressionProc)NULL;/* no gamut compression func */ 1021ab64890Smrg 1031ab64890Smrg /* 1041ab64890Smrg * Color specification passed as input can be assumed to: 1051ab64890Smrg * 1. Be in XcmsCIEXYZFormat 1061ab64890Smrg * 2. Already be white point adjusted for the Screen White Point. 1071ab64890Smrg * This means that the white point now associated with this 1081ab64890Smrg * color spec is the Screen White Point (even if the 1091ab64890Smrg * ccc->clientWhitePt differs). 1101ab64890Smrg */ 1111ab64890Smrg 1121ab64890Smrg pColor = pColors_in_out + i; 1131ab64890Smrg 1141ab64890Smrg if (ccc->visual->class < StaticColor) { 1151ab64890Smrg /* 1161ab64890Smrg * GRAY ! 1171ab64890Smrg */ 1181ab64890Smrg _XcmsDIConvertColors(ccc, pColor, ScreenWhitePointOfCCC(ccc), 1191ab64890Smrg 1, XcmsCIELuvFormat); 1201ab64890Smrg _XcmsDIConvertColors(ccc, pColor, ScreenWhitePointOfCCC(ccc), 1211ab64890Smrg 1, XcmsCIEXYZFormat); 1221ab64890Smrg if (pCompressed) { 1231ab64890Smrg *(pCompressed + i) = True; 1241ab64890Smrg } 1251ab64890Smrg return(XcmsSuccess); 1261ab64890Smrg } 1271ab64890Smrg 1281ab64890Smrg /* Convert from CIEXYZ to CIELuv format */ 1291ab64890Smrg if (_XcmsDIConvertColors(&myCCC, pColor, 1301ab64890Smrg ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIELuvFormat) 1311ab64890Smrg == XcmsFailure) { 1321ab64890Smrg return(XcmsFailure); 1331ab64890Smrg } 1341ab64890Smrg 1351ab64890Smrg /* Step 1: compute the maximum L* and chroma for this hue. */ 1361ab64890Smrg /* This copy may be overkill but it preserves the pixel etc. */ 1371ab64890Smrg saveLstar = pColor->spec.CIELuv.L_star; 1381ab64890Smrg hue = XCMS_CIELUV_PMETRIC_HUE(pColor->spec.CIELuv.u_star, 1391ab64890Smrg pColor->spec.CIELuv.v_star); 1401ab64890Smrg chroma = XCMS_CIELUV_PMETRIC_CHROMA(pColor->spec.CIELuv.u_star, 1411ab64890Smrg pColor->spec.CIELuv.v_star); 1421ab64890Smrg memcpy((char *)&Luv_max, (char *)pColor, sizeof(XcmsColor)); 14361b2299dSmrg if (_XcmsCIELuvQueryMaxLCRGB (&myCCC, hue, &Luv_max, &rgb_max) 1441ab64890Smrg == XcmsFailure) { 1451ab64890Smrg return (XcmsFailure); 1461ab64890Smrg } 1471ab64890Smrg maxLstar = Luv_max.spec.CIELuv.L_star; 14861b2299dSmrg 1491ab64890Smrg /* Now check and return the appropriate L* */ 1501ab64890Smrg if (saveLstar == maxLstar) { 1511ab64890Smrg /* When the L* input is equal to the maximum L* */ 1521ab64890Smrg /* merely return the maximum Luv point. */ 1531ab64890Smrg memcpy((char *)pColor, (char *)&Luv_max, sizeof(XcmsColor)); 1541ab64890Smrg retval = _XcmsDIConvertColors(&myCCC, pColor, 1551ab64890Smrg ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIEXYZFormat); 1561ab64890Smrg } else { 1571ab64890Smrg /* return the closest point on the hue leaf. */ 1581ab64890Smrg /* must do a bisection here to compute the delta e. */ 1591ab64890Smrg maxChroma = XCMS_CIELUV_PMETRIC_CHROMA(Luv_max.spec.CIELuv.u_star, 1601ab64890Smrg Luv_max.spec.CIELuv.v_star); 1611ab64890Smrg nMaxCount = MAXBISECTCOUNT; 1621ab64890Smrg nI = nMaxCount / 2; 1631ab64890Smrg bestLstar = Lstar = pColor->spec.CIELuv.L_star; 1641ab64890Smrg bestustar = pColor->spec.CIELuv.u_star; 1651ab64890Smrg bestvstar = pColor->spec.CIELuv.v_star; 1661ab64890Smrg bestChroma = Chroma = chroma; 1671ab64890Smrg saveDist = XCMS_SQRT(((Chroma - maxChroma) * (Chroma - maxChroma)) + 1681ab64890Smrg ((Lstar - maxLstar) * (Lstar - maxLstar))); 1691ab64890Smrg for (nCount = 0; nCount < nMaxCount; nCount++) { 1701ab64890Smrg nT = (XcmsFloat) nI / (XcmsFloat) nMaxCount; 1711ab64890Smrg if (saveLstar > maxLstar) { 1721ab64890Smrg pColor->spec.RGBi.red = rgb_max.red * (1.0 - nT) + nT; 1731ab64890Smrg pColor->spec.RGBi.green = rgb_max.green * (1.0 - nT) + nT; 1741ab64890Smrg pColor->spec.RGBi.blue = rgb_max.blue * (1.0 - nT) + nT; 1751ab64890Smrg } else { 1761ab64890Smrg pColor->spec.RGBi.red = rgb_max.red - (rgb_max.red * nT); 1771ab64890Smrg pColor->spec.RGBi.green = rgb_max.green - (rgb_max.green * nT); 1781ab64890Smrg pColor->spec.RGBi.blue = rgb_max.blue - (rgb_max.blue * nT); 1791ab64890Smrg } 1801ab64890Smrg pColor->format = XcmsRGBiFormat; 1811ab64890Smrg 1821ab64890Smrg /* Convert from RGBi to CIE Luv */ 1831ab64890Smrg if (_XcmsConvertColorsWithWhitePt(&myCCC, pColor, 1841ab64890Smrg ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIELuvFormat, 1851ab64890Smrg (Bool *) NULL) == XcmsFailure) { 1861ab64890Smrg return (XcmsFailure); 1871ab64890Smrg } 1881ab64890Smrg chroma = XCMS_CIELUV_PMETRIC_CHROMA(pColor->spec.CIELuv.u_star, 1891ab64890Smrg pColor->spec.CIELuv.v_star); 1901ab64890Smrg tmpDist = XCMS_SQRT(((Chroma - chroma) * (Chroma - chroma)) + 1911ab64890Smrg ((Lstar - pColor->spec.CIELuv.L_star) * 1921ab64890Smrg (Lstar - pColor->spec.CIELuv.L_star))); 1931ab64890Smrg nILast = nI; 1941ab64890Smrg if (tmpDist > saveDist) { 1951ab64890Smrg nI /= 2; 1961ab64890Smrg } else { 1971ab64890Smrg nI = (nMaxCount + nI) / 2; 1981ab64890Smrg saveDist = tmpDist; 1991ab64890Smrg bestLstar = pColor->spec.CIELuv.L_star; 2001ab64890Smrg bestustar = pColor->spec.CIELuv.u_star; 2011ab64890Smrg bestvstar = pColor->spec.CIELuv.v_star; 20261b2299dSmrg bestChroma = chroma; 2031ab64890Smrg } 2041ab64890Smrg if (nI == nILast || nI == 0) { 2051ab64890Smrg break; 2061ab64890Smrg } 2071ab64890Smrg } 2081ab64890Smrg if (bestChroma >= maxChroma) { 2091ab64890Smrg pColor->spec.CIELuv.L_star = maxLstar; 2101ab64890Smrg pColor->spec.CIELuv.u_star = Luv_max.spec.CIELuv.u_star; 2111ab64890Smrg pColor->spec.CIELuv.v_star = Luv_max.spec.CIELuv.v_star; 2121ab64890Smrg } else { 2131ab64890Smrg pColor->spec.CIELuv.L_star = bestLstar; 2141ab64890Smrg pColor->spec.CIELuv.u_star = bestustar; 2151ab64890Smrg pColor->spec.CIELuv.v_star = bestvstar; 2161ab64890Smrg } 2171ab64890Smrg retval = _XcmsDIConvertColors(&myCCC, pColor, 2181ab64890Smrg ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIEXYZFormat); 2191ab64890Smrg 2201ab64890Smrg if (retval != XcmsFailure && pCompressed != NULL) { 2211ab64890Smrg *(pCompressed + i) = True; 2221ab64890Smrg } 2231ab64890Smrg } 2241ab64890Smrg return(retval); 2251ab64890Smrg} 226