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