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 * XcmsCvCols.c 28 * 29 * DESCRIPTION 30 * Xcms API routine that converts between the 31 * device-independent color spaces. 32 * 33 * 34 */ 35 36 #ifdef HAVE_CONFIG_H 37 #include <config.h> 38 #endif 39 #include "Xlibint.h" 40 #include "Xcmsint.h" 41 #include "Cv.h" 42 #include "reallocarray.h" 43 44 /* 45 * LOCAL DEFINES 46 */ 47 #define DD_FORMAT 0x01 48 #define DI_FORMAT 0x02 49 #define MIX_FORMAT 0x04 50 #ifndef MAX 51 # define MAX(x,y) ((x) > (y) ? (x) : (y)) 52 #endif 53 54 55 /************************************************************************ 57 * * 58 * PRIVATE ROUTINES * 59 * * 60 ************************************************************************/ 61 62 /* 63 * NAME 64 * EqualCIEXYZ 65 * 66 * SYNOPSIS 67 */ 68 static int 69 EqualCIEXYZ( 70 XcmsColor *p1, XcmsColor *p2) 71 /* 72 * DESCRIPTION 73 * Compares two XcmsColor structures that are in XcmsCIEXYZFormat 74 * 75 * RETURNS 76 * Returns 1 if equal; 0 otherwise. 77 * 78 */ 79 { 80 if (p1->format != XcmsCIEXYZFormat || p2->format != XcmsCIEXYZFormat) { 81 return(0); 82 } 83 if ((p1->spec.CIEXYZ.X != p2->spec.CIEXYZ.X) 84 || (p1->spec.CIEXYZ.Y != p2->spec.CIEXYZ.Y) 85 || (p1->spec.CIEXYZ.Z != p2->spec.CIEXYZ.Z)) { 86 return(0); 87 } 88 return(1); 89 } 90 91 92 /* 94 * NAME 95 * XcmsColorSpace 96 * 97 * SYNOPSIS 98 */ 99 static XcmsColorSpace * 100 ColorSpaceOfID( 101 XcmsCCC ccc, 102 XcmsColorFormat id) 103 /* 104 * DESCRIPTION 105 * Returns a pointer to the color space structure 106 * (XcmsColorSpace) associated with the specified color space 107 * ID. 108 * 109 * RETURNS 110 * Pointer to matching XcmsColorSpace structure if found; 111 * otherwise NULL. 112 */ 113 { 114 XcmsColorSpace **papColorSpaces; 115 116 if (ccc == NULL) { 117 return(NULL); 118 } 119 120 /* 121 * First try Device-Independent color spaces 122 */ 123 papColorSpaces = _XcmsDIColorSpaces; 124 if (papColorSpaces != NULL) { 125 while (*papColorSpaces != NULL) { 126 if ((*papColorSpaces)->id == id) { 127 return(*papColorSpaces); 128 } 129 papColorSpaces++; 130 } 131 } 132 133 /* 134 * Next try Device-Dependent color spaces 135 */ 136 papColorSpaces = ((XcmsFunctionSet *)ccc->pPerScrnInfo->functionSet)->DDColorSpaces; 137 if (papColorSpaces != NULL) { 138 while (*papColorSpaces != NULL) { 139 if ((*papColorSpaces)->id == id) { 140 return(*papColorSpaces); 141 } 142 papColorSpaces++; 143 } 144 } 145 146 return(NULL); 147 } 148 149 150 /* 152 * NAME 153 * ValidDIColorSpaceID 154 * 155 * SYNOPSIS 156 */ 157 static int 158 ValidDIColorSpaceID( 159 XcmsColorFormat id) 160 /* 161 * DESCRIPTION 162 * Determines if the specified color space ID is a valid 163 * Device-Independent color space in the specified Color 164 * Conversion Context. 165 * 166 * RETURNS 167 * Returns zero if not valid; otherwise non-zero. 168 */ 169 { 170 XcmsColorSpace **papRec; 171 papRec = _XcmsDIColorSpaces; 172 if (papRec != NULL) { 173 while (*papRec != NULL) { 174 if ((*papRec)->id == id) { 175 return(1); 176 } 177 papRec++; 178 } 179 } 180 return(0); 181 } 182 183 184 /* 186 * NAME 187 * ValidDDColorSpaceID 188 * 189 * SYNOPSIS 190 */ 191 static int 192 ValidDDColorSpaceID( 193 XcmsCCC ccc, 194 XcmsColorFormat id) 195 /* 196 * DESCRIPTION 197 * Determines if the specified color space ID is a valid 198 * Device-Dependent color space in the specified Color 199 * Conversion Context. 200 * 201 * RETURNS 202 * Returns zero if not valid; otherwise non-zero. 203 */ 204 { 205 XcmsColorSpace **papRec; 206 207 if (ccc->pPerScrnInfo->state != XcmsInitNone) { 208 papRec = ((XcmsFunctionSet *)ccc->pPerScrnInfo->functionSet)->DDColorSpaces; 209 while (*papRec != NULL) { 210 if ((*papRec)->id == id) { 211 return(1); 212 } 213 papRec++; 214 } 215 } 216 return(0); 217 } 218 219 220 /* 222 * NAME 223 * ConvertMixedColors - Convert XcmsColor structures 224 * 225 * SYNOPSIS 226 */ 227 static Status 228 ConvertMixedColors( 229 XcmsCCC ccc, 230 XcmsColor *pColors_in_out, 231 XcmsColor *pWhitePt, 232 unsigned int nColors, 233 XcmsColorFormat targetFormat, 234 unsigned char format_flag) 235 /* 236 * DESCRIPTION 237 * This routine will only convert the following types of 238 * batches: 239 * DI to DI 240 * DD to DD 241 * DD to CIEXYZ 242 * In other words, it will not convert the following types of 243 * batches: 244 * DI to DD 245 * DD to DI(not CIEXYZ) 246 * 247 * format_flag: 248 * 0x01 : convert Device-Dependent only specifications to the 249 * target format. 250 * 0x02 : convert Device-Independent only specifications to the 251 * target format. 252 * 0x03 : convert all specifications to the target format. 253 * 254 * RETURNS 255 * XcmsFailure if failed, 256 * XcmsSuccess if none of the color specifications were 257 * compressed in the conversion process 258 * XcmsSuccessWithCompression if at least one of the 259 * color specifications were compressed in the 260 * conversion process. 261 * 262 */ 263 { 264 XcmsColor *pColor, *pColors_start; 265 XcmsColorFormat format; 266 Status retval_tmp; 267 Status retval = XcmsSuccess; 268 unsigned int iColors; 269 unsigned int nBatch; 270 271 /* 272 * Convert array of mixed color specifications in batches of 273 * contiguous formats to the target format 274 */ 275 iColors = 0; 276 while (iColors < nColors) { 277 /* 278 * Find contiguous array of color specifications with the 279 * same format 280 */ 281 pColor = pColors_start = pColors_in_out + iColors; 282 format = pColors_start->format; 283 nBatch = 0; 284 while (iColors < nColors && pColor->format == format) { 285 pColor++; 286 nBatch++; 287 iColors++; 288 } 289 if (format != targetFormat) { 290 /* 291 * Need to convert this batch from current format to target format. 292 */ 293 if (XCMS_DI_ID(format) && (format_flag & DI_FORMAT) && 294 XCMS_DI_ID(targetFormat)) { 295 /* 296 * DI->DI 297 * 298 * Format of interest is Device-Independent, 299 * This batch contains Device-Independent specifications, and 300 * the Target format is Device-Independent. 301 */ 302 retval_tmp = _XcmsDIConvertColors(ccc, pColors_start, pWhitePt, 303 nBatch, targetFormat); 304 } else if (XCMS_DD_ID(format) && (format_flag & DD_FORMAT) && 305 (targetFormat == XcmsCIEXYZFormat)) { 306 /* 307 * DD->CIEXYZ 308 * 309 * Format of interest is Device-Dependent, 310 * This batch contains Device-Dependent specifications, and 311 * the Target format is CIEXYZ. 312 * 313 * Since DD->CIEXYZ we can use NULL instead of pCompressed. 314 */ 315 if ((ccc->whitePtAdjProc != NULL) && !_XcmsEqualWhitePts(ccc, 316 pWhitePt, ScreenWhitePointOfCCC(ccc))) { 317 /* 318 * Need to call WhiteAdjustProc (Screen White Point to 319 * White Point). 320 */ 321 retval_tmp = (*ccc->whitePtAdjProc)(ccc, 322 ScreenWhitePointOfCCC(ccc), pWhitePt, 323 XcmsCIEXYZFormat, pColors_start, nBatch, 324 (Bool *)NULL); 325 } else { 326 retval_tmp = _XcmsDDConvertColors(ccc, pColors_start, 327 nBatch, XcmsCIEXYZFormat, (Bool *)NULL); 328 } 329 } else if (XCMS_DD_ID(format) && (format_flag & DD_FORMAT) && 330 XCMS_DD_ID(targetFormat)) { 331 /* 332 * DD->DD(not CIEXYZ) 333 * 334 * Format of interest is Device-Dependent, 335 * This batch contains Device-Dependent specifications, and 336 * the Target format is Device-Dependent and not CIEXYZ. 337 */ 338 retval_tmp = _XcmsDDConvertColors(ccc, pColors_start, nBatch, 339 targetFormat, (Bool *)NULL); 340 } else { 341 /* 342 * This routine is called for the wrong reason. 343 */ 344 return(XcmsFailure); 345 } 346 if (retval_tmp == XcmsFailure) { 347 return(XcmsFailure); 348 } 349 retval = MAX(retval, retval_tmp); 350 } 351 } 352 return(retval); 353 } 354 355 356 /************************************************************************ 358 * * 359 * API PRIVATE ROUTINES * 360 * * 361 ************************************************************************/ 362 363 /* 364 * NAME 365 * _XcmsEqualWhitePts 366 * 367 * SYNOPSIS 368 */ 369 int 370 _XcmsEqualWhitePts(XcmsCCC ccc, XcmsColor *pWhitePt1, XcmsColor *pWhitePt2) 371 /* 372 * DESCRIPTION 373 * 374 * RETURNS 375 * Returns 0 if not equal; otherwise 1. 376 * 377 */ 378 { 379 XcmsColor tmp1, tmp2; 380 381 memcpy((char *)&tmp1, (char *)pWhitePt1, sizeof(XcmsColor)); 382 memcpy((char *)&tmp2, (char *)pWhitePt2, sizeof(XcmsColor)); 383 384 if (tmp1.format != XcmsCIEXYZFormat) { 385 if (_XcmsDIConvertColors(ccc, &tmp1, (XcmsColor *) NULL, 1, 386 XcmsCIEXYZFormat)==0) { 387 return(0); 388 } 389 } 390 391 if (tmp2.format != XcmsCIEXYZFormat) { 392 if (_XcmsDIConvertColors(ccc, &tmp2, (XcmsColor *) NULL, 1, 393 XcmsCIEXYZFormat)==0) { 394 return(0); 395 } 396 } 397 398 return (EqualCIEXYZ(&tmp1, &tmp2)); 399 } 400 401 402 /* 404 * NAME 405 * _XcmsDIConvertColors - Convert XcmsColor structures 406 * 407 * SYNOPSIS 408 */ 409 Status 410 _XcmsDIConvertColors( 411 XcmsCCC ccc, 412 XcmsColor *pColors_in_out, 413 XcmsColor *pWhitePt, 414 unsigned int nColors, 415 XcmsColorFormat newFormat) 416 /* 417 * DESCRIPTION 418 * Convert XcmsColor structures to another Device-Independent 419 * form. 420 * 421 * Here are some assumptions that this routine makes: 422 * 1. The calling routine has already checked if 423 * pColors_in_out->format == newFormat, therefore 424 * there is no need to check again here. 425 * 2. The calling routine has already checked nColors, 426 * therefore this routine assumes nColors > 0. 427 * 3. The calling routine may want to convert only between 428 * CIExyY <-> CIEXYZ <-> CIEuvY 429 * therefore, this routine allows pWhitePt to equal NULL. 430 * 431 * 432 * RETURNS 433 * XcmsFailure if failed, 434 * XcmsSuccess if succeeded. 435 * 436 */ 437 { 438 XcmsColorSpace *pFrom, *pTo; 439 XcmsDIConversionProc *src_to_CIEXYZ, *src_from_CIEXYZ; 440 XcmsDIConversionProc *dest_to_CIEXYZ, *dest_from_CIEXYZ; 441 XcmsDIConversionProc *to_CIEXYZ_stop, *from_CIEXYZ_start; 442 XcmsDIConversionProc *tmp; 443 444 /* 445 * Allow pWhitePt to equal NULL. This appropriate when converting 446 * anywhere between: 447 * CIExyY <-> CIEXYZ <-> CIEuvY 448 */ 449 450 if (pColors_in_out == NULL || 451 !ValidDIColorSpaceID(pColors_in_out->format) || 452 !ValidDIColorSpaceID(newFormat)) { 453 return(XcmsFailure); 454 } 455 456 /* 457 * Get a handle on the function list for the current specification format 458 */ 459 if ((pFrom = ColorSpaceOfID(ccc, pColors_in_out->format)) 460 == NULL) { 461 return(XcmsFailure); 462 } 463 464 /* 465 * Get a handle on the function list for the new specification format 466 */ 467 if ((pTo = ColorSpaceOfID(ccc, newFormat)) == NULL) { 468 return(XcmsFailure); 469 } 470 471 src_to_CIEXYZ = pFrom->to_CIEXYZ; 472 src_from_CIEXYZ = pFrom->from_CIEXYZ; 473 dest_to_CIEXYZ = pTo->to_CIEXYZ; 474 dest_from_CIEXYZ = pTo->from_CIEXYZ; 475 476 if (pTo->inverse_flag && pFrom->inverse_flag) { 477 /* 478 * Find common function pointers 479 */ 480 for (to_CIEXYZ_stop = src_to_CIEXYZ; *to_CIEXYZ_stop; to_CIEXYZ_stop++){ 481 for (tmp = dest_to_CIEXYZ; *tmp; tmp++) { 482 if (*to_CIEXYZ_stop == *tmp) { 483 goto Continue; 484 } 485 } 486 } 487 488 Continue: 489 490 /* 491 * Execute the functions to CIEXYZ, stopping short as necessary 492 */ 493 while (src_to_CIEXYZ != to_CIEXYZ_stop) { 494 if ((*src_to_CIEXYZ++)(ccc, pWhitePt, pColors_in_out, 495 nColors) == XcmsFailure) { 496 return(XcmsFailure); 497 } 498 } 499 500 /* 501 * Determine where to start on the from_CIEXYZ path. 502 */ 503 from_CIEXYZ_start = dest_from_CIEXYZ; 504 tmp = src_from_CIEXYZ; 505 while ((*from_CIEXYZ_start == *tmp) && (*from_CIEXYZ_start != NULL)) { 506 from_CIEXYZ_start++; 507 tmp++; 508 } 509 510 } else { 511 /* 512 * The function in at least one of the Color Spaces are not 513 * complementary, i.e., 514 * for an i, 0 <= i < n elements 515 * from_CIEXYZ[i] is not the inverse of to_CIEXYZ[i] 516 * 517 * Execute the functions all the way to CIEXYZ 518 */ 519 while (*src_to_CIEXYZ) { 520 if ((*src_to_CIEXYZ++)(ccc, pWhitePt, pColors_in_out, 521 nColors) == XcmsFailure) { 522 return(XcmsFailure); 523 } 524 } 525 526 /* 527 * Determine where to start on the from_CIEXYZ path. 528 */ 529 from_CIEXYZ_start = dest_from_CIEXYZ; 530 } 531 532 533 /* 534 * Execute the functions from CIEXYZ. 535 */ 536 while (*from_CIEXYZ_start) { 537 if ((*from_CIEXYZ_start++)(ccc, pWhitePt, pColors_in_out, 538 nColors) == XcmsFailure) { 539 return(XcmsFailure); 540 } 541 } 542 543 return(XcmsSuccess); 544 } 545 546 547 /* 549 * NAME 550 * _XcmsDDConvertColors - Convert XcmsColor structures 551 * 552 * SYNOPSIS 553 */ 554 Status 555 _XcmsDDConvertColors( 556 XcmsCCC ccc, 557 XcmsColor *pColors_in_out, 558 unsigned int nColors, 559 XcmsColorFormat newFormat, 560 Bool *pCompressed) 561 /* 562 * DESCRIPTION 563 * Convert XcmsColor structures: 564 * 565 * 1. From CIEXYZ to Device-Dependent formats (typically RGB and 566 * RGBi), 567 * or 568 * 2. Between Device-Dependent formats (typically RGB and RGBi). 569 * 570 * Assumes that these specifications have already been white point 571 * adjusted if necessary from Client White Point to Screen 572 * White Point. Therefore, the white point now associated 573 * with the specifications is the Screen White Point. 574 * 575 * pCompressed may be NULL. If so this indicates that the 576 * calling routine is not interested in knowing exactly which 577 * color was compressed, if any. 578 * 579 * 580 * RETURNS 581 * XcmsFailure if failed, 582 * XcmsSuccess if none of the color specifications were 583 * compressed in the conversion process 584 * XcmsSuccessWithCompression if at least one of the 585 * color specifications were compressed in the 586 * conversion process. 587 * 588 */ 589 { 590 XcmsColorSpace *pFrom, *pTo; 591 XcmsDDConversionProc *src_to_CIEXYZ, *src_from_CIEXYZ; 592 XcmsDDConversionProc *dest_to_CIEXYZ, *dest_from_CIEXYZ; 593 XcmsDDConversionProc *from_CIEXYZ_start, *to_CIEXYZ_stop; 594 XcmsDDConversionProc *tmp; 595 int retval; 596 int hasCompressed = 0; 597 598 if (ccc == NULL || pColors_in_out == NULL) { 599 return(XcmsFailure); 600 } 601 602 if (nColors == 0 || pColors_in_out->format == newFormat) { 603 /* do nothing */ 604 return(XcmsSuccess); 605 } 606 607 if (((XcmsFunctionSet *)ccc->pPerScrnInfo->functionSet) == NULL) { 608 return(XcmsFailure); /* hmm, an internal error? */ 609 } 610 611 /* 612 * Its ok if pColors_in_out->format == XcmsCIEXYZFormat 613 * or 614 * if newFormat == XcmsCIEXYZFormat 615 */ 616 if ( !( ValidDDColorSpaceID(ccc, pColors_in_out->format) 617 || 618 (pColors_in_out->format == XcmsCIEXYZFormat)) 619 || 620 !(ValidDDColorSpaceID(ccc, newFormat) 621 || 622 newFormat == XcmsCIEXYZFormat)) { 623 return(XcmsFailure); 624 } 625 626 if ((pFrom = ColorSpaceOfID(ccc, pColors_in_out->format)) == NULL){ 627 return(XcmsFailure); 628 } 629 630 if ((pTo = ColorSpaceOfID(ccc, newFormat)) == NULL) { 631 return(XcmsFailure); 632 } 633 634 src_to_CIEXYZ = (XcmsDDConversionProc *)pFrom->to_CIEXYZ; 635 src_from_CIEXYZ = (XcmsDDConversionProc *)pFrom->from_CIEXYZ; 636 dest_to_CIEXYZ = (XcmsDDConversionProc *)pTo->to_CIEXYZ; 637 dest_from_CIEXYZ = (XcmsDDConversionProc *)pTo->from_CIEXYZ; 638 639 if (pTo->inverse_flag && pFrom->inverse_flag) { 640 /* 641 * Find common function pointers 642 */ 643 for (to_CIEXYZ_stop = src_to_CIEXYZ; *to_CIEXYZ_stop; to_CIEXYZ_stop++){ 644 for (tmp = dest_to_CIEXYZ; *tmp; tmp++) { 645 if (*to_CIEXYZ_stop == *tmp) { 646 goto Continue; 647 } 648 } 649 } 650 Continue: 651 652 /* 653 * Execute the functions 654 */ 655 while (src_to_CIEXYZ != to_CIEXYZ_stop) { 656 retval = (*src_to_CIEXYZ++)(ccc, pColors_in_out, nColors, 657 pCompressed); 658 if (retval == XcmsFailure) { 659 return(XcmsFailure); 660 } 661 hasCompressed |= (retval == XcmsSuccessWithCompression); 662 } 663 664 /* 665 * Determine where to start on the from_CIEXYZ path. 666 */ 667 from_CIEXYZ_start = dest_from_CIEXYZ; 668 tmp = src_from_CIEXYZ; 669 while ((*from_CIEXYZ_start == *tmp) && (*from_CIEXYZ_start != NULL)) { 670 from_CIEXYZ_start++; 671 tmp++; 672 } 673 674 } else { 675 /* 676 * The function in at least one of the Color Spaces are not 677 * complementary, i.e., 678 * for an i, 0 <= i < n elements 679 * from_CIEXYZ[i] is not the inverse of to_CIEXYZ[i] 680 * 681 * Execute the functions all the way to CIEXYZ 682 */ 683 while (*src_to_CIEXYZ) { 684 retval = (*src_to_CIEXYZ++)(ccc, pColors_in_out, nColors, 685 pCompressed); 686 if (retval == XcmsFailure) { 687 return(XcmsFailure); 688 } 689 hasCompressed |= (retval == XcmsSuccessWithCompression); 690 } 691 692 /* 693 * Determine where to start on the from_CIEXYZ path. 694 */ 695 from_CIEXYZ_start = dest_from_CIEXYZ; 696 } 697 698 while (*from_CIEXYZ_start) { 699 retval = (*from_CIEXYZ_start++)(ccc, pColors_in_out, nColors, 700 pCompressed); 701 if (retval == XcmsFailure) { 702 return(XcmsFailure); 703 } 704 hasCompressed |= (retval == XcmsSuccessWithCompression); 705 } 706 707 return(hasCompressed ? XcmsSuccessWithCompression : XcmsSuccess); 708 } 709 710 711 /************************************************************************ 713 * * 714 * PUBLIC ROUTINES * 715 * * 716 ************************************************************************/ 717 718 /* 719 * NAME 720 * XcmsConvertColors - Convert XcmsColor structures 721 * 722 * SYNOPSIS 723 */ 724 Status 725 XcmsConvertColors( 726 XcmsCCC ccc, 727 XcmsColor *pColors_in_out, 728 unsigned int nColors, 729 XcmsColorFormat targetFormat, 730 Bool *pCompressed) 731 /* 732 * DESCRIPTION 733 * Convert XcmsColor structures to another format 734 * 735 * RETURNS 736 * XcmsFailure if failed, 737 * XcmsSuccess if succeeded without gamut compression, 738 * XcmsSuccessWithCompression if succeeded with gamut 739 * compression. 740 * 741 */ 742 { 743 XcmsColor clientWhitePt; 744 XcmsColor Color1; 745 XcmsColor *pColors_tmp; 746 int callWhiteAdjustProc = 0; 747 XcmsColorFormat format; 748 Status retval; 749 unsigned char contents_flag = 0x00; 750 unsigned int iColors; 751 752 if (ccc == NULL || pColors_in_out == NULL || 753 !(ValidDIColorSpaceID(targetFormat) || 754 ValidDDColorSpaceID(ccc, targetFormat))) { 755 return(XcmsFailure); 756 } 757 758 /* 759 * Check formats in color specification array 760 */ 761 format = pColors_in_out->format; 762 for (pColors_tmp = pColors_in_out, iColors = nColors; iColors; pColors_tmp++, iColors--) { 763 if (!(ValidDIColorSpaceID(pColors_tmp->format) || 764 ValidDDColorSpaceID(ccc, pColors_tmp->format))) { 765 return(XcmsFailure); 766 } 767 if (XCMS_DI_ID(pColors_tmp->format)) { 768 contents_flag |= DI_FORMAT; 769 } else { 770 contents_flag |= DD_FORMAT; 771 } 772 if (pColors_tmp->format != format) { 773 contents_flag |= MIX_FORMAT; 774 } 775 } 776 777 /* 778 * Check if we need the Client White Point. 779 */ 780 if ((contents_flag & DI_FORMAT) || XCMS_DI_ID(targetFormat)) { 781 /* To proceed, we need to get the Client White Point */ 782 memcpy((char *)&clientWhitePt, (char *)&ccc->clientWhitePt, 783 sizeof(XcmsColor)); 784 if (clientWhitePt.format == XcmsUndefinedFormat) { 785 /* 786 * Client White Point is undefined, therefore set to the Screen 787 * White Point. 788 * Since Client White Point == Screen White Point, WhiteAdjustProc 789 * is not called. 790 */ 791 memcpy((char *)&clientWhitePt, 792 (char *)&ccc->pPerScrnInfo->screenWhitePt, 793 sizeof(XcmsColor)); 794 } else if ((ccc->whitePtAdjProc != NULL) && !_XcmsEqualWhitePts(ccc, 795 &clientWhitePt, ScreenWhitePointOfCCC(ccc))) { 796 /* 797 * Client White Point != Screen White Point, and WhiteAdjustProc 798 * is not NULL, therefore, will need to call it when 799 * converting between DI and DD specifications. 800 */ 801 callWhiteAdjustProc = 1; 802 } 803 } 804 805 /* 806 * Make copy of array of color specifications 807 */ 808 if (nColors > 1) { 809 pColors_tmp = Xmallocarray(nColors, sizeof(XcmsColor)); 810 if (pColors_tmp == NULL) 811 return(XcmsFailure); 812 } else { 813 pColors_tmp = &Color1; 814 } 815 memcpy((char *)pColors_tmp, (char *)pColors_in_out, 816 nColors * sizeof(XcmsColor)); 817 818 /* 819 * zero out pCompressed 820 */ 821 if (pCompressed) { 822 bzero((char *)pCompressed, nColors * sizeof(Bool)); 823 } 824 825 if (contents_flag == DD_FORMAT || contents_flag == DI_FORMAT) { 826 /* 827 * ENTIRE ARRAY IS IN ONE FORMAT. 828 */ 829 if (XCMS_DI_ID(format) && XCMS_DI_ID(targetFormat)) { 830 /* 831 * DI-to-DI only conversion 832 */ 833 retval = _XcmsDIConvertColors(ccc, pColors_tmp, 834 &clientWhitePt, nColors, targetFormat); 835 } else if (XCMS_DD_ID(format) && XCMS_DD_ID(targetFormat)) { 836 /* 837 * DD-to-DD only conversion 838 * Since DD->DD there will be no compressed thus we can 839 * pass NULL instead of pCompressed. 840 */ 841 retval = _XcmsDDConvertColors(ccc, pColors_tmp, nColors, 842 targetFormat, (Bool *)NULL); 843 } else { 844 /* 845 * Otherwise we have: 846 * 1. Device-Independent to Device-Dependent Conversion 847 * OR 848 * 2. Device-Dependent to Device-Independent Conversion 849 * 850 * We need to go from oldFormat -> CIEXYZ -> targetFormat 851 * adjusting for white points as necessary. 852 */ 853 854 if (XCMS_DI_ID(format)) { 855 /* 856 * 1. Device-Independent to Device-Dependent Conversion 857 */ 858 if (callWhiteAdjustProc) { 859 /* 860 * White Point Adjustment 861 * Client White Point to Screen White Point 862 */ 863 retval = (*ccc->whitePtAdjProc)(ccc, &clientWhitePt, 864 ScreenWhitePointOfCCC(ccc), targetFormat, 865 pColors_tmp, nColors, pCompressed); 866 } else { 867 if (_XcmsDIConvertColors(ccc, pColors_tmp, 868 &clientWhitePt, nColors, XcmsCIEXYZFormat) 869 == XcmsFailure) { 870 goto Failure; 871 } 872 retval = _XcmsDDConvertColors(ccc, pColors_tmp, nColors, 873 targetFormat, pCompressed); 874 } 875 } else { 876 /* 877 * 2. Device-Dependent to Device-Independent Conversion 878 */ 879 if (callWhiteAdjustProc) { 880 /* 881 * White Point Adjustment 882 * Screen White Point to Client White Point 883 */ 884 retval = (*ccc->whitePtAdjProc)(ccc, 885 ScreenWhitePointOfCCC(ccc), &clientWhitePt, 886 targetFormat, pColors_tmp, nColors, pCompressed); 887 } else { 888 /* 889 * Since DD->CIEXYZ, no compression takes place therefore 890 * we can pass NULL instead of pCompressed. 891 */ 892 if (_XcmsDDConvertColors(ccc, pColors_tmp, nColors, 893 XcmsCIEXYZFormat, (Bool *)NULL) == XcmsFailure) { 894 goto Failure; 895 } 896 retval = _XcmsDIConvertColors(ccc, pColors_tmp, 897 &clientWhitePt, nColors, targetFormat); 898 } 899 } 900 } 901 } else { 902 /* 903 * ARRAY HAS MIXED FORMATS. 904 */ 905 if ((contents_flag == (DI_FORMAT | MIX_FORMAT)) && 906 XCMS_DI_ID(targetFormat)) { 907 /* 908 * Convert from DI to DI in batches of contiguous formats 909 * 910 * Because DI->DI, WhiteAdjustProc not called. 911 */ 912 retval = ConvertMixedColors(ccc, pColors_tmp, &clientWhitePt, 913 nColors, targetFormat, (unsigned char)DI_FORMAT); 914 } else if ((contents_flag == (DD_FORMAT | MIX_FORMAT)) && 915 XCMS_DD_ID(targetFormat)) { 916 /* 917 * Convert from DD to DD in batches of contiguous formats 918 * 919 * Because DD->DD, WhiteAdjustProc not called. 920 */ 921 retval = ConvertMixedColors(ccc, pColors_tmp, 922 (XcmsColor *)NULL, nColors, targetFormat, 923 (unsigned char)DD_FORMAT); 924 } else if (XCMS_DI_ID(targetFormat)) { 925 /* 926 * We need to convert from DI-to-DI and DD-to-DI, therefore 927 * 1. convert DD specifications to CIEXYZ, then 928 * 2. convert all in batches to the target DI format. 929 * 930 * Note that ConvertMixedColors will call WhiteAdjustProc 931 * as necessary. 932 */ 933 934 /* 935 * Convert only DD specifications in batches of contiguous formats 936 * to CIEXYZ 937 * 938 * Since DD->CIEXYZ, ConvertMixedColors will apply WhiteAdjustProc 939 * if required. 940 */ 941 retval = ConvertMixedColors(ccc, pColors_tmp, &clientWhitePt, 942 nColors, XcmsCIEXYZFormat, (unsigned char)DD_FORMAT); 943 944 /* 945 * Because at this point we may have a mix of DI formats 946 * (e.g., CIEXYZ, CIELuv) we must convert the specs to the 947 * target DI format in batches of contiguous source formats. 948 */ 949 retval = ConvertMixedColors(ccc, pColors_tmp, &clientWhitePt, 950 nColors, targetFormat, (unsigned char)DI_FORMAT); 951 } else { 952 /* 953 * We need to convert from DI-to-DD and DD-to-DD, therefore 954 * 1. convert DI specifications to CIEXYZ, then 955 * 2. convert all to the DD target format. 956 * 957 * This allows white point adjustment and gamut compression 958 * to be applied to all the color specifications in one 959 * swoop if those functions do in fact modify the entire 960 * group of color specifications. 961 */ 962 963 /* 964 * Convert in batches to CIEXYZ 965 * 966 * If DD->CIEXYZ, ConvertMixedColors will apply WhiteAdjustProc 967 * if required. 968 */ 969 if ((retval = ConvertMixedColors(ccc, pColors_tmp, &clientWhitePt, 970 nColors, XcmsCIEXYZFormat, 971 (unsigned char)(DI_FORMAT | DD_FORMAT))) == XcmsFailure) { 972 goto Failure; 973 } 974 975 /* 976 * Convert all specifications (now in CIEXYZ format) to 977 * the target DD format. 978 * Since CIEXYZ->DD, compression MAY take place therefore 979 * we must pass pCompressed. 980 * Note that WhiteAdjustProc must be used if necessary. 981 */ 982 if (callWhiteAdjustProc) { 983 /* 984 * White Point Adjustment 985 * Client White Point to Screen White Point 986 */ 987 retval = (*ccc->whitePtAdjProc)(ccc, 988 &clientWhitePt, ScreenWhitePointOfCCC(ccc), 989 targetFormat, pColors_tmp, nColors, pCompressed); 990 } else { 991 retval = _XcmsDDConvertColors(ccc, pColors_tmp, nColors, 992 targetFormat, pCompressed); 993 } 994 } 995 } 996 997 if (retval != XcmsFailure) { 998 memcpy((char *)pColors_in_out, (char *)pColors_tmp, 999 nColors * sizeof(XcmsColor)); 1000 } 1001 if (nColors > 1) { 1002 Xfree(pColors_tmp); 1003 } 1004 return(retval); 1005 1006 Failure: 1007 if (nColors > 1) { 1008 Xfree(pColors_tmp); 1009 } 1010 return(XcmsFailure); 1011 } 1012 1013 1014 /* 1016 * NAME 1017 * XcmsRegFormatOfPrefix 1018 * 1019 * SYNOPSIS 1020 */ 1021 XcmsColorFormat 1022 _XcmsRegFormatOfPrefix( 1023 _Xconst char *prefix) 1024 /* 1025 * DESCRIPTION 1026 * Returns a color space ID associated with the specified 1027 * X Consortium registered color space prefix. 1028 * 1029 * RETURNS 1030 * The color space ID if found; 1031 * otherwise NULL. 1032 */ 1033 { 1034 XcmsRegColorSpaceEntry *pEntry = _XcmsRegColorSpaces; 1035 1036 while (pEntry->prefix != NULL) { 1037 if (strcmp(prefix, pEntry->prefix) == 0) { 1038 return(pEntry->id); 1039 } 1040 pEntry++; 1041 } 1042 return(XcmsUndefinedFormat); 1043 } 1044