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