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