Luv.c revision 1ab64890
1/* $Xorg: Luv.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 * 27 * NAME 28 * CIELuv.c 29 * 30 * DESCRIPTION 31 * This file contains routines that support the CIE L*u*v* 32 * color space to include conversions to and from the CIE 33 * XYZ space. 34 * 35 * DOCUMENTATION 36 * "TekColor Color Management System, System Implementor's Manual" 37 * and 38 * Fred W. Billmeyer & Max Saltzman, "Principles of Color 39 * Technology", John Wily & Sons, Inc, 1981. 40 */ 41/* $XFree86: xc/lib/X11/Luv.c,v 1.3 2001/01/17 19:41:39 dawes Exp $ */ 42 43#ifdef HAVE_CONFIG_H 44#include <config.h> 45#endif 46#include <X11/Xos.h> 47#include "Xlibint.h" 48#include "Xcmsint.h" 49#include "Cv.h" 50 51#include <stdio.h> /* sscanf */ 52 53 54/* 55 * FORWARD DECLARATIONS 56 */ 57 58static int CIELuv_ParseString(register char *spec, XcmsColor *pColor); 59static Status XcmsCIELuv_ValidSpec(XcmsColor *pColor); 60 61/* 62 * DEFINES 63 * Internal definitions that need NOT be exported to any package 64 * or program using this package. 65 */ 66#ifdef DBL_EPSILON 67# define XMY_DBL_EPSILON DBL_EPSILON 68#else 69# define XMY_DBL_EPSILON 0.00001 70#endif 71 72 73/* 74 * LOCAL VARIABLES 75 */ 76 77 /* 78 * NULL terminated list of functions applied to get from CIELuv to CIEXYZ 79 */ 80static XcmsConversionProc Fl_CIELuv_to_CIEXYZ[] = { 81 XcmsCIELuvToCIEuvY, 82 XcmsCIEuvYToCIEXYZ, 83 NULL 84}; 85 86 /* 87 * NULL terminated list of functions applied to get from CIEXYZ to CIELuv 88 */ 89static XcmsConversionProc Fl_CIEXYZ_to_CIELuv[] = { 90 XcmsCIEXYZToCIEuvY, 91 XcmsCIEuvYToCIELuv, 92 NULL 93}; 94 95/* 96 * GLOBALS 97 */ 98 99 /* 100 * CIE Luv Color Space 101 */ 102XcmsColorSpace XcmsCIELuvColorSpace = 103 { 104 _XcmsCIELuv_prefix, /* prefix */ 105 XcmsCIELuvFormat, /* id */ 106 CIELuv_ParseString, /* parseString */ 107 Fl_CIELuv_to_CIEXYZ, /* to_CIEXYZ */ 108 Fl_CIEXYZ_to_CIELuv, /* from_CIEXYZ */ 109 1 110 }; 111 112 113/************************************************************************ 114 * * 115 * PRIVATE ROUTINES * 116 * * 117 ************************************************************************/ 118 119/* 120 * NAME 121 * CIELuv_ParseString 122 * 123 * SYNOPSIS 124 */ 125static int 126CIELuv_ParseString( 127 register char *spec, 128 XcmsColor *pColor) 129/* 130 * DESCRIPTION 131 * This routines takes a string and attempts to convert 132 * it into a XcmsColor structure with XcmsCIELuvFormat. 133 * The assumed CIELuv string syntax is: 134 * CIELuv:<L>/<u>/<v> 135 * Where L, u, and v are in string input format for floats 136 * consisting of: 137 * a. an optional sign 138 * b. a string of numbers possibly containing a decimal point, 139 * c. an optional exponent field containing an 'E' or 'e' 140 * followed by a possibly signed integer string. 141 * 142 * RETURNS 143 * 0 if failed, non-zero otherwise. 144 */ 145{ 146 int n; 147 char *pchar; 148 149 if ((pchar = strchr(spec, ':')) == NULL) { 150 return(XcmsFailure); 151 } 152 n = (int)(pchar - spec); 153 154 /* 155 * Check for proper prefix. 156 */ 157 if (strncmp(spec, _XcmsCIELuv_prefix, n) != 0) { 158 return(XcmsFailure); 159 } 160 161 /* 162 * Attempt to parse the value portion. 163 */ 164 if (sscanf(spec + n + 1, "%lf/%lf/%lf", 165 &pColor->spec.CIELuv.L_star, 166 &pColor->spec.CIELuv.u_star, 167 &pColor->spec.CIELuv.v_star) != 3) { 168 char *s; /* Maybe failed due to locale */ 169 int f; 170 if ((s = strdup(spec))) { 171 for (f = 0; s[f]; ++f) 172 if (s[f] == '.') 173 s[f] = ','; 174 else if (s[f] == ',') 175 s[f] = '.'; 176 if (sscanf(s + n + 1, "%lf/%lf/%lf", 177 &pColor->spec.CIELuv.L_star, 178 &pColor->spec.CIELuv.u_star, 179 &pColor->spec.CIELuv.v_star) != 3) { 180 free(s); 181 return(XcmsFailure); 182 } 183 free(s); 184 } else 185 return(XcmsFailure); 186 } 187 pColor->format = XcmsCIELuvFormat; 188 pColor->pixel = 0; 189 return(XcmsCIELuv_ValidSpec(pColor)); 190} 191 192 193/************************************************************************ 194 * * 195 * PUBLIC ROUTINES * 196 * * 197 ************************************************************************/ 198 199/* 200 * NAME 201 * XcmsCIELuv_ValidSpec 202 * 203 * SYNOPSIS 204 */ 205static Status 206XcmsCIELuv_ValidSpec( 207 XcmsColor *pColor) 208/* 209 * DESCRIPTION 210 * Checks if color specification valid for CIE L*u*v*. 211 * 212 * RETURNS 213 * XcmsFailure if invalid, 214 * XcmsSuccess if valid. 215 * 216 */ 217{ 218 if (pColor->format != XcmsCIELuvFormat 219 || 220 (pColor->spec.CIELuv.L_star < 0.0 - XMY_DBL_EPSILON) 221 || 222 (pColor->spec.CIELuv.L_star > 100.0 + XMY_DBL_EPSILON)) { 223 return(XcmsFailure); 224 } 225 return(XcmsSuccess); 226} 227 228 229/* 230 * NAME 231 * XcmsCIELuvToCIEuvY - convert CIELuv to CIEuvY 232 * 233 * SYNOPSIS 234 */ 235Status 236XcmsCIELuvToCIEuvY( 237 XcmsCCC ccc, 238 XcmsColor *pLuv_WhitePt, 239 XcmsColor *pColors_in_out, 240 unsigned int nColors) 241/* 242 * DESCRIPTION 243 * Converts color specifications in an array of XcmsColor 244 * structures from CIELuv format to CIEuvY format. 245 * 246 * RETURNS 247 * XcmsFailure if failed, 248 * XcmsSuccess if succeeded. 249 * 250 */ 251{ 252 XcmsColor *pColor = pColors_in_out; 253 XcmsColor whitePt; 254 XcmsCIEuvY uvY_return; 255 XcmsFloat tmpVal; 256 register int i; 257 258 /* 259 * Check arguments 260 */ 261 if (pLuv_WhitePt == NULL || pColors_in_out == NULL) { 262 return(XcmsFailure); 263 } 264 265 /* 266 * Make sure white point is in CIEuvY form 267 */ 268 if (pLuv_WhitePt->format != XcmsCIEuvYFormat) { 269 /* Make copy of the white point because we're going to modify it */ 270 memcpy((char *)&whitePt, (char *)pLuv_WhitePt, sizeof(XcmsColor)); 271 if (!_XcmsDIConvertColors(ccc, &whitePt, (XcmsColor *)NULL, 272 1, XcmsCIEuvYFormat)) { 273 return(XcmsFailure); 274 } 275 pLuv_WhitePt = &whitePt; 276 } 277 /* Make sure it is a white point, i.e., Y == 1.0 */ 278 if (pLuv_WhitePt->spec.CIEuvY.Y != 1.0) { 279 return(XcmsFailure); 280 } 281 282 /* 283 * Now convert each XcmsColor structure to CIEXYZ form 284 */ 285 for (i = 0; i < nColors; i++, pColor++) { 286 287 /* Make sure original format is CIELuv and is valid */ 288 if (!XcmsCIELuv_ValidSpec(pColor)) { 289 return(XcmsFailure); 290 } 291 292 if (pColor->spec.CIELuv.L_star < 7.99953624) { 293 uvY_return.Y = pColor->spec.CIELuv.L_star / 903.29; 294 } else { 295 tmpVal = (pColor->spec.CIELuv.L_star + 16.0) / 116.0; 296 uvY_return.Y = tmpVal * tmpVal * tmpVal; /* tmpVal ** 3 */ 297 } 298 299 300 301 if (pColor->spec.CIELuv.L_star == 0.0) { 302 uvY_return.u_prime = pLuv_WhitePt->spec.CIEuvY.u_prime; 303 uvY_return.v_prime = pLuv_WhitePt->spec.CIEuvY.v_prime; 304 } else { 305 tmpVal = 13.0 * (pColor->spec.CIELuv.L_star / 100.0); 306 uvY_return.u_prime = pColor->spec.CIELuv.u_star/tmpVal + 307 pLuv_WhitePt->spec.CIEuvY.u_prime; 308 uvY_return.v_prime = pColor->spec.CIELuv.v_star/tmpVal + 309 pLuv_WhitePt->spec.CIEuvY.v_prime; 310 } 311 /* Copy result to pColor */ 312 memcpy((char *)&pColor->spec, (char *)&uvY_return, sizeof(XcmsCIEuvY)); 313 314 /* Identify that the format is now CIEuvY */ 315 pColor->format = XcmsCIEuvYFormat; 316 } 317 return(XcmsSuccess); 318} 319 320 321/* 322 * NAME 323 * XcmsCIEuvYToCIELuv - convert CIEuvY to CIELuv 324 * 325 * SYNOPSIS 326 */ 327Status 328XcmsCIEuvYToCIELuv( 329 XcmsCCC ccc, 330 XcmsColor *pLuv_WhitePt, 331 XcmsColor *pColors_in_out, 332 unsigned int nColors) 333/* 334 * DESCRIPTION 335 * Converts color specifications in an array of XcmsColor 336 * structures from CIEuvY format to CIELab format. 337 * 338 * RETURNS 339 * XcmsFailure if failed, 340 * XcmsSuccess if succeeded. 341 * 342 */ 343{ 344 XcmsColor *pColor = pColors_in_out; 345 XcmsColor whitePt; 346 XcmsCIELuv Luv_return; 347 XcmsFloat tmpVal; 348 register int i; 349 350 /* 351 * Check arguments 352 */ 353 if (pLuv_WhitePt == NULL || pColors_in_out == NULL) { 354 return(XcmsFailure); 355 } 356 357 /* 358 * Make sure white point is in CIEuvY form 359 */ 360 if (pLuv_WhitePt->format != XcmsCIEuvYFormat) { 361 /* Make copy of the white point because we're going to modify it */ 362 memcpy((char *)&whitePt, (char *)pLuv_WhitePt, sizeof(XcmsColor)); 363 if (!_XcmsDIConvertColors(ccc, &whitePt, 364 (XcmsColor *)NULL, 1, XcmsCIEuvYFormat)) { 365 return(XcmsFailure); 366 } 367 pLuv_WhitePt = &whitePt; 368 } 369 /* Make sure it is a white point, i.e., Y == 1.0 */ 370 if (pLuv_WhitePt->spec.CIEuvY.Y != 1.0) { 371 return(XcmsFailure); 372 } 373 374 /* 375 * Now convert each XcmsColor structure to CIEXYZ form 376 */ 377 for (i = 0; i < nColors; i++, pColor++) { 378 379 if (!_XcmsCIEuvY_ValidSpec(pColor)) { 380 return(XcmsFailure); 381 } 382 383 /* Now convert the uvY to Luv */ 384 Luv_return.L_star = 385 (pColor->spec.CIEuvY.Y < 0.008856) 386 ? 387 (pColor->spec.CIEuvY.Y * 903.29) 388 : 389 ((XcmsFloat)(XCMS_CUBEROOT(pColor->spec.CIEuvY.Y) * 116.0) - 16.0); 390 tmpVal = 13.0 * (Luv_return.L_star / 100.0); 391 Luv_return.u_star = tmpVal * 392 (pColor->spec.CIEuvY.u_prime - pLuv_WhitePt->spec.CIEuvY.u_prime); 393 Luv_return.v_star = tmpVal * 394 (pColor->spec.CIEuvY.v_prime - pLuv_WhitePt->spec.CIEuvY.v_prime); 395 396 /* Copy result to pColor */ 397 memcpy((char *)&pColor->spec, (char *)&Luv_return, sizeof(XcmsCIELuv)); 398 399 /* Identify that the format is now CIEuvY */ 400 pColor->format = XcmsCIELuvFormat; 401 } 402 return(XcmsSuccess); 403} 404