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