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