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