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