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 * 26 * 27 * NAME 28 * CIELuvMxVC.c 29 * 30 * DESCRIPTION 31 * Source for the XcmsCIELuvQueryMaxLC() gamut boundary 32 * querying routine. 33 * 34 * DOCUMENTATION 35 * "TekColor Color Management System, System Implementor's Manual" 36 * and 37 * Fred W. Billmeyer & Max Saltzman, "Principles of Color 38 * Technology", John Wily & Sons, Inc, 1981. 39 */ 40 41#ifdef HAVE_CONFIG_H 42#include <config.h> 43#endif 44#include "Xlibint.h" 45#include "Xcmsint.h" 46#include "Cv.h" 47 48/* 49 * DEFINES 50 */ 51#define MIN(x,y) ((x) > (y) ? (y) : (x)) 52#define MIN3(x,y,z) ((x) > (MIN((y), (z))) ? (MIN((y), (z))) : (x)) 53#define MAX(x,y) ((x) > (y) ? (x) : (y)) 54#define MAX3(x,y,z) ((x) > (MAX((y), (z))) ? (x) : (MAX((y), (z)))) 55#define START_LSTAR (XcmsFloat)40.0 56#define START_CHROMA (XcmsFloat)2.2 57 58 59/************************************************************************ 60 * * 61 * API PRIVATE ROUTINES * 62 * * 63 ************************************************************************/ 64 65/* 66 * NAME 67 * _XcmsCIELuvQueryMaxLCRGB - Compute maximum L* and chroma. 68 * 69 * SYNOPSIS 70 */ 71Status 72_XcmsCIELuvQueryMaxLCRGB( 73 XcmsCCC ccc, 74 XcmsFloat hue, /* hue in radians */ 75 XcmsColor *pColor_return, 76 XcmsRGBi *pRGB_return) 77/* 78 * DESCRIPTION 79 * Return the maximum psychometric chroma for a specified 80 * hue angle(radians), and the corresponding L*. This is computed 81 * by a binary search of all possible chromas. An assumption 82 * is made that there are no local maxima. Use the unrounded 83 * Max psychometric chroma because the difference check can be 84 * small. 85 * 86 * NOTE: No local CCC is used because this is a private 87 * routine and all routines that call it are expected 88 * to behave properly, i.e. send a local CCC with 89 * no white adjust function and no gamut compression 90 * function. 91 * 92 * This routine only accepts hue as input and outputs 93 * Luv and RGBi. 94 * 95 * RETURNS 96 * XcmsFailure - Failure 97 * XcmsSuccess - Succeeded 98 * 99 */ 100{ 101 XcmsFloat nSmall, nLarge; 102 XcmsColor tmp; 103 104 tmp.format = XcmsCIELuvFormat; 105 /* Use some unreachable color on the given hue angle */ 106 tmp.spec.CIELuv.L_star = START_LSTAR; 107 tmp.spec.CIELuv.u_star = XCMS_CIEUSTAROFHUE(hue, START_CHROMA); 108 tmp.spec.CIELuv.v_star = XCMS_CIEVSTAROFHUE(hue, START_CHROMA); 109 /* 110 * Convert from Luv to RGB 111 * 112 * Note that the CIEXYZ to RGBi conversion routine must stuff the 113 * out of bounds RGBi values in tmp when the ccc->gamutCompProc 114 * is NULL. 115 */ 116 if ((_XcmsConvertColorsWithWhitePt(ccc, &tmp, ScreenWhitePointOfCCC(ccc), 117 (unsigned int)1, XcmsRGBiFormat, (Bool *) NULL) 118 == XcmsFailure) && tmp.format != XcmsRGBiFormat) { 119 return (XcmsFailure); 120 } 121 122 /* Now pick the smallest RGB */ 123 nSmall = MIN3(tmp.spec.RGBi.red, 124 tmp.spec.RGBi.green, 125 tmp.spec.RGBi.blue); 126 /* Make the smallest RGB equal to zero */ 127 tmp.spec.RGBi.red -= nSmall; 128 tmp.spec.RGBi.green -= nSmall; 129 tmp.spec.RGBi.blue -= nSmall; 130 131 /* Now pick the largest RGB */ 132 nLarge = MAX3(tmp.spec.RGBi.red, 133 tmp.spec.RGBi.green, 134 tmp.spec.RGBi.blue); 135 /* Scale the RGB values based on the largest one */ 136 tmp.spec.RGBi.red /= nLarge; 137 tmp.spec.RGBi.green /= nLarge; 138 tmp.spec.RGBi.blue /= nLarge; 139 tmp.format = XcmsRGBiFormat; 140 141 /* If the calling routine wants RGB value give them the ones used. */ 142 if (pRGB_return) { 143 pRGB_return->red = tmp.spec.RGBi.red; 144 pRGB_return->green = tmp.spec.RGBi.green; 145 pRGB_return->blue = tmp.spec.RGBi.blue; 146 } 147 148 /* Convert from RGBi to Luv */ 149 if (_XcmsConvertColorsWithWhitePt(ccc, &tmp, 150 ScreenWhitePointOfCCC(ccc), 1, XcmsCIELuvFormat, (Bool *) NULL) 151 == XcmsFailure) { 152 return (XcmsFailure); 153 } 154 155 memcpy((char *)pColor_return, (char *)&tmp, sizeof(XcmsColor)); 156 return (XcmsSuccess); 157} 158 159 160/************************************************************************ 161 * * 162 * PUBLIC ROUTINES * 163 * * 164 ************************************************************************/ 165 166/* 167 * NAME 168 * XcmsCIELuvQueryMaxLC - Compute maximum L* and chroma. 169 * 170 * SYNOPSIS 171 */ 172Status 173XcmsCIELuvQueryMaxLC ( 174 XcmsCCC ccc, 175 XcmsFloat hue_angle, /* hue angle in degrees */ 176 XcmsColor *pColor_return) 177 178/* 179 * DESCRIPTION 180 * Return the point of maximum chroma for the specified 181 * hue angle. 182 * 183 * ASSUMPTIONS 184 * This routine assumes that the white point associated with 185 * the color specification is the Screen White Point. The 186 * Screen White Point will also be associated with the 187 * returned color specification. 188 * 189 * RETURNS 190 * XcmsFailure - Failure 191 * XcmsSuccess - Succeeded 192 * 193 */ 194{ 195 XcmsCCCRec myCCC; 196 197 /* 198 * Check Arguments 199 */ 200 if (ccc == NULL || pColor_return == NULL) { 201 return(XcmsFailure); 202 } 203 204 /* Use my own CCC */ 205 memcpy ((char *)&myCCC, (char *)ccc, sizeof(XcmsCCCRec)); 206 myCCC.clientWhitePt.format = XcmsUndefinedFormat; 207 myCCC.gamutCompProc = (XcmsCompressionProc)NULL; 208 209 while (hue_angle < 0.0) { 210 hue_angle += 360.0; 211 } 212 while (hue_angle >= 360.0) { 213 hue_angle -= 360.0; 214 } 215 216 return(_XcmsCIELuvQueryMaxLCRGB (&myCCC, radians(hue_angle), pColor_return, 217 (XcmsRGBi *)NULL)); 218} 219