LRGB.c revision 1ab64890
1/* $Xorg: LRGB.c,v 1.3 2000/08/17 19:44:39 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 * XcmsLRGB.c 29 * 30 * DESCRIPTION 31 * This file contains the conversion routines: 32 * 1. CIE XYZ to RGB intensity 33 * 2. RGB intensity to device RGB 34 * 3. device RGB to RGB intensity 35 * 4. RGB intensity to CIE XYZ 36 * 37 */ 38/* $XFree86: xc/lib/X11/LRGB.c,v 3.6 2003/04/13 19:22:16 dawes Exp $ */ 39 40#ifdef HAVE_CONFIG_H 41#include <config.h> 42#endif 43#include <stdio.h> 44#include <X11/Xos.h> 45#include <X11/Xatom.h> 46#include "Xlibint.h" 47#include "Xcmsint.h" 48#include "Cv.h" 49 50/* 51 * LOCAL DEFINES 52 * #define declarations local to this package. 53 */ 54#define EPS 0.001 55#ifndef MIN 56#define MIN(x,y) ((x) > (y) ? (y) : (x)) 57#endif /* MIN */ 58#ifndef MAX 59#define MAX(x,y) ((x) > (y) ? (x) : (y)) 60#endif /* MAX */ 61#ifndef MIN3 62#define MIN3(x,y,z) ((x) > (MIN((y), (z))) ? (MIN((y), (z))) : (x)) 63#endif /* MIN3 */ 64#ifndef MAX3 65#define MAX3(x,y,z) ((x) > (MAX((y), (z))) ? (x) : (MAX((y), (z)))) 66#endif /* MAX3 */ 67 68/* 69 * LOCAL TYPEDEFS 70 * typedefs local to this package (for use with local vars). 71 * 72 */ 73 74/* 75 * FORWARD DECLARATIONS 76 */ 77static void LINEAR_RGB_FreeSCCData(XPointer pScreenDataTemp); 78static int LINEAR_RGB_InitSCCData(Display *dpy, 79 int screenNumber, XcmsPerScrnInfo *pPerScrnInfo); 80static int XcmsLRGB_RGB_ParseString(register char *spec, XcmsColor *pColor); 81static int XcmsLRGB_RGBi_ParseString(register char *spec, XcmsColor *pColor); 82static Status 83_XcmsGetTableType0( 84 IntensityTbl *pTbl, 85 int format, 86 char **pChar, 87 unsigned long *pCount); 88static Status 89_XcmsGetTableType1( 90 IntensityTbl *pTbl, 91 int format, 92 char **pChar, 93 unsigned long *pCount); 94 95/* 96 * LOCALS VARIABLES 97 * Variables local to this package. 98 * Usage example: 99 * static int ExampleLocalVar; 100 */ 101 102static unsigned short const MASK[17] = { 103 0x0000, /* 0 bitsPerRGB */ 104 0x8000, /* 1 bitsPerRGB */ 105 0xc000, /* 2 bitsPerRGB */ 106 0xe000, /* 3 bitsPerRGB */ 107 0xf000, /* 4 bitsPerRGB */ 108 0xf800, /* 5 bitsPerRGB */ 109 0xfc00, /* 6 bitsPerRGB */ 110 0xfe00, /* 7 bitsPerRGB */ 111 0xff00, /* 8 bitsPerRGB */ 112 0xff80, /* 9 bitsPerRGB */ 113 0xffc0, /* 10 bitsPerRGB */ 114 0xffe0, /* 11 bitsPerRGB */ 115 0xfff0, /* 12 bitsPerRGB */ 116 0xfff8, /* 13 bitsPerRGB */ 117 0xfffc, /* 14 bitsPerRGB */ 118 0xfffe, /* 15 bitsPerRGB */ 119 0xffff /* 16 bitsPerRGB */ 120}; 121 122 123 /* 124 * A NULL terminated array of function pointers that when applied 125 * in series will convert an XcmsColor structure from XcmsRGBFormat 126 * to XcmsCIEXYZFormat. 127 */ 128static XcmsConversionProc Fl_RGB_to_CIEXYZ[] = { 129 (XcmsConversionProc)XcmsRGBToRGBi, 130 (XcmsConversionProc)XcmsRGBiToCIEXYZ, 131 NULL 132}; 133 134 /* 135 * A NULL terminated array of function pointers that when applied 136 * in series will convert an XcmsColor structure from XcmsCIEXYZFormat 137 * to XcmsRGBFormat. 138 */ 139static XcmsConversionProc Fl_CIEXYZ_to_RGB[] = { 140 (XcmsConversionProc)XcmsCIEXYZToRGBi, 141 (XcmsConversionProc)XcmsRGBiToRGB, 142 NULL 143}; 144 145 /* 146 * A NULL terminated array of function pointers that when applied 147 * in series will convert an XcmsColor structure from XcmsRGBiFormat 148 * to XcmsCIEXYZFormat. 149 */ 150static XcmsConversionProc Fl_RGBi_to_CIEXYZ[] = { 151 (XcmsConversionProc)XcmsRGBiToCIEXYZ, 152 NULL 153}; 154 155 /* 156 * A NULL terminated array of function pointers that when applied 157 * in series will convert an XcmsColor structure from XcmsCIEXYZFormat 158 * to XcmsRGBiFormat. 159 */ 160static XcmsConversionProc Fl_CIEXYZ_to_RGBi[] = { 161 (XcmsConversionProc)XcmsCIEXYZToRGBi, 162 NULL 163}; 164 165 /* 166 * RGBi Color Spaces 167 */ 168XcmsColorSpace XcmsRGBiColorSpace = 169 { 170 _XcmsRGBi_prefix, /* prefix */ 171 XcmsRGBiFormat, /* id */ 172 XcmsLRGB_RGBi_ParseString, /* parseString */ 173 Fl_RGBi_to_CIEXYZ, /* to_CIEXYZ */ 174 Fl_CIEXYZ_to_RGBi, /* from_CIEXYZ */ 175 1 176 }; 177 178 /* 179 * RGB Color Spaces 180 */ 181XcmsColorSpace XcmsRGBColorSpace = 182 { 183 _XcmsRGB_prefix, /* prefix */ 184 XcmsRGBFormat, /* id */ 185 XcmsLRGB_RGB_ParseString, /* parseString */ 186 Fl_RGB_to_CIEXYZ, /* to_CIEXYZ */ 187 Fl_CIEXYZ_to_RGB, /* from_CIEXYZ */ 188 1 189 }; 190 191 /* 192 * Device-Independent Color Spaces known to the 193 * LINEAR_RGB Screen Color Characteristics Function Set. 194 */ 195static XcmsColorSpace *DDColorSpaces[] = { 196 &XcmsRGBColorSpace, 197 &XcmsRGBiColorSpace, 198 NULL 199}; 200 201 202/* 203 * GLOBALS 204 * Variables declared in this package that are allowed 205 * to be used globally. 206 */ 207 208 /* 209 * LINEAR_RGB Screen Color Characteristics Function Set. 210 */ 211XcmsFunctionSet XcmsLinearRGBFunctionSet = 212 { 213 &DDColorSpaces[0], /* pDDColorSpaces */ 214 LINEAR_RGB_InitSCCData, /* pInitScrnFunc */ 215 LINEAR_RGB_FreeSCCData /* pFreeSCCData */ 216 }; 217 218/* 219 * DESCRIPTION 220 * Contents of Default SCCData should be replaced if other 221 * data should be used as default. 222 * 223 * 224 */ 225 226/* 227 * NAME Tektronix 19" (Sony) CRT 228 * PART_NUMBER 119-2451-00 229 * MODEL Tek4300, Tek4800 230 */ 231 232static IntensityRec const Default_RGB_RedTuples[] = { 233 /* {unsigned short value, XcmsFloat intensity} */ 234 { 0x0000, 0.000000 }, 235 { 0x0909, 0.000000 }, 236 { 0x0a0a, 0.000936 }, 237 { 0x0f0f, 0.001481 }, 238 { 0x1414, 0.002329 }, 239 { 0x1919, 0.003529 }, 240 { 0x1e1e, 0.005127 }, 241 { 0x2323, 0.007169 }, 242 { 0x2828, 0.009699 }, 243 { 0x2d2d, 0.012759 }, 244 { 0x3232, 0.016392 }, 245 { 0x3737, 0.020637 }, 246 { 0x3c3c, 0.025533 }, 247 { 0x4141, 0.031119 }, 248 { 0x4646, 0.037431 }, 249 { 0x4b4b, 0.044504 }, 250 { 0x5050, 0.052373 }, 251 { 0x5555, 0.061069 }, 252 { 0x5a5a, 0.070624 }, 253 { 0x5f5f, 0.081070 }, 254 { 0x6464, 0.092433 }, 255 { 0x6969, 0.104744 }, 256 { 0x6e6e, 0.118026 }, 257 { 0x7373, 0.132307 }, 258 { 0x7878, 0.147610 }, 259 { 0x7d7d, 0.163958 }, 260 { 0x8282, 0.181371 }, 261 { 0x8787, 0.199871 }, 262 { 0x8c8c, 0.219475 }, 263 { 0x9191, 0.240202 }, 264 { 0x9696, 0.262069 }, 265 { 0x9b9b, 0.285089 }, 266 { 0xa0a0, 0.309278 }, 267 { 0xa5a5, 0.334647 }, 268 { 0xaaaa, 0.361208 }, 269 { 0xafaf, 0.388971 }, 270 { 0xb4b4, 0.417945 }, 271 { 0xb9b9, 0.448138 }, 272 { 0xbebe, 0.479555 }, 273 { 0xc3c3, 0.512202 }, 274 { 0xc8c8, 0.546082 }, 275 { 0xcdcd, 0.581199 }, 276 { 0xd2d2, 0.617552 }, 277 { 0xd7d7, 0.655144 }, 278 { 0xdcdc, 0.693971 }, 279 { 0xe1e1, 0.734031 }, 280 { 0xe6e6, 0.775322 }, 281 { 0xebeb, 0.817837 }, 282 { 0xf0f0, 0.861571 }, 283 { 0xf5f5, 0.906515 }, 284 { 0xfafa, 0.952662 }, 285 { 0xffff, 1.000000 } 286}; 287 288static IntensityRec const Default_RGB_GreenTuples[] = { 289 /* {unsigned short value, XcmsFloat intensity} */ 290 { 0x0000, 0.000000 }, 291 { 0x1313, 0.000000 }, 292 { 0x1414, 0.000832 }, 293 { 0x1919, 0.001998 }, 294 { 0x1e1e, 0.003612 }, 295 { 0x2323, 0.005736 }, 296 { 0x2828, 0.008428 }, 297 { 0x2d2d, 0.011745 }, 298 { 0x3232, 0.015740 }, 299 { 0x3737, 0.020463 }, 300 { 0x3c3c, 0.025960 }, 301 { 0x4141, 0.032275 }, 302 { 0x4646, 0.039449 }, 303 { 0x4b4b, 0.047519 }, 304 { 0x5050, 0.056520 }, 305 { 0x5555, 0.066484 }, 306 { 0x5a5a, 0.077439 }, 307 { 0x5f5f, 0.089409 }, 308 { 0x6464, 0.102418 }, 309 { 0x6969, 0.116485 }, 310 { 0x6e6e, 0.131625 }, 311 { 0x7373, 0.147853 }, 312 { 0x7878, 0.165176 }, 313 { 0x7d7d, 0.183604 }, 314 { 0x8282, 0.203140 }, 315 { 0x8787, 0.223783 }, 316 { 0x8c8c, 0.245533 }, 317 { 0x9191, 0.268384 }, 318 { 0x9696, 0.292327 }, 319 { 0x9b9b, 0.317351 }, 320 { 0xa0a0, 0.343441 }, 321 { 0xa5a5, 0.370580 }, 322 { 0xaaaa, 0.398747 }, 323 { 0xafaf, 0.427919 }, 324 { 0xb4b4, 0.458068 }, 325 { 0xb9b9, 0.489165 }, 326 { 0xbebe, 0.521176 }, 327 { 0xc3c3, 0.554067 }, 328 { 0xc8c8, 0.587797 }, 329 { 0xcdcd, 0.622324 }, 330 { 0xd2d2, 0.657604 }, 331 { 0xd7d7, 0.693588 }, 332 { 0xdcdc, 0.730225 }, 333 { 0xe1e1, 0.767459 }, 334 { 0xe6e6, 0.805235 }, 335 { 0xebeb, 0.843491 }, 336 { 0xf0f0, 0.882164 }, 337 { 0xf5f5, 0.921187 }, 338 { 0xfafa, 0.960490 }, 339 { 0xffff, 1.000000 } 340}; 341 342static IntensityRec const Default_RGB_BlueTuples[] = { 343 /* {unsigned short value, XcmsFloat intensity} */ 344 { 0x0000, 0.000000 }, 345 { 0x0e0e, 0.000000 }, 346 { 0x0f0f, 0.001341 }, 347 { 0x1414, 0.002080 }, 348 { 0x1919, 0.003188 }, 349 { 0x1e1e, 0.004729 }, 350 { 0x2323, 0.006766 }, 351 { 0x2828, 0.009357 }, 352 { 0x2d2d, 0.012559 }, 353 { 0x3232, 0.016424 }, 354 { 0x3737, 0.021004 }, 355 { 0x3c3c, 0.026344 }, 356 { 0x4141, 0.032489 }, 357 { 0x4646, 0.039481 }, 358 { 0x4b4b, 0.047357 }, 359 { 0x5050, 0.056154 }, 360 { 0x5555, 0.065903 }, 361 { 0x5a5a, 0.076634 }, 362 { 0x5f5f, 0.088373 }, 363 { 0x6464, 0.101145 }, 364 { 0x6969, 0.114968 }, 365 { 0x6e6e, 0.129862 }, 366 { 0x7373, 0.145841 }, 367 { 0x7878, 0.162915 }, 368 { 0x7d7d, 0.181095 }, 369 { 0x8282, 0.200386 }, 370 { 0x8787, 0.220791 }, 371 { 0x8c8c, 0.242309 }, 372 { 0x9191, 0.264937 }, 373 { 0x9696, 0.288670 }, 374 { 0x9b9b, 0.313499 }, 375 { 0xa0a0, 0.339410 }, 376 { 0xa5a5, 0.366390 }, 377 { 0xaaaa, 0.394421 }, 378 { 0xafaf, 0.423481 }, 379 { 0xb4b4, 0.453547 }, 380 { 0xb9b9, 0.484592 }, 381 { 0xbebe, 0.516587 }, 382 { 0xc3c3, 0.549498 }, 383 { 0xc8c8, 0.583291 }, 384 { 0xcdcd, 0.617925 }, 385 { 0xd2d2, 0.653361 }, 386 { 0xd7d7, 0.689553 }, 387 { 0xdcdc, 0.726454 }, 388 { 0xe1e1, 0.764013 }, 389 { 0xe6e6, 0.802178 }, 390 { 0xebeb, 0.840891 }, 391 { 0xf0f0, 0.880093 }, 392 { 0xf5f5, 0.919723 }, 393 { 0xfafa, 0.959715 }, 394 { 0xffff, 1.00000 } 395}; 396 397static IntensityTbl Default_RGB_RedTbl = { 398 /* IntensityRec *pBase */ 399 (IntensityRec *) Default_RGB_RedTuples, 400 /* unsigned int nEntries */ 401 52 402}; 403 404static IntensityTbl Default_RGB_GreenTbl = { 405 /* IntensityRec *pBase */ 406 (IntensityRec *)Default_RGB_GreenTuples, 407 /* unsigned int nEntries */ 408 50 409}; 410 411static IntensityTbl Default_RGB_BlueTbl = { 412 /* IntensityRec *pBase */ 413 (IntensityRec *)Default_RGB_BlueTuples, 414 /* unsigned int nEntries */ 415 51 416}; 417 418static LINEAR_RGB_SCCData Default_RGB_SCCData = { 419 /* XcmsFloat XYZtoRGBmatrix[3][3] */ 420 { 421 { 3.48340481253539000, -1.52176374927285200, -0.55923133354049780 }, 422 {-1.07152751306193600, 1.96593795204372400, 0.03673691339553462 }, 423 { 0.06351179790497788, -0.20020501000496480, 0.81070942031648220 } 424 }, 425 426 /* XcmsFloat RGBtoXYZmatrix[3][3] */ 427 { 428 { 0.38106149108714790, 0.32025712365352110, 0.24834578525933100 }, 429 { 0.20729745115140850, 0.68054638776373240, 0.11215616108485920 }, 430 { 0.02133944350088028, 0.14297193020246480, 1.24172892629665500 } 431 }, 432 433 /* IntensityTbl *pRedTbl */ 434 &Default_RGB_RedTbl, 435 436 /* IntensityTbl *pGreenTbl */ 437 &Default_RGB_GreenTbl, 438 439 /* IntensityTbl *pBlueTbl */ 440 &Default_RGB_BlueTbl 441}; 442 443/************************************************************************ 444 * * 445 * PRIVATE ROUTINES * 446 * * 447 ************************************************************************/ 448 449/* 450 * NAME 451 * LINEAR_RGB_InitSCCData() 452 * 453 * SYNOPSIS 454 */ 455static Status 456LINEAR_RGB_InitSCCData( 457 Display *dpy, 458 int screenNumber, 459 XcmsPerScrnInfo *pPerScrnInfo) 460/* 461 * DESCRIPTION 462 * 463 * RETURNS 464 * XcmsFailure if failed. 465 * XcmsSuccess if succeeded. 466 * 467 */ 468{ 469 Atom CorrectAtom = XInternAtom (dpy, XDCCC_CORRECT_ATOM_NAME, True); 470 Atom MatrixAtom = XInternAtom (dpy, XDCCC_MATRIX_ATOM_NAME, True); 471 int format_return, count, cType, nTables; 472 unsigned long nitems, nbytes_return; 473 char *property_return, *pChar; 474 XcmsFloat *pValue; 475#ifdef ALLDEBUG 476 IntensityRec *pIRec; 477#endif /* ALLDEBUG */ 478 VisualID visualID; 479 480 LINEAR_RGB_SCCData *pScreenData, *pScreenDefaultData; 481 XcmsIntensityMap *pNewMap; 482 483 /* 484 * Allocate memory for pScreenData 485 */ 486 if (!(pScreenData = pScreenDefaultData = (LINEAR_RGB_SCCData *) 487 Xcalloc (1, sizeof(LINEAR_RGB_SCCData)))) { 488 return(XcmsFailure); 489 } 490 491 /* 492 * 1. Get the XYZ->RGB and RGB->XYZ matrices 493 */ 494 495 if (MatrixAtom == None || 496 !_XcmsGetProperty (dpy, RootWindow(dpy, screenNumber), MatrixAtom, 497 &format_return, &nitems, &nbytes_return, &property_return) || 498 nitems != 18 || format_return != 32) { 499 /* 500 * As per the XDCCC, there must be 18 data items and each must be 501 * in 32 bits ! 502 */ 503 goto FreeSCCData; 504 505 } else { 506 507 /* 508 * RGBtoXYZ and XYZtoRGB matrices 509 */ 510 pValue = (XcmsFloat *) pScreenData; 511 pChar = property_return; 512 for (count = 0; count < 18; count++) { 513 *pValue++ = (long)_XcmsGetElement(format_return, &pChar, 514 &nitems) / (XcmsFloat)XDCCC_NUMBER; 515 } 516 Xfree ((char *)property_return); 517 pPerScrnInfo->screenWhitePt.spec.CIEXYZ.X = 518 pScreenData->RGBtoXYZmatrix[0][0] + 519 pScreenData->RGBtoXYZmatrix[0][1] + 520 pScreenData->RGBtoXYZmatrix[0][2]; 521 pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Y = 522 pScreenData->RGBtoXYZmatrix[1][0] + 523 pScreenData->RGBtoXYZmatrix[1][1] + 524 pScreenData->RGBtoXYZmatrix[1][2]; 525 pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Z = 526 pScreenData->RGBtoXYZmatrix[2][0] + 527 pScreenData->RGBtoXYZmatrix[2][1] + 528 pScreenData->RGBtoXYZmatrix[2][2]; 529 530 /* 531 * Compute the Screen White Point 532 */ 533 if ((pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Y < (1.0 - EPS) ) 534 || (pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Y > (1.0 + EPS))) { 535 goto FreeSCCData; 536 } else { 537 pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Y = 1.0; 538 } 539 pPerScrnInfo->screenWhitePt.format = XcmsCIEXYZFormat; 540 pPerScrnInfo->screenWhitePt.pixel = 0; 541 542#ifdef PDEBUG 543 printf ("RGB to XYZ Matrix values:\n"); 544 printf (" %f %f %f\n %f %f %f\n %f %f %f\n", 545 pScreenData->RGBtoXYZmatrix[0][0], 546 pScreenData->RGBtoXYZmatrix[0][1], 547 pScreenData->RGBtoXYZmatrix[0][2], 548 pScreenData->RGBtoXYZmatrix[1][0], 549 pScreenData->RGBtoXYZmatrix[1][1], 550 pScreenData->RGBtoXYZmatrix[1][2], 551 pScreenData->RGBtoXYZmatrix[2][0], 552 pScreenData->RGBtoXYZmatrix[2][1], 553 pScreenData->RGBtoXYZmatrix[2][2]); 554 printf ("XYZ to RGB Matrix values:\n"); 555 printf (" %f %f %f\n %f %f %f\n %f %f %f\n", 556 pScreenData->XYZtoRGBmatrix[0][0], 557 pScreenData->XYZtoRGBmatrix[0][1], 558 pScreenData->XYZtoRGBmatrix[0][2], 559 pScreenData->XYZtoRGBmatrix[1][0], 560 pScreenData->XYZtoRGBmatrix[1][1], 561 pScreenData->XYZtoRGBmatrix[1][2], 562 pScreenData->XYZtoRGBmatrix[2][0], 563 pScreenData->XYZtoRGBmatrix[2][1], 564 pScreenData->XYZtoRGBmatrix[2][2]); 565 printf ("Screen White Pt value: %f %f %f\n", 566 pPerScrnInfo->screenWhitePt.spec.CIEXYZ.X, 567 pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Y, 568 pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Z); 569#endif /* PDEBUG */ 570 } 571 572 /* 573 * 2. Get the Intensity Profile 574 */ 575 if (CorrectAtom == None || 576 !_XcmsGetProperty (dpy, RootWindow(dpy, screenNumber), CorrectAtom, 577 &format_return, &nitems, &nbytes_return, &property_return)) { 578 Xfree ((char *)property_return); 579 goto FreeSCCData; 580 } 581 582 pChar = property_return; 583 584 while (nitems) { 585 switch (format_return) { 586 case 8: 587 /* 588 * Must have at least: 589 * VisualID0 590 * VisualID1 591 * VisualID2 592 * VisualID3 593 * type 594 * count 595 * length 596 * intensity1 597 * intensity2 598 */ 599 if (nitems < 9) { 600 Xfree ((char *)property_return); 601 goto FreeSCCData; 602 } 603 count = 3; 604 break; 605 case 16: 606 /* 607 * Must have at least: 608 * VisualID0 609 * VisualID3 610 * type 611 * count 612 * length 613 * intensity1 614 * intensity2 615 */ 616 if (nitems < 7) { 617 Xfree ((char *)property_return); 618 goto FreeSCCData; 619 } 620 count = 1; 621 break; 622 case 32: 623 /* 624 * Must have at least: 625 * VisualID0 626 * type 627 * count 628 * length 629 * intensity1 630 * intensity2 631 */ 632 if (nitems < 6) { 633 Xfree ((char *)property_return); 634 goto FreeSCCData; 635 } 636 count = 0; 637 break; 638 default: 639 Xfree ((char *)property_return); 640 goto FreeSCCData; 641 } 642 643 /* 644 * Get VisualID 645 */ 646 visualID = _XcmsGetElement(format_return, &pChar, &nitems); 647 while (count--) { 648 visualID = visualID << format_return; 649 visualID |= _XcmsGetElement(format_return, &pChar, &nitems); 650 } 651 652 if (visualID == 0) { 653 /* 654 * This is a shared intensity table 655 */ 656 pScreenData = pScreenDefaultData; 657 } else { 658 /* 659 * This is a per-Visual intensity table 660 */ 661 if (!(pScreenData = (LINEAR_RGB_SCCData *) 662 Xcalloc (1, sizeof(LINEAR_RGB_SCCData)))) { 663 return(XcmsFailure); 664 } 665 /* copy matrices */ 666 memcpy((char *)pScreenData, (char *)pScreenDefaultData, 667 18 * sizeof(XcmsFloat)); 668 669 /* Create, initialize, and add map */ 670 if (!(pNewMap = (XcmsIntensityMap *) 671 Xcalloc (1, sizeof(XcmsIntensityMap)))) { 672 Xfree((char *)pScreenData); 673 return(XcmsFailure); 674 } 675 pNewMap->visualID = visualID; 676 pNewMap->screenData = (XPointer)pScreenData; 677 pNewMap->pFreeScreenData = LINEAR_RGB_FreeSCCData; 678 pNewMap->pNext = 679 (XcmsIntensityMap *)dpy->cms.perVisualIntensityMaps; 680 dpy->cms.perVisualIntensityMaps = (XPointer)pNewMap; 681 dpy->free_funcs->intensityMaps = _XcmsFreeIntensityMaps; 682 } 683 684 cType = _XcmsGetElement(format_return, &pChar, &nitems); 685 nTables = _XcmsGetElement(format_return, &pChar, &nitems); 686 687 if (cType == 0) { 688 689 /* Red Intensity Table */ 690 if (!(pScreenData->pRedTbl = (IntensityTbl *) 691 Xcalloc (1, sizeof(IntensityTbl)))) { 692 goto FreeSCCData; 693 } 694 if (_XcmsGetTableType0(pScreenData->pRedTbl, format_return, &pChar, 695 &nitems) == XcmsFailure) { 696 goto FreeRedTbl; 697 } 698 699 if (nTables == 1) { 700 /* Green Intensity Table */ 701 pScreenData->pGreenTbl = pScreenData->pRedTbl; 702 /* Blue Intensity Table */ 703 pScreenData->pBlueTbl = pScreenData->pRedTbl; 704 } else { 705 /* Green Intensity Table */ 706 if (!(pScreenData->pGreenTbl = (IntensityTbl *) 707 Xcalloc (1, sizeof(IntensityTbl)))) { 708 goto FreeRedTblElements; 709 } 710 if (_XcmsGetTableType0(pScreenData->pGreenTbl, format_return, &pChar, 711 &nitems) == XcmsFailure) { 712 goto FreeGreenTbl; 713 } 714 715 /* Blue Intensity Table */ 716 if (!(pScreenData->pBlueTbl = (IntensityTbl *) 717 Xcalloc (1, sizeof(IntensityTbl)))) { 718 goto FreeGreenTblElements; 719 } 720 if (_XcmsGetTableType0(pScreenData->pBlueTbl, format_return, &pChar, 721 &nitems) == XcmsFailure) { 722 goto FreeBlueTbl; 723 } 724 } 725 } else if (cType == 1) { 726 /* Red Intensity Table */ 727 if (!(pScreenData->pRedTbl = (IntensityTbl *) 728 Xcalloc (1, sizeof(IntensityTbl)))) { 729 goto FreeSCCData; 730 } 731 if (_XcmsGetTableType1(pScreenData->pRedTbl, format_return, &pChar, 732 &nitems) == XcmsFailure) { 733 goto FreeRedTbl; 734 } 735 736 if (nTables == 1) { 737 738 /* Green Intensity Table */ 739 pScreenData->pGreenTbl = pScreenData->pRedTbl; 740 /* Blue Intensity Table */ 741 pScreenData->pBlueTbl = pScreenData->pRedTbl; 742 743 } else { 744 745 /* Green Intensity Table */ 746 if (!(pScreenData->pGreenTbl = (IntensityTbl *) 747 Xcalloc (1, sizeof(IntensityTbl)))) { 748 goto FreeRedTblElements; 749 } 750 if (_XcmsGetTableType1(pScreenData->pGreenTbl, format_return, &pChar, 751 &nitems) == XcmsFailure) { 752 goto FreeGreenTbl; 753 } 754 755 /* Blue Intensity Table */ 756 if (!(pScreenData->pBlueTbl = (IntensityTbl *) 757 Xcalloc (1, sizeof(IntensityTbl)))) { 758 goto FreeBlueTblElements; 759 } 760 if (_XcmsGetTableType1(pScreenData->pBlueTbl, format_return, &pChar, 761 &nitems) == XcmsFailure) { 762 goto FreeBlueTbl; 763 } 764 } 765 } else { 766 Xfree ((char *)property_return); 767 goto FreeSCCData; 768 } 769 770#ifdef ALLDEBUG 771 printf ("Intensity Table RED %d\n", pScreenData->pRedTbl->nEntries); 772 pIRec = (IntensityRec *) pScreenData->pRedTbl->pBase; 773 for (count = 0; count < pScreenData->pRedTbl->nEntries; count++, pIRec++) { 774 printf ("\t0x%4x\t%f\n", pIRec->value, pIRec->intensity); 775 } 776 if (pScreenData->pGreenTbl->pBase != pScreenData->pRedTbl->pBase) { 777 printf ("Intensity Table GREEN %d\n", pScreenData->pGreenTbl->nEntries); 778 pIRec = (IntensityRec *)pScreenData->pGreenTbl->pBase; 779 for (count = 0; count < pScreenData->pGreenTbl->nEntries; count++, pIRec++) { 780 printf ("\t0x%4x\t%f\n", pIRec->value, pIRec->intensity); 781 } 782 } 783 if (pScreenData->pBlueTbl->pBase != pScreenData->pRedTbl->pBase) { 784 printf ("Intensity Table BLUE %d\n", pScreenData->pBlueTbl->nEntries); 785 pIRec = (IntensityRec *) pScreenData->pBlueTbl->pBase; 786 for (count = 0; count < pScreenData->pBlueTbl->nEntries; count++, pIRec++) { 787 printf ("\t0x%4x\t%f\n", pIRec->value, pIRec->intensity); 788 } 789 } 790#endif /* ALLDEBUG */ 791 } 792 793 Xfree ((char *)property_return); 794 795 /* Free the old memory and use the new structure created. */ 796 LINEAR_RGB_FreeSCCData(pPerScrnInfo->screenData); 797 798 pPerScrnInfo->functionSet = (XPointer) &XcmsLinearRGBFunctionSet; 799 800 pPerScrnInfo->screenData = (XPointer) pScreenData; 801 802 pPerScrnInfo->state = XcmsInitSuccess; 803 804 return(XcmsSuccess); 805 806FreeBlueTblElements: 807 Xfree((char *)pScreenData->pBlueTbl->pBase); 808 809FreeBlueTbl: 810 Xfree((char *)pScreenData->pBlueTbl); 811 812FreeGreenTblElements: 813 Xfree((char *)pScreenData->pBlueTbl->pBase); 814 815FreeGreenTbl: 816 Xfree((char *)pScreenData->pGreenTbl); 817 818FreeRedTblElements: 819 Xfree((char *)pScreenData->pRedTbl->pBase); 820 821FreeRedTbl: 822 Xfree((char *)pScreenData->pRedTbl); 823 824FreeSCCData: 825 Xfree((char *)pScreenData); 826 pPerScrnInfo->state = XcmsInitNone; 827 return(XcmsFailure); 828} 829 830 831/* 832 * NAME 833 * LINEAR_RGB_FreeSCCData() 834 * 835 * SYNOPSIS 836 */ 837static void 838LINEAR_RGB_FreeSCCData( 839 XPointer pScreenDataTemp) 840/* 841 * DESCRIPTION 842 * 843 * RETURNS 844 * 0 if failed. 845 * 1 if succeeded with no modifications. 846 * 847 */ 848{ 849 LINEAR_RGB_SCCData *pScreenData = (LINEAR_RGB_SCCData *) pScreenDataTemp; 850 851 if (pScreenData && pScreenData != &Default_RGB_SCCData) { 852 if (pScreenData->pRedTbl) { 853 if (pScreenData->pGreenTbl) { 854 if (pScreenData->pRedTbl->pBase != 855 pScreenData->pGreenTbl->pBase) { 856 if (pScreenData->pGreenTbl->pBase) { 857 Xfree ((char *)pScreenData->pGreenTbl->pBase); 858 } 859 } 860 if (pScreenData->pGreenTbl != pScreenData->pRedTbl) { 861 Xfree ((char *)pScreenData->pGreenTbl); 862 } 863 } 864 if (pScreenData->pBlueTbl) { 865 if (pScreenData->pRedTbl->pBase != 866 pScreenData->pBlueTbl->pBase) { 867 if (pScreenData->pBlueTbl->pBase) { 868 Xfree ((char *)pScreenData->pBlueTbl->pBase); 869 } 870 } 871 if (pScreenData->pBlueTbl != pScreenData->pRedTbl) { 872 Xfree ((char *)pScreenData->pBlueTbl); 873 } 874 } 875 if (pScreenData->pRedTbl->pBase) { 876 Xfree ((char *)pScreenData->pRedTbl->pBase); 877 } 878 Xfree ((char *)pScreenData->pRedTbl); 879 } 880 Xfree ((char *)pScreenData); 881 } 882} 883 884 885 886/************************************************************************ 887 * * 888 * API PRIVATE ROUTINES * 889 * * 890 ************************************************************************/ 891 892/* 893 * NAME 894 * _XcmsGetTableType0 895 * 896 * SYNOPSIS 897 */ 898static Status 899_XcmsGetTableType0( 900 IntensityTbl *pTbl, 901 int format, 902 char **pChar, 903 unsigned long *pCount) 904/* 905 * DESCRIPTION 906 * 907 * RETURNS 908 * XcmsFailure if failed. 909 * XcmsSuccess if succeeded. 910 * 911 */ 912{ 913 unsigned int nElements; 914 IntensityRec *pIRec; 915 916 nElements = pTbl->nEntries = 917 _XcmsGetElement(format, pChar, pCount) + 1; 918 if (!(pIRec = pTbl->pBase = (IntensityRec *) 919 Xcalloc (nElements, sizeof(IntensityRec)))) { 920 return(XcmsFailure); 921 } 922 923 switch (format) { 924 case 8: 925 for (; nElements--; pIRec++) { 926 /* 0xFFFF/0xFF = 0x101 */ 927 pIRec->value = _XcmsGetElement (format, pChar, pCount) * 0x101; 928 pIRec->intensity = 929 _XcmsGetElement (format, pChar, pCount) / (XcmsFloat)255.0; 930 } 931 break; 932 case 16: 933 for (; nElements--; pIRec++) { 934 pIRec->value = _XcmsGetElement (format, pChar, pCount); 935 pIRec->intensity = _XcmsGetElement (format, pChar, pCount) 936 / (XcmsFloat)65535.0; 937 } 938 break; 939 case 32: 940 for (; nElements--; pIRec++) { 941 pIRec->value = _XcmsGetElement (format, pChar, pCount); 942 pIRec->intensity = _XcmsGetElement (format, pChar, pCount) 943 / (XcmsFloat)4294967295.0; 944 } 945 break; 946 default: 947 return(XcmsFailure); 948 } 949 return(XcmsSuccess); 950} 951 952 953/* 954 * NAME 955 * _XcmsGetTableType1 956 * 957 * SYNOPSIS 958 */ 959static Status 960_XcmsGetTableType1( 961 IntensityTbl *pTbl, 962 int format, 963 char **pChar, 964 unsigned long *pCount) 965/* 966 * DESCRIPTION 967 * 968 * RETURNS 969 * XcmsFailure if failed. 970 * XcmsSuccess if succeeded. 971 * 972 */ 973{ 974 int count; 975 unsigned int max_index; 976 IntensityRec *pIRec; 977 978 max_index = _XcmsGetElement(format, pChar, pCount); 979 pTbl->nEntries = max_index + 1; 980 if (!(pIRec = pTbl->pBase = (IntensityRec *) 981 Xcalloc (max_index+1, sizeof(IntensityRec)))) { 982 return(XcmsFailure); 983 } 984 985 switch (format) { 986 case 8: 987 for (count = 0; count < max_index+1; count++, pIRec++) { 988 pIRec->value = (count * 65535) / max_index; 989 pIRec->intensity = _XcmsGetElement (format, pChar, pCount) 990 / (XcmsFloat)255.0; 991 } 992 break; 993 case 16: 994 for (count = 0; count < max_index+1; count++, pIRec++) { 995 pIRec->value = (count * 65535) / max_index; 996 pIRec->intensity = _XcmsGetElement (format, pChar, pCount) 997 / (XcmsFloat)65535.0; 998 } 999 break; 1000 case 32: 1001 for (count = 0; count < max_index+1; count++, pIRec++) { 1002 pIRec->value = (count * 65535) / max_index; 1003 pIRec->intensity = _XcmsGetElement (format, pChar, pCount) 1004 / (XcmsFloat)4294967295.0; 1005 } 1006 break; 1007 default: 1008 return(XcmsFailure); 1009 } 1010 1011 return(XcmsSuccess); 1012} 1013 1014 1015/* 1016 * NAME 1017 * ValueCmp 1018 * 1019 * SYNOPSIS 1020 */ 1021static int 1022_XcmsValueCmp( 1023 IntensityRec *p1, IntensityRec *p2) 1024/* 1025 * DESCRIPTION 1026 * Compares the value component of two IntensityRec 1027 * structures. 1028 * 1029 * RETURNS 1030 * 0 if p1->value is equal to p2->value 1031 * < 0 if p1->value is less than p2->value 1032 * > 0 if p1->value is greater than p2->value 1033 * 1034 */ 1035{ 1036 return (p1->value - p2->value); 1037} 1038 1039 1040/* 1041 * NAME 1042 * IntensityCmp 1043 * 1044 * SYNOPSIS 1045 */ 1046static int 1047_XcmsIntensityCmp( 1048 IntensityRec *p1, IntensityRec *p2) 1049/* 1050 * DESCRIPTION 1051 * Compares the intensity component of two IntensityRec 1052 * structures. 1053 * 1054 * RETURNS 1055 * 0 if equal; 1056 * < 0 if first precedes second 1057 * > 0 if first succeeds second 1058 * 1059 */ 1060{ 1061 if (p1->intensity < p2->intensity) { 1062 return (-1); 1063 } 1064 if (p1->intensity > p2->intensity) { 1065 return (XcmsSuccess); 1066 } 1067 return (XcmsFailure); 1068} 1069 1070/* 1071 * NAME 1072 * ValueInterpolation 1073 * 1074 * SYNOPSIS 1075 */ 1076/* ARGSUSED */ 1077static int 1078_XcmsValueInterpolation( 1079 IntensityRec *key, IntensityRec *lo, IntensityRec *hi, IntensityRec *answer, 1080 int bitsPerRGB) 1081/* 1082 * DESCRIPTION 1083 * Based on a given value, performs a linear interpolation 1084 * on the intensities between two IntensityRec structures. 1085 * Note that the bitsPerRGB parameter is ignored. 1086 * 1087 * RETURNS 1088 * Returns 0 if failed; otherwise non-zero. 1089 */ 1090{ 1091 XcmsFloat ratio; 1092 1093 ratio = ((XcmsFloat)key->value - (XcmsFloat)lo->value) / 1094 ((XcmsFloat)hi->value - (XcmsFloat)lo->value); 1095 answer->value = key->value; 1096 answer->intensity = (hi->intensity - lo->intensity) * ratio; 1097 answer->intensity += lo->intensity; 1098 return (XcmsSuccess); 1099} 1100 1101/* 1102 * NAME 1103 * IntensityInterpolation 1104 * 1105 * SYNOPSIS 1106 */ 1107static int 1108_XcmsIntensityInterpolation( 1109 IntensityRec *key, IntensityRec *lo, IntensityRec *hi, IntensityRec *answer, 1110 int bitsPerRGB) 1111/* 1112 * DESCRIPTION 1113 * Based on a given intensity, performs a linear interpolation 1114 * on the values between two IntensityRec structures. 1115 * The bitsPerRGB parameter is necessary to perform rounding 1116 * to the correct number of significant bits. 1117 * 1118 * RETURNS 1119 * Returns 0 if failed; otherwise non-zero. 1120 */ 1121{ 1122 XcmsFloat ratio; 1123 long target, up, down; 1124 int shift = 16 - bitsPerRGB; 1125 int max_color = (1 << bitsPerRGB) - 1; 1126 1127 ratio = (key->intensity - lo->intensity) / (hi->intensity - lo->intensity); 1128 answer->intensity = key->intensity; 1129 target = hi->value - lo->value; 1130 target *= ratio; 1131 target += lo->value; 1132 1133 /* 1134 * Ok now, lets find the closest in respects to bits per RGB 1135 */ 1136 up = ((target >> shift) * 0xFFFF) / max_color; 1137 if (up < target) { 1138 down = up; 1139 up = (MIN((down >> shift) + 1, max_color) * 0xFFFF) / max_color; 1140 } else { 1141 down = (MAX((up >> shift) - 1, 0) * 0xFFFF) / max_color; 1142 } 1143 answer->value = ((up - target) < (target - down) ? up : down); 1144 answer->value &= MASK[bitsPerRGB]; 1145 return (XcmsSuccess); 1146} 1147 1148 1149 1150typedef int (*comparProcp)( 1151 char *p1, 1152 char *p2); 1153typedef int (*interpolProcp)( 1154 char *key, 1155 char *lo, 1156 char *hi, 1157 char *answer, 1158 int bitsPerRGB); 1159 1160/* 1161 * NAME 1162 * _XcmsTableSearch 1163 * 1164 * SYNOPSIS 1165 */ 1166static int 1167_XcmsTableSearch( 1168 char *key, 1169 int bitsPerRGB, 1170 char *base, 1171 unsigned nel, 1172 unsigned nKeyPtrSize, 1173 int (*compar)( 1174 char *p1, 1175 char *p2), 1176 int (*interpol)( 1177 char *key, 1178 char *lo, 1179 char *hi, 1180 char *answer, 1181 int bitsPerRGB), 1182 char *answer) 1183 1184/* 1185 * DESCRIPTION 1186 * A binary search through the specificied table. 1187 * 1188 * RETURNS 1189 * Returns 0 if failed; otherwise non-zero. 1190 * 1191 */ 1192{ 1193 char *hi, *lo, *mid, *last; 1194 int result; 1195 1196 last = hi = base + ((nel - 1) * nKeyPtrSize); 1197 mid = lo = base; 1198 1199 /* use only the significants bits, then scale into 16 bits */ 1200 ((IntensityRec *)key)->value = ((unsigned long) 1201 (((IntensityRec *)key)->value >> (16 - bitsPerRGB)) * 0xFFFF) 1202 / ((1 << bitsPerRGB) - 1); 1203 1204 /* Special case so that zero intensity always maps to zero value */ 1205 if ((*compar) (key,lo) <= 0) { 1206 memcpy (answer, lo, nKeyPtrSize); 1207 ((IntensityRec *)answer)->value &= MASK[bitsPerRGB]; 1208 return XcmsSuccess; 1209 } 1210 while (mid != last) { 1211 last = mid; 1212 mid = lo + (((unsigned)(hi - lo) / nKeyPtrSize) / 2) * nKeyPtrSize; 1213 result = (*compar) (key, mid); 1214 if (result == 0) { 1215 1216 memcpy(answer, mid, nKeyPtrSize); 1217 ((IntensityRec *)answer)->value &= MASK[bitsPerRGB]; 1218 return (XcmsSuccess); 1219 } else if (result < 0) { 1220 hi = mid; 1221 } else { 1222 lo = mid; 1223 } 1224 } 1225 1226 /* 1227 * If we got to here, we didn't find a solution, so we 1228 * need to apply interpolation. 1229 */ 1230 return ((*interpol)(key, lo, hi, answer, bitsPerRGB)); 1231} 1232 1233 1234/* 1235 * NAME 1236 * _XcmsMatVec - multiply a 3 x 3 by a 3 x 1 vector 1237 * 1238 * SYNOPSIS 1239 */ 1240static void _XcmsMatVec( 1241 XcmsFloat *pMat, XcmsFloat *pIn, XcmsFloat *pOut) 1242/* 1243 * DESCRIPTION 1244 * Multiply the passed vector by the passed matrix to return a 1245 * vector. Matrix is 3x3, vectors are of length 3. 1246 * 1247 * RETURNS 1248 * void 1249 */ 1250{ 1251 int i, j; 1252 1253 for (i = 0; i < 3; i++) { 1254 pOut[i] = 0.0; 1255 for (j = 0; j < 3; j++) 1256 pOut[i] += *(pMat+(i*3)+j) * pIn[j]; 1257 } 1258} 1259 1260 1261/************************************************************************ 1262 * * 1263 * PUBLIC ROUTINES * 1264 * * 1265 ************************************************************************/ 1266 1267 1268/* 1269 * NAME 1270 * XcmsLRGB_RGB_ParseString 1271 * 1272 * SYNOPSIS 1273 */ 1274static int 1275XcmsLRGB_RGB_ParseString( 1276 register char *spec, 1277 XcmsColor *pColor) 1278/* 1279 * DESCRIPTION 1280 * This routines takes a string and attempts to convert 1281 * it into a XcmsColor structure with XcmsRGBFormat. 1282 * 1283 * RETURNS 1284 * 0 if failed, non-zero otherwise. 1285 */ 1286{ 1287 register int n, i; 1288 unsigned short r, g, b; 1289 char c; 1290 char *pchar; 1291 unsigned short *pShort; 1292 1293 /* 1294 * Check for old # format 1295 */ 1296 if (*spec == '#') { 1297 /* 1298 * Attempt to parse the value portion. 1299 */ 1300 spec++; 1301 n = strlen(spec); 1302 if (n != 3 && n != 6 && n != 9 && n != 12) { 1303 return(XcmsFailure); 1304 } 1305 1306 n /= 3; 1307 g = b = 0; 1308 do { 1309 r = g; 1310 g = b; 1311 b = 0; 1312 for (i = n; --i >= 0; ) { 1313 c = *spec++; 1314 b <<= 4; 1315 if (c >= '0' && c <= '9') 1316 b |= c - '0'; 1317 /* assume string in lowercase 1318 else if (c >= 'A' && c <= 'F') 1319 b |= c - ('A' - 10); 1320 */ 1321 else if (c >= 'a' && c <= 'f') 1322 b |= c - ('a' - 10); 1323 else return (XcmsFailure); 1324 } 1325 } while (*spec != '\0'); 1326 1327 /* 1328 * Succeeded ! 1329 */ 1330 n <<= 2; 1331 n = 16 - n; 1332 /* shift instead of scale, to match old broken semantics */ 1333 pColor->spec.RGB.red = r << n; 1334 pColor->spec.RGB.green = g << n; 1335 pColor->spec.RGB.blue = b << n; 1336 } else { 1337 if ((pchar = strchr(spec, ':')) == NULL) { 1338 return(XcmsFailure); 1339 } 1340 n = (int)(pchar - spec); 1341 1342 /* 1343 * Check for proper prefix. 1344 */ 1345 if (strncmp(spec, _XcmsRGB_prefix, n) != 0) { 1346 return(XcmsFailure); 1347 } 1348 1349 /* 1350 * Attempt to parse the value portion. 1351 */ 1352 spec += (n + 1); 1353 pShort = &pColor->spec.RGB.red; 1354 for (i = 0; i < 3; i++, pShort++, spec++) { 1355 n = 0; 1356 *pShort = 0; 1357 while (*spec != '/' && *spec != '\0') { 1358 if (++n > 4) { 1359 return(XcmsFailure); 1360 } 1361 c = *spec++; 1362 *pShort <<= 4; 1363 if (c >= '0' && c <= '9') 1364 *pShort |= c - '0'; 1365 /* assume string in lowercase 1366 else if (c >= 'A' && c <= 'F') 1367 *pShort |= c - ('A' - 10); 1368 */ 1369 else if (c >= 'a' && c <= 'f') 1370 *pShort |= c - ('a' - 10); 1371 else return (XcmsFailure); 1372 } 1373 if (n == 0) 1374 return (XcmsFailure); 1375 if (n < 4) { 1376 *pShort = ((unsigned long)*pShort * 0xFFFF) / ((1 << n*4) - 1); 1377 } 1378 } 1379 } 1380 pColor->format = XcmsRGBFormat; 1381 pColor->pixel = 0; 1382 return (XcmsSuccess); 1383} 1384 1385 1386/* 1387 * NAME 1388 * XcmsLRGB_RGBi_ParseString 1389 * 1390 * SYNOPSIS 1391 */ 1392static int 1393XcmsLRGB_RGBi_ParseString( 1394 register char *spec, 1395 XcmsColor *pColor) 1396/* 1397 * DESCRIPTION 1398 * This routines takes a string and attempts to convert 1399 * it into a XcmsColor structure with XcmsRGBiFormat. 1400 * The assumed RGBi string syntax is: 1401 * RGBi:<r>/<g>/<b> 1402 * Where r, g, and b are in string input format for floats 1403 * consisting of: 1404 * a. an optional sign 1405 * b. a string of numbers possibly containing a decimal point, 1406 * c. an optional exponent field containing an 'E' or 'e' 1407 * followed by a possibly signed integer string. 1408 * 1409 * RETURNS 1410 * 0 if failed, non-zero otherwise. 1411 */ 1412{ 1413 int n; 1414 char *pchar; 1415 1416 if ((pchar = strchr(spec, ':')) == NULL) { 1417 return(XcmsFailure); 1418 } 1419 n = (int)(pchar - spec); 1420 1421 /* 1422 * Check for proper prefix. 1423 */ 1424 if (strncmp(spec, _XcmsRGBi_prefix, n) != 0) { 1425 return(XcmsFailure); 1426 } 1427 1428 /* 1429 * Attempt to parse the value portion. 1430 */ 1431 if (sscanf(spec + n + 1, "%lf/%lf/%lf", 1432 &pColor->spec.RGBi.red, 1433 &pColor->spec.RGBi.green, 1434 &pColor->spec.RGBi.blue) != 3) { 1435 char *s; /* Maybe failed due to locale */ 1436 int f; 1437 if ((s = strdup(spec))) { 1438 for (f = 0; s[f]; ++f) 1439 if (s[f] == '.') 1440 s[f] = ','; 1441 else if (s[f] == ',') 1442 s[f] = '.'; 1443 if (sscanf(s + n + 1, "%lf/%lf/%lf", 1444 &pColor->spec.RGBi.red, 1445 &pColor->spec.RGBi.green, 1446 &pColor->spec.RGBi.blue) != 3) { 1447 free(s); 1448 return(XcmsFailure); 1449 } 1450 free(s); 1451 } else 1452 return(XcmsFailure); 1453 } 1454 1455 /* 1456 * Succeeded ! 1457 */ 1458 pColor->format = XcmsRGBiFormat; 1459 pColor->pixel = 0; 1460 return (XcmsSuccess); 1461} 1462 1463 1464/* 1465 * NAME 1466 * XcmsCIEXYZToRGBi - convert CIE XYZ to RGB 1467 * 1468 * SYNOPSIS 1469 */ 1470/* ARGSUSED */ 1471Status 1472XcmsCIEXYZToRGBi( 1473 XcmsCCC ccc, 1474 XcmsColor *pXcmsColors_in_out,/* pointer to XcmsColors to convert */ 1475 unsigned int nColors, /* Number of colors */ 1476 Bool *pCompressed) /* pointer to an array of Bool */ 1477/* 1478 * DESCRIPTION 1479 * Converts color specifications in an array of XcmsColor 1480 * structures from RGB format to RGBi format. 1481 * 1482 * RETURNS 1483 * XcmsFailure if failed, 1484 * XcmsSuccess if succeeded without gamut compression. 1485 * XcmsSuccessWithCompression if succeeded with gamut 1486 * compression. 1487 */ 1488{ 1489 LINEAR_RGB_SCCData *pScreenData; 1490 XcmsFloat tmp[3]; 1491 int hasCompressed = 0; 1492 unsigned int i; 1493 XcmsColor *pColor = pXcmsColors_in_out; 1494 1495 if (ccc == NULL) { 1496 return(XcmsFailure); 1497 } 1498 1499 pScreenData = (LINEAR_RGB_SCCData *)ccc->pPerScrnInfo->screenData; 1500 1501 /* 1502 * XcmsColors should be White Point Adjusted, if necessary, by now! 1503 */ 1504 1505 /* 1506 * NEW!!! for extended gamut compression 1507 * 1508 * 1. Need to zero out pCompressed 1509 * 1510 * 2. Need to save initial address of pColor 1511 * 1512 * 3. Need to save initial address of pCompressed 1513 */ 1514 1515 for (i = 0; i < nColors; i++) { 1516 1517 /* Make sure format is XcmsCIEXYZFormat */ 1518 if (pColor->format != XcmsCIEXYZFormat) { 1519 return(XcmsFailure); 1520 } 1521 1522 /* Multiply [A]-1 * [XYZ] to get RGB intensity */ 1523 _XcmsMatVec((XcmsFloat *) pScreenData->XYZtoRGBmatrix, 1524 (XcmsFloat *) &pColor->spec, tmp); 1525 1526 if ((MIN3 (tmp[0], tmp[1], tmp[2]) < -EPS) || 1527 (MAX3 (tmp[0], tmp[1], tmp[2]) > (1.0 + EPS))) { 1528 1529 /* 1530 * RGBi out of screen's gamut 1531 */ 1532 1533 if (ccc->gamutCompProc == NULL) { 1534 /* 1535 * Aha!! Here's that little trick that will allow 1536 * gamut compression routines to get the out of bound 1537 * RGBi. 1538 */ 1539 memcpy((char *)&pColor->spec, (char *)tmp, sizeof(tmp)); 1540 pColor->format = XcmsRGBiFormat; 1541 return(XcmsFailure); 1542 } else if ((*ccc->gamutCompProc)(ccc, pXcmsColors_in_out, nColors, 1543 i, pCompressed) == 0) { 1544 return(XcmsFailure); 1545 } 1546 1547 /* 1548 * The gamut compression function should return colors in CIEXYZ 1549 * Also check again to if the new color is within gamut. 1550 */ 1551 if (pColor->format != XcmsCIEXYZFormat) { 1552 return(XcmsFailure); 1553 } 1554 _XcmsMatVec((XcmsFloat *) pScreenData->XYZtoRGBmatrix, 1555 (XcmsFloat *) &pColor->spec, tmp); 1556 if ((MIN3 (tmp[0], tmp[1], tmp[2]) < -EPS) || 1557 (MAX3 (tmp[0], tmp[1], tmp[2]) > (1.0 + EPS))) { 1558 return(XcmsFailure); 1559 } 1560 hasCompressed++; 1561 } 1562 memcpy((char *)&pColor->spec, (char *)tmp, sizeof(tmp)); 1563 /* These if statements are done to ensure the fudge factor is */ 1564 /* is taken into account. */ 1565 if (pColor->spec.RGBi.red < 0.0) { 1566 pColor->spec.RGBi.red = 0.0; 1567 } else if (pColor->spec.RGBi.red > 1.0) { 1568 pColor->spec.RGBi.red = 1.0; 1569 } 1570 if (pColor->spec.RGBi.green < 0.0) { 1571 pColor->spec.RGBi.green = 0.0; 1572 } else if (pColor->spec.RGBi.green > 1.0) { 1573 pColor->spec.RGBi.green = 1.0; 1574 } 1575 if (pColor->spec.RGBi.blue < 0.0) { 1576 pColor->spec.RGBi.blue = 0.0; 1577 } else if (pColor->spec.RGBi.blue > 1.0) { 1578 pColor->spec.RGBi.blue = 1.0; 1579 } 1580 (pColor++)->format = XcmsRGBiFormat; 1581 } 1582 return (hasCompressed ? XcmsSuccessWithCompression : XcmsSuccess); 1583} 1584 1585 1586/* 1587 * NAME 1588 * LINEAR_RGBi_to_CIEXYZ - convert RGBi to CIEXYZ 1589 * 1590 * SYNOPSIS 1591 */ 1592/* ARGSUSED */ 1593Status 1594XcmsRGBiToCIEXYZ( 1595 XcmsCCC ccc, 1596 XcmsColor *pXcmsColors_in_out,/* pointer to XcmsColors to convert */ 1597 unsigned int nColors, /* Number of colors */ 1598 Bool *pCompressed) /* pointer to a bit array */ 1599/* 1600 * DESCRIPTION 1601 * Converts color specifications in an array of XcmsColor 1602 * structures from RGBi format to CIEXYZ format. 1603 * 1604 * RETURNS 1605 * XcmsFailure if failed, 1606 * XcmsSuccess if succeeded. 1607 */ 1608{ 1609 LINEAR_RGB_SCCData *pScreenData; 1610 XcmsFloat tmp[3]; 1611 1612 /* 1613 * pCompressed ignored in this function. 1614 */ 1615 1616 if (ccc == NULL) { 1617 return(XcmsFailure); 1618 } 1619 1620 pScreenData = (LINEAR_RGB_SCCData *)ccc->pPerScrnInfo->screenData; 1621 1622 /* 1623 * XcmsColors should be White Point Adjusted, if necessary, by now! 1624 */ 1625 1626 while (nColors--) { 1627 1628 /* Multiply [A]-1 * [XYZ] to get RGB intensity */ 1629 _XcmsMatVec((XcmsFloat *) pScreenData->RGBtoXYZmatrix, 1630 (XcmsFloat *) &pXcmsColors_in_out->spec, tmp); 1631 1632 memcpy((char *)&pXcmsColors_in_out->spec, (char *)tmp, sizeof(tmp)); 1633 (pXcmsColors_in_out++)->format = XcmsCIEXYZFormat; 1634 } 1635 return(XcmsSuccess); 1636} 1637 1638 1639/* 1640 * NAME 1641 * XcmsRGBiToRGB 1642 * 1643 * SYNOPSIS 1644 */ 1645/* ARGSUSED */ 1646Status 1647XcmsRGBiToRGB( 1648 XcmsCCC ccc, 1649 XcmsColor *pXcmsColors_in_out,/* pointer to XcmsColors to convert */ 1650 unsigned int nColors, /* Number of colors */ 1651 Bool *pCompressed) /* pointer to a bit array */ 1652/* 1653 * DESCRIPTION 1654 * Converts color specifications in an array of XcmsColor 1655 * structures from RGBi format to RGB format. 1656 * 1657 * RETURNS 1658 * XcmsFailure if failed, 1659 * XcmsSuccess if succeeded without gamut compression. 1660 * XcmsSuccessWithCompression if succeeded with gamut 1661 * compression. 1662 */ 1663{ 1664 LINEAR_RGB_SCCData *pScreenData; 1665 XcmsRGB tmpRGB; 1666 IntensityRec keyIRec, answerIRec; 1667 1668 /* 1669 * pCompressed ignored in this function. 1670 */ 1671 1672 if (ccc == NULL) { 1673 return(XcmsFailure); 1674 } 1675 1676 pScreenData = (LINEAR_RGB_SCCData *)ccc->pPerScrnInfo->screenData; 1677 1678 while (nColors--) { 1679 1680 /* Make sure format is XcmsRGBiFormat */ 1681 if (pXcmsColors_in_out->format != XcmsRGBiFormat) { 1682 return(XcmsFailure); 1683 } 1684 1685 keyIRec.intensity = pXcmsColors_in_out->spec.RGBi.red; 1686 if (!_XcmsTableSearch((char *)&keyIRec, ccc->visual->bits_per_rgb, 1687 (char *)pScreenData->pRedTbl->pBase, 1688 (unsigned)pScreenData->pRedTbl->nEntries, 1689 (unsigned)sizeof(IntensityRec), 1690 (comparProcp)_XcmsIntensityCmp, (interpolProcp)_XcmsIntensityInterpolation, (char *)&answerIRec)) { 1691 return(XcmsFailure); 1692 } 1693 tmpRGB.red = answerIRec.value; 1694 1695 keyIRec.intensity = pXcmsColors_in_out->spec.RGBi.green; 1696 if (!_XcmsTableSearch((char *)&keyIRec, ccc->visual->bits_per_rgb, 1697 (char *)pScreenData->pGreenTbl->pBase, 1698 (unsigned)pScreenData->pGreenTbl->nEntries, 1699 (unsigned)sizeof(IntensityRec), 1700 (comparProcp)_XcmsIntensityCmp, (interpolProcp)_XcmsIntensityInterpolation, (char *)&answerIRec)) { 1701 return(XcmsFailure); 1702 } 1703 tmpRGB.green = answerIRec.value; 1704 1705 keyIRec.intensity = pXcmsColors_in_out->spec.RGBi.blue; 1706 if (!_XcmsTableSearch((char *)&keyIRec, ccc->visual->bits_per_rgb, 1707 (char *)pScreenData->pBlueTbl->pBase, 1708 (unsigned)pScreenData->pBlueTbl->nEntries, 1709 (unsigned)sizeof(IntensityRec), 1710 (comparProcp)_XcmsIntensityCmp, (interpolProcp)_XcmsIntensityInterpolation, (char *)&answerIRec)) { 1711 return(XcmsFailure); 1712 } 1713 tmpRGB.blue = answerIRec.value; 1714 1715 memcpy((char *)&pXcmsColors_in_out->spec, (char *)&tmpRGB, sizeof(XcmsRGB)); 1716 (pXcmsColors_in_out++)->format = XcmsRGBFormat; 1717 } 1718 return(XcmsSuccess); 1719} 1720 1721 1722/* 1723 * NAME 1724 * XcmsRGBToRGBi 1725 * 1726 * SYNOPSIS 1727 */ 1728/* ARGSUSED */ 1729Status 1730XcmsRGBToRGBi( 1731 XcmsCCC ccc, 1732 XcmsColor *pXcmsColors_in_out,/* pointer to XcmsColors to convert */ 1733 unsigned int nColors, /* Number of colors */ 1734 Bool *pCompressed) /* pointer to a bit array */ 1735/* 1736 * DESCRIPTION 1737 * Converts color specifications in an array of XcmsColor 1738 * structures from RGB format to RGBi format. 1739 * 1740 * RETURNS 1741 * XcmsFailure if failed, 1742 * XcmsSuccess if succeeded. 1743 */ 1744{ 1745 LINEAR_RGB_SCCData *pScreenData; 1746 XcmsRGBi tmpRGBi; 1747 IntensityRec keyIRec, answerIRec; 1748 1749 /* 1750 * pCompressed ignored in this function. 1751 */ 1752 1753 if (ccc == NULL) { 1754 return(XcmsFailure); 1755 } 1756 1757 pScreenData = (LINEAR_RGB_SCCData *)ccc->pPerScrnInfo->screenData; 1758 1759 while (nColors--) { 1760 1761 /* Make sure format is XcmsRGBFormat */ 1762 if (pXcmsColors_in_out->format != XcmsRGBFormat) { 1763 return(XcmsFailure); 1764 } 1765 1766 keyIRec.value = pXcmsColors_in_out->spec.RGB.red; 1767 if (!_XcmsTableSearch((char *)&keyIRec, ccc->visual->bits_per_rgb, 1768 (char *)pScreenData->pRedTbl->pBase, 1769 (unsigned)pScreenData->pRedTbl->nEntries, 1770 (unsigned)sizeof(IntensityRec), 1771 (comparProcp)_XcmsValueCmp, (interpolProcp)_XcmsValueInterpolation, (char *)&answerIRec)) { 1772 return(XcmsFailure); 1773 } 1774 tmpRGBi.red = answerIRec.intensity; 1775 1776 keyIRec.value = pXcmsColors_in_out->spec.RGB.green; 1777 if (!_XcmsTableSearch((char *)&keyIRec, ccc->visual->bits_per_rgb, 1778 (char *)pScreenData->pGreenTbl->pBase, 1779 (unsigned)pScreenData->pGreenTbl->nEntries, 1780 (unsigned)sizeof(IntensityRec), 1781 (comparProcp)_XcmsValueCmp, (interpolProcp)_XcmsValueInterpolation, (char *)&answerIRec)) { 1782 return(XcmsFailure); 1783 } 1784 tmpRGBi.green = answerIRec.intensity; 1785 1786 keyIRec.value = pXcmsColors_in_out->spec.RGB.blue; 1787 if (!_XcmsTableSearch((char *)&keyIRec, ccc->visual->bits_per_rgb, 1788 (char *)pScreenData->pBlueTbl->pBase, 1789 (unsigned)pScreenData->pBlueTbl->nEntries, 1790 (unsigned)sizeof(IntensityRec), 1791 (comparProcp)_XcmsValueCmp, (interpolProcp)_XcmsValueInterpolation, (char *)&answerIRec)) { 1792 return(XcmsFailure); 1793 } 1794 tmpRGBi.blue = answerIRec.intensity; 1795 1796 memcpy((char *)&pXcmsColors_in_out->spec, (char *)&tmpRGBi, sizeof(XcmsRGBi)); 1797 (pXcmsColors_in_out++)->format = XcmsRGBiFormat; 1798 } 1799 return(XcmsSuccess); 1800} 1801 1802/* 1803 * NAME 1804 * _XcmsInitScrnDefaultInfo 1805 * 1806 * SYNOPSIS 1807 */ 1808/* ARGSUSED */ 1809int 1810_XcmsLRGB_InitScrnDefault( 1811 Display *dpy, 1812 int screenNumber, 1813 XcmsPerScrnInfo *pPerScrnInfo) 1814/* 1815 * DESCRIPTION 1816 * Given a display and screen number, this routine attempts 1817 * to initialize the Xcms per Screen Info structure 1818 * (XcmsPerScrnInfo) with defaults. 1819 * 1820 * RETURNS 1821 * Returns zero if initialization failed; non-zero otherwise. 1822 */ 1823{ 1824 pPerScrnInfo->screenData = (XPointer)&Default_RGB_SCCData; 1825 pPerScrnInfo->screenWhitePt.spec.CIEXYZ.X = 1826 Default_RGB_SCCData.RGBtoXYZmatrix[0][0] + 1827 Default_RGB_SCCData.RGBtoXYZmatrix[0][1] + 1828 Default_RGB_SCCData.RGBtoXYZmatrix[0][2]; 1829 pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Y = 1830 Default_RGB_SCCData.RGBtoXYZmatrix[1][0] + 1831 Default_RGB_SCCData.RGBtoXYZmatrix[1][1] + 1832 Default_RGB_SCCData.RGBtoXYZmatrix[1][2]; 1833 pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Z = 1834 Default_RGB_SCCData.RGBtoXYZmatrix[2][0] + 1835 Default_RGB_SCCData.RGBtoXYZmatrix[2][1] + 1836 Default_RGB_SCCData.RGBtoXYZmatrix[2][2]; 1837 if ((pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Y < (1.0 - EPS) ) 1838 || (pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Y > (1.0 + EPS))) { 1839 pPerScrnInfo->screenData = (XPointer)NULL; 1840 pPerScrnInfo->state = XcmsInitNone; 1841 return(0); 1842 } 1843 pPerScrnInfo->screenWhitePt.spec.CIEXYZ.Y = 1.0; 1844 pPerScrnInfo->screenWhitePt.format = XcmsCIEXYZFormat; 1845 pPerScrnInfo->screenWhitePt.pixel = 0; 1846 pPerScrnInfo->functionSet = (XPointer)&XcmsLinearRGBFunctionSet; 1847 pPerScrnInfo->state = XcmsInitFailure; /* default initialization */ 1848 return(1); 1849} 1850