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 * CIELabGcLC.c 27 * 28 * DESCRIPTION 29 * Source for XcmsCIELabClipLab() gamut 30 * compression function. 31 */ 32 33#ifdef HAVE_CONFIG_H 34#include <config.h> 35#endif 36#include "Xlibint.h" 37#include "Xcmsint.h" 38#include <math.h> 39#include "Cv.h" 40 41/* 42 * INTERNALS 43 * Internal defines that need NOT be exported to any package or 44 * program using this package. 45 */ 46#define MAXBISECTCOUNT 100 47 48 49/************************************************************************ 50 * * 51 * PUBLIC ROUTINES * 52 * * 53 ************************************************************************/ 54 55/* 56 * NAME 57 * XcmsCIELabClipLab - Return the closest L* and chroma 58 * 59 * SYNOPSIS 60 */ 61/* ARGSUSED */ 62Status 63XcmsCIELabClipLab ( 64 XcmsCCC ccc, 65 XcmsColor *pColors_in_out, 66 unsigned int nColors, 67 unsigned int i, 68 Bool *pCompressed) 69/* 70 * DESCRIPTION 71 * This routine will find the closest L* and chroma 72 * for a specific hue. The color input is converted to 73 * CIE L*u*v* format and returned as CIE XYZ format. 74 * 75 * Since this routine works with the L* within 76 * pColor_in_out intermediate results may be returned 77 * even though it may be invalid. 78 * 79 * RETURNS 80 * XcmsFailure - Failure 81 * XcmsSuccess - Succeeded 82 * 83 */ 84{ 85 Status retval; 86 XcmsCCCRec myCCC; 87 XcmsColor *pColor; 88 XcmsColor Lab_max; 89 XcmsFloat hue, chroma, maxChroma; 90 XcmsFloat Chroma, bestChroma, Lstar, maxLstar, saveLstar; 91 XcmsFloat bestLstar, bestastar, bestbstar; 92 XcmsFloat nT, saveDist, tmpDist; 93 XcmsRGBi rgb_max; 94 int nCount, nMaxCount, nI, nILast; 95 96 /* Use my own CCC */ 97 memcpy ((char *)&myCCC, (char *)ccc, sizeof(XcmsCCCRec)); 98 myCCC.clientWhitePt.format = XcmsUndefinedFormat;/* inherit screen white */ 99 myCCC.gamutCompProc = (XcmsCompressionProc)NULL;/* no gamut compression func */ 100 101 /* 102 * Color specification passed as input can be assumed to: 103 * 1. Be in XcmsCIEXYZFormat 104 * 2. Already be white point adjusted for the Screen White Point. 105 * This means that the white point now associated with this 106 * color spec is the Screen White Point (even if the 107 * ccc->clientWhitePt differs). 108 */ 109 110 pColor = pColors_in_out + i; 111 112 if (ccc->visual->class < StaticColor) { 113 /* 114 * GRAY ! 115 */ 116 _XcmsDIConvertColors(ccc, pColor, ScreenWhitePointOfCCC(ccc), 117 1, XcmsCIELabFormat); 118 _XcmsDIConvertColors(ccc, pColor, ScreenWhitePointOfCCC(ccc), 119 1, XcmsCIEXYZFormat); 120 if (pCompressed) { 121 *(pCompressed + i) = True; 122 } 123 return(XcmsSuccess); 124 } 125 126 /* Convert from CIEXYZ to CIELab format */ 127 if (_XcmsDIConvertColors(&myCCC, pColor, 128 ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIELabFormat) 129 == XcmsFailure) { 130 return(XcmsFailure); 131 } 132 133 /* Step 1: compute the maximum L* and chroma for this hue. */ 134 /* This copy may be overkill but it preserves the pixel etc. */ 135 saveLstar = pColor->spec.CIELab.L_star; 136 hue = XCMS_CIELAB_PMETRIC_HUE(pColor->spec.CIELab.a_star, 137 pColor->spec.CIELab.b_star); 138 chroma = XCMS_CIELAB_PMETRIC_CHROMA(pColor->spec.CIELab.a_star, 139 pColor->spec.CIELab.b_star); 140 memcpy((char *)&Lab_max, (char *)pColor, sizeof(XcmsColor)); 141 if (_XcmsCIELabQueryMaxLCRGB (&myCCC, hue, &Lab_max, &rgb_max) 142 == XcmsFailure) { 143 return (XcmsFailure); 144 } 145 maxLstar = Lab_max.spec.CIELab.L_star; 146 147 /* Now check and return the appropriate L* */ 148 if (saveLstar == maxLstar) { 149 /* When the L* input is equal to the maximum L* */ 150 /* merely return the maximum Lab point. */ 151 memcpy((char *)pColor, (char *)&Lab_max, sizeof(XcmsColor)); 152 retval = _XcmsDIConvertColors(&myCCC, pColor, 153 ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIEXYZFormat); 154 } else { 155 /* return the closest point on the hue leaf. */ 156 /* must do a bisection here to compute the delta e. */ 157 maxChroma = XCMS_CIELAB_PMETRIC_CHROMA(Lab_max.spec.CIELab.a_star, 158 Lab_max.spec.CIELab.b_star); 159 nMaxCount = MAXBISECTCOUNT; 160 nI = nMaxCount / 2; 161 bestLstar = Lstar = pColor->spec.CIELab.L_star; 162 bestastar = pColor->spec.CIELab.a_star; 163 bestbstar = pColor->spec.CIELab.b_star; 164 bestChroma = Chroma = chroma; 165 saveDist = XCMS_SQRT(((Chroma - maxChroma) * (Chroma - maxChroma)) + 166 ((Lstar - maxLstar) * (Lstar - maxLstar))); 167 for (nCount = 0; nCount < nMaxCount; nCount++) { 168 nT = (XcmsFloat) nI / (XcmsFloat) nMaxCount; 169 if (saveLstar > maxLstar) { 170 pColor->spec.RGBi.red = rgb_max.red * (1.0 - nT) + nT; 171 pColor->spec.RGBi.green = rgb_max.green * (1.0 - nT) + nT; 172 pColor->spec.RGBi.blue = rgb_max.blue * (1.0 - nT) + nT; 173 } else { 174 pColor->spec.RGBi.red = rgb_max.red - (rgb_max.red * nT); 175 pColor->spec.RGBi.green = rgb_max.green - (rgb_max.green * nT); 176 pColor->spec.RGBi.blue = rgb_max.blue - (rgb_max.blue * nT); 177 } 178 pColor->format = XcmsRGBiFormat; 179 180 /* Convert from RGBi to CIE Lab */ 181 if (_XcmsConvertColorsWithWhitePt(&myCCC, pColor, 182 ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIELabFormat, 183 (Bool *) NULL) == XcmsFailure) { 184 return (XcmsFailure); 185 } 186 chroma = XCMS_CIELAB_PMETRIC_CHROMA(pColor->spec.CIELab.a_star, 187 pColor->spec.CIELab.b_star); 188 tmpDist = XCMS_SQRT(((Chroma - chroma) * (Chroma - chroma)) + 189 ((Lstar - pColor->spec.CIELab.L_star) * 190 (Lstar - pColor->spec.CIELab.L_star))); 191 nILast = nI; 192 if (tmpDist > saveDist) { 193 nI /= 2; 194 } else { 195 nI = (nMaxCount + nI) / 2; 196 saveDist = tmpDist; 197 bestLstar = pColor->spec.CIELab.L_star; 198 bestastar = pColor->spec.CIELab.a_star; 199 bestbstar = pColor->spec.CIELab.b_star; 200 bestChroma = chroma; 201 } 202 if (nI == nILast || nI == 0) { 203 break; 204 } 205 } 206 if (bestChroma >= maxChroma) { 207 pColor->spec.CIELab.L_star = maxLstar; 208 pColor->spec.CIELab.a_star = Lab_max.spec.CIELab.a_star; 209 pColor->spec.CIELab.b_star = Lab_max.spec.CIELab.b_star; 210 } else { 211 pColor->spec.CIELab.L_star = bestLstar; 212 pColor->spec.CIELab.a_star = bestastar; 213 pColor->spec.CIELab.b_star = bestbstar; 214 } 215 retval = _XcmsDIConvertColors(&myCCC, pColor, 216 ScreenWhitePointOfCCC(&myCCC), 1, XcmsCIEXYZFormat); 217 218 if (retval != XcmsFailure && pCompressed != NULL) { 219 *(pCompressed + i) = True; 220 } 221 } 222 return(retval); 223} 224