Home | History | Annotate | Line # | Download | only in xcms
      1 
      2 /*
      3  * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc.
      4  * 	All Rights Reserved
      5  *
      6  * This file is a component of an X Window System-specific implementation
      7  * of XCMS based on the TekColor Color Management System.  Permission is
      8  * hereby granted to use, copy, modify, sell, and otherwise distribute this
      9  * software and its documentation for any purpose and without fee, provided
     10  * that this copyright, permission, and disclaimer notice is reproduced in
     11  * all copies of this software and in supporting documentation.  TekColor
     12  * is a trademark of Tektronix, Inc.
     13  *
     14  * Tektronix makes no representation about the suitability of this software
     15  * for any purpose.  It is provided "as is" and with all faults.
     16  *
     17  * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE,
     18  * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
     19  * PARTICULAR PURPOSE.  IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY
     20  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
     21  * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF
     22  * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     23  * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE.
     24  *
     25  *	NAME
     26  *		CIELuvMxL.c
     27  *
     28  *	DESCRIPTION
     29  *		Source for the XcmsCIELuvQueryMaxL() gamut boundary
     30  *		querying routine.
     31  *
     32  */
     33 
     34 #ifdef HAVE_CONFIG_H
     35 #include <config.h>
     36 #endif
     37 #include "Xlibint.h"
     38 #include "Xcmsint.h"
     39 #include <math.h>
     40 #include "Cv.h"
     41 
     42 /*
     43  *	DEFINES
     44  */
     45 #define MAXBISECTCOUNT	100
     46 #define EPS		(XcmsFloat)0.001
     47 #define START_L_STAR	(XcmsFloat)40.0
     48 
     49 
     50 /************************************************************************
     52  *									*
     53  *			 PUBLIC ROUTINES				*
     54  *									*
     55  ************************************************************************/
     56 
     57 /*
     58  *	NAME
     59  *		XcmsCIELuvQueryMaxL - Compute max Lstar for a hue and chroma
     60  *
     61  *	SYNOPSIS
     62  */
     63 Status
     64 XcmsCIELuvQueryMaxL(
     65     XcmsCCC ccc,
     66     XcmsFloat hue_angle,	    /* hue angle in degrees */
     67     XcmsFloat chroma,
     68     XcmsColor *pColor_return)
     69 /*
     70  *	DESCRIPTION
     71  *		Return the maximum Lstar for a specified hue_angle and chroma.
     72  *
     73  *	ASSUMPTIONS
     74  *		This routine assumes that the white point associated with
     75  *		the color specification is the Screen White Point.  The
     76  *		Screen White Point will also be associated with the
     77  *		returned color specification.
     78  *
     79  *	RETURNS
     80  *		XcmsFailure - Failure
     81  *              XcmsSuccess - Succeeded with no modifications
     82  *
     83  */
     84 {
     85     XcmsCCCRec	myCCC;
     86     XcmsColor   max_lc, tmp, prev;
     87     XcmsFloat   max_chroma, tmp_chroma;
     88     XcmsFloat   hue, nT, nChroma, lastChroma, prevChroma;
     89     XcmsFloat   rFactor;
     90     XcmsRGBi    rgb_saved;
     91     int         nCount, nMaxCount;
     92 
     93     /*
     94      * Check Arguments
     95      */
     96     if (ccc == NULL || pColor_return == NULL) {
     97 	return(XcmsFailure);
     98     }
     99 
    100     /* setup the CCC to use for the conversions. */
    101     memcpy ((char *) &myCCC, (char *) ccc, sizeof(XcmsCCCRec));
    102     myCCC.clientWhitePt.format = XcmsUndefinedFormat;
    103     myCCC.gamutCompProc = (XcmsCompressionProc) NULL;
    104 
    105     while (hue_angle < 0.0) {
    106 	hue_angle += 360.0;
    107     }
    108     while (hue_angle >= 360.0) {
    109 	hue_angle -= 360.0;
    110     }
    111 
    112     hue = radians(hue_angle);
    113     tmp.spec.CIELuv.L_star = START_L_STAR;
    114     tmp.spec.CIELuv.u_star = XCMS_CIEUSTAROFHUE(hue, chroma);
    115     tmp.spec.CIELuv.v_star = XCMS_CIEVSTAROFHUE(hue, chroma);
    116     tmp.pixel = pColor_return->pixel;
    117     tmp.format = XcmsCIELuvFormat;
    118 
    119     /* Step 1: Obtain the maximum L_star and chroma for this hue. */
    120     if (_XcmsCIELuvQueryMaxLCRGB(&myCCC, hue, &max_lc, &rgb_saved)
    121 	    == XcmsFailure) {
    122 	return(XcmsFailure);
    123     }
    124 
    125     max_chroma = XCMS_CIELUV_PMETRIC_CHROMA(max_lc.spec.CIELuv.u_star,
    126 					    max_lc.spec.CIELuv.v_star);
    127 
    128     if (max_chroma <= chroma) {
    129 	/*
    130 	 *  If the chroma is greater than the chroma for the
    131 	 *  maximum L/chroma point then the L_star is the
    132 	 *  the L_star for the maximum L_star/chroma point.
    133 	 *  This is an error but I return the best approximation I can.
    134          *  Thus the inconsistency.
    135 	 */
    136 	memcpy ((char *) pColor_return, (char *) &max_lc, sizeof (XcmsColor));
    137 	return(XcmsSuccess);
    138     }
    139 
    140     /*
    141      *  If the chroma is equal to the chroma for the
    142      *  maximum L_star/chroma point then the L_star is the
    143      *  the L_star for the maximum L* and chroma point.
    144      */
    145     /* if (max_chroma == chroma) {
    146      *  memcpy ((char *) pColor_return, (char *) &max_lc, sizeof (XcmsColor));
    147      *	return(XcmsSuccess);
    148      *    }
    149      */
    150 
    151     /* must do a bisection here to compute the maximum L* */
    152     /* save the structure input so that any elements that */
    153     /* are not touched are recopied later in the routine. */
    154     nChroma = chroma;
    155     tmp_chroma = max_chroma;
    156     lastChroma = -1.0;
    157     nMaxCount = MAXBISECTCOUNT;
    158     rFactor = 1.0;
    159 
    160     for (nCount = 0; nCount < nMaxCount; nCount++) {
    161 	prevChroma = lastChroma;
    162 	lastChroma = tmp_chroma;
    163 	nT = (1.0 - (nChroma / max_chroma)) * rFactor;
    164 	memcpy ((char *)&prev, (char *)&tmp, sizeof(XcmsColor));
    165 	tmp.spec.RGBi.red   = rgb_saved.red * (1.0 - nT) + nT;
    166 	tmp.spec.RGBi.green = rgb_saved.green * (1.0 - nT) + nT;
    167 	tmp.spec.RGBi.blue  = rgb_saved.blue * (1.0 - nT) + nT;
    168 	tmp.format = XcmsRGBiFormat;
    169 
    170 	/* convert from RGB to CIELuv */
    171 	if (_XcmsConvertColorsWithWhitePt(&myCCC, &tmp,
    172 		ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIELuvFormat,
    173 		(Bool *) NULL) == XcmsFailure) {
    174 	    return(XcmsFailure);
    175 	}
    176 
    177 	/* Now check the return against what is expected */
    178 	tmp_chroma = XCMS_CIELUV_PMETRIC_CHROMA(tmp.spec.CIELuv.u_star,
    179 						tmp.spec.CIELuv.v_star);
    180 	if (tmp_chroma <= chroma + EPS && tmp_chroma >= chroma - EPS) {
    181 	    /* Found It! */
    182 	    memcpy ((char *) pColor_return, (char *) &tmp, sizeof (XcmsColor));
    183 	    return(XcmsSuccess);
    184 	}
    185 	nChroma += chroma - tmp_chroma;
    186 	if (nChroma > max_chroma) {
    187 	    nChroma = max_chroma;
    188 	    rFactor *= 0.5;  /* selective relaxation employed */
    189 	} else if (nChroma < 0.0) {
    190 	    if (XCMS_FABS(lastChroma - chroma) <
    191 		XCMS_FABS(tmp_chroma - chroma)) {
    192 		memcpy ((char *)pColor_return, (char *)&prev,
    193  			sizeof(XcmsColor));
    194 	    } else {
    195 		memcpy ((char *)pColor_return, (char *)&tmp,
    196  			sizeof(XcmsColor));
    197 	    }
    198 	    return(XcmsSuccess);
    199 	} else if (tmp_chroma <= prevChroma + EPS &&
    200 		   tmp_chroma >= prevChroma - EPS) {
    201 	    rFactor *= 0.5;  /* selective relaxation employed */
    202 	}
    203     }
    204 
    205     if (nCount >= nMaxCount) {
    206 	if (XCMS_FABS(lastChroma - chroma) <
    207 	    XCMS_FABS(tmp_chroma - chroma)) {
    208 		memcpy ((char *)pColor_return, (char *)&prev,
    209  			sizeof(XcmsColor));
    210 	    } else {
    211 		memcpy ((char *)pColor_return, (char *)&tmp,
    212  			sizeof(XcmsColor));
    213 	}
    214     }
    215     memcpy ((char *) pColor_return, (char *) &tmp, sizeof (XcmsColor));
    216     return(XcmsSuccess);
    217 }
    218