LuvGcLC.c revision 61b2299d
1/* $Xorg: LuvGcLC.c,v 1.3 2000/08/17 19:44:41 cpqbld Exp $ */ 2 3/* 4 * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc. 5 * All Rights Reserved 6 * 7 * This file is a component of an X Window System-specific implementation 8 * of XCMS based on the TekColor Color Management System. Permission is 9 * hereby granted to use, copy, modify, sell, and otherwise distribute this 10 * software and its documentation for any purpose and without fee, provided 11 * that this copyright, permission, and disclaimer notice is reproduced in 12 * all copies of this software and in supporting documentation. TekColor 13 * is a trademark of Tektronix, Inc. 14 * 15 * Tektronix makes no representation about the suitability of this software 16 * for any purpose. It is provided "as is" and with all faults. 17 * 18 * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE, 19 * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 20 * PARTICULAR PURPOSE. IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY 21 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 22 * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF 23 * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 24 * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE. 25 * 26 * NAME 27 * CIELuvGcLC.c 28 * 29 * DESCRIPTION 30 * Source for XcmsCIELuvClipLuv() gamut 31 * compression function. 32 */ 33/* $XFree86: xc/lib/X11/LuvGcLC.c,v 1.3 2001/01/17 19:41:39 dawes Exp $ */ 34 35#ifdef HAVE_CONFIG_H 36#include <config.h> 37#endif 38#include "Xlibint.h" 39#include "Xcmsint.h" 40#include <math.h> 41#include "Cv.h" 42 43/* 44 * INTERNALS 45 * Internal defines that need NOT be exported to any package or 46 * program using this package. 47 */ 48#define MAXBISECTCOUNT 100 49 50 51/************************************************************************ 52 * * 53 * PUBLIC ROUTINES * 54 * * 55 ************************************************************************/ 56 57/* 58 * NAME 59 * XcmsCIELuvClipLuv - Return the closest L* and chroma 60 * 61 * SYNOPSIS 62 */ 63/* ARGSUSED */ 64Status 65XcmsCIELuvClipLuv ( 66 XcmsCCC ccc, 67 XcmsColor *pColors_in_out, 68 unsigned int nColors, 69 unsigned int i, 70 Bool *pCompressed) 71/* 72 * DESCRIPTION 73 * This routine will find the closest L* and chroma 74 * for a specific hue. The color input is converted to 75 * CIE L*u*v* format and returned as CIE XYZ format. 76 * 77 * Since this routine works with the L* within 78 * pColor_in_out intermediate results may be returned 79 * even though it may be invalid. 80 * 81 * RETURNS 82 * XcmsFailure - Failure 83 * XcmsSuccess - Succeeded 84 * 85 */ 86{ 87 Status retval; 88 XcmsCCCRec myCCC; 89 XcmsColor *pColor; 90 XcmsColor Luv_max; 91 XcmsFloat hue, chroma, maxChroma; 92 XcmsFloat Chroma, bestChroma, Lstar, maxLstar, saveLstar; 93 XcmsFloat bestLstar, bestustar, bestvstar; 94 XcmsFloat nT, saveDist, tmpDist; 95 XcmsRGBi rgb_max; 96 int nCount, nMaxCount, nI, nILast; 97 98 /* Use my own CCC */ 99 memcpy ((char *)&myCCC, (char *)ccc, sizeof(XcmsCCCRec)); 100 myCCC.clientWhitePt.format = XcmsUndefinedFormat;/* inherit screen white */ 101 myCCC.gamutCompProc = (XcmsCompressionProc)NULL;/* no gamut compression func */ 102 103 /* 104 * Color specification passed as input can be assumed to: 105 * 1. Be in XcmsCIEXYZFormat 106 * 2. Already be white point adjusted for the Screen White Point. 107 * This means that the white point now associated with this 108 * color spec is the Screen White Point (even if the 109 * ccc->clientWhitePt differs). 110 */ 111 112 pColor = pColors_in_out + i; 113 114 if (ccc->visual->class < StaticColor) { 115 /* 116 * GRAY ! 117 */ 118 _XcmsDIConvertColors(ccc, pColor, ScreenWhitePointOfCCC(ccc), 119 1, XcmsCIELuvFormat); 120 _XcmsDIConvertColors(ccc, pColor, ScreenWhitePointOfCCC(ccc), 121 1, XcmsCIEXYZFormat); 122 if (pCompressed) { 123 *(pCompressed + i) = True; 124 } 125 return(XcmsSuccess); 126 } 127 128 /* Convert from CIEXYZ to CIELuv format */ 129 if (_XcmsDIConvertColors(&myCCC, pColor, 130 ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIELuvFormat) 131 == XcmsFailure) { 132 return(XcmsFailure); 133 } 134 135 /* Step 1: compute the maximum L* and chroma for this hue. */ 136 /* This copy may be overkill but it preserves the pixel etc. */ 137 saveLstar = pColor->spec.CIELuv.L_star; 138 hue = XCMS_CIELUV_PMETRIC_HUE(pColor->spec.CIELuv.u_star, 139 pColor->spec.CIELuv.v_star); 140 chroma = XCMS_CIELUV_PMETRIC_CHROMA(pColor->spec.CIELuv.u_star, 141 pColor->spec.CIELuv.v_star); 142 memcpy((char *)&Luv_max, (char *)pColor, sizeof(XcmsColor)); 143 if (_XcmsCIELuvQueryMaxLCRGB (&myCCC, hue, &Luv_max, &rgb_max) 144 == XcmsFailure) { 145 return (XcmsFailure); 146 } 147 maxLstar = Luv_max.spec.CIELuv.L_star; 148 149 /* Now check and return the appropriate L* */ 150 if (saveLstar == maxLstar) { 151 /* When the L* input is equal to the maximum L* */ 152 /* merely return the maximum Luv point. */ 153 memcpy((char *)pColor, (char *)&Luv_max, sizeof(XcmsColor)); 154 retval = _XcmsDIConvertColors(&myCCC, pColor, 155 ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIEXYZFormat); 156 } else { 157 /* return the closest point on the hue leaf. */ 158 /* must do a bisection here to compute the delta e. */ 159 maxChroma = XCMS_CIELUV_PMETRIC_CHROMA(Luv_max.spec.CIELuv.u_star, 160 Luv_max.spec.CIELuv.v_star); 161 nMaxCount = MAXBISECTCOUNT; 162 nI = nMaxCount / 2; 163 bestLstar = Lstar = pColor->spec.CIELuv.L_star; 164 bestustar = pColor->spec.CIELuv.u_star; 165 bestvstar = pColor->spec.CIELuv.v_star; 166 bestChroma = Chroma = chroma; 167 saveDist = XCMS_SQRT(((Chroma - maxChroma) * (Chroma - maxChroma)) + 168 ((Lstar - maxLstar) * (Lstar - maxLstar))); 169 for (nCount = 0; nCount < nMaxCount; nCount++) { 170 nT = (XcmsFloat) nI / (XcmsFloat) nMaxCount; 171 if (saveLstar > maxLstar) { 172 pColor->spec.RGBi.red = rgb_max.red * (1.0 - nT) + nT; 173 pColor->spec.RGBi.green = rgb_max.green * (1.0 - nT) + nT; 174 pColor->spec.RGBi.blue = rgb_max.blue * (1.0 - nT) + nT; 175 } else { 176 pColor->spec.RGBi.red = rgb_max.red - (rgb_max.red * nT); 177 pColor->spec.RGBi.green = rgb_max.green - (rgb_max.green * nT); 178 pColor->spec.RGBi.blue = rgb_max.blue - (rgb_max.blue * nT); 179 } 180 pColor->format = XcmsRGBiFormat; 181 182 /* Convert from RGBi to CIE Luv */ 183 if (_XcmsConvertColorsWithWhitePt(&myCCC, pColor, 184 ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIELuvFormat, 185 (Bool *) NULL) == XcmsFailure) { 186 return (XcmsFailure); 187 } 188 chroma = XCMS_CIELUV_PMETRIC_CHROMA(pColor->spec.CIELuv.u_star, 189 pColor->spec.CIELuv.v_star); 190 tmpDist = XCMS_SQRT(((Chroma - chroma) * (Chroma - chroma)) + 191 ((Lstar - pColor->spec.CIELuv.L_star) * 192 (Lstar - pColor->spec.CIELuv.L_star))); 193 nILast = nI; 194 if (tmpDist > saveDist) { 195 nI /= 2; 196 } else { 197 nI = (nMaxCount + nI) / 2; 198 saveDist = tmpDist; 199 bestLstar = pColor->spec.CIELuv.L_star; 200 bestustar = pColor->spec.CIELuv.u_star; 201 bestvstar = pColor->spec.CIELuv.v_star; 202 bestChroma = chroma; 203 } 204 if (nI == nILast || nI == 0) { 205 break; 206 } 207 } 208 if (bestChroma >= maxChroma) { 209 pColor->spec.CIELuv.L_star = maxLstar; 210 pColor->spec.CIELuv.u_star = Luv_max.spec.CIELuv.u_star; 211 pColor->spec.CIELuv.v_star = Luv_max.spec.CIELuv.v_star; 212 } else { 213 pColor->spec.CIELuv.L_star = bestLstar; 214 pColor->spec.CIELuv.u_star = bestustar; 215 pColor->spec.CIELuv.v_star = bestvstar; 216 } 217 retval = _XcmsDIConvertColors(&myCCC, pColor, 218 ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIEXYZFormat); 219 220 if (retval != XcmsFailure && pCompressed != NULL) { 221 *(pCompressed + i) = True; 222 } 223 } 224 return(retval); 225} 226