]> git.ipfire.org Git - thirdparty/cups.git/blame - driver/cmyk.c
Import CUPS 1.4svn-r7356.
[thirdparty/cups.git] / driver / cmyk.c
CommitLineData
ac884b6a
MS
1/*
2 * "$Id$"
3 *
4 * CMYK color separation code for CUPS.
5 *
6 * Copyright 2007 by Apple Inc.
7 * Copyright 1993-2005 by Easy Software Products.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * Contents:
16 *
17 * cupsCMYKDelete() - Delete a color separation.
18 * cupsCMYKDoBlack() - Do a black separation...
19 * cupsCMYKDoCMYK() - Do a CMYK separation...
20 * cupsCMYKDoGray() - Do a grayscale separation...
21 * cupsCMYKDoRGB() - Do an sRGB separation...
22 * cupsCMYKLoad() - Load a CMYK color profile from PPD attributes.
23 * cupsCMYKNew() - Create a new CMYK color separation.
24 * cupsCMYKSetBlack() - Set the transition range for CMY to black.
25 * cupsCMYKSetCurve() - Set a color transform curve using points.
26 * cupsCMYKSetGamma() - Set a color transform curve using gamma and
27 * density.
28 * cupsCMYKSetInkLimit() - Set the limit on the amount of ink.
29 * cupsCMYKSetLtDk() - Set light/dark ink transforms.
30 */
31
32/*
33 * Include necessary headers.
34 */
35
36#include "driver.h"
37#include <cups/string.h>
38
39
40/*
41 * 'cupsCMYKDelete()' - Delete a color separation.
42 */
43
44void
45cupsCMYKDelete(cups_cmyk_t *cmyk) /* I - Color separation */
46{
47 /*
48 * Range check input...
49 */
50
51 if (cmyk == NULL)
52 return;
53
54 /*
55 * Free memory used...
56 */
57
58 free(cmyk->channels[0]);
59 free(cmyk);
60}
61
62
63/*
64 * 'cupsCMYKDoBlack()' - Do a black separation...
65 */
66
67void
68cupsCMYKDoBlack(const cups_cmyk_t *cmyk,
69 /* I - Color separation */
70 const unsigned char *input,
71 /* I - Input grayscale pixels */
72 short *output,
73 /* O - Output Device-N pixels */
74 int num_pixels)
75 /* I - Number of pixels */
76{
77 int k; /* Current black value */
78 const short **channels; /* Copy of channel LUTs */
79 const unsigned char *black_lut, /* Black LUT */
80 *color_lut; /* Color LUT */
81 int ink, /* Amount of ink */
82 ink_limit; /* Ink limit from separation */
83
84
85 /*
86 * Range check input...
87 */
88
89 if (cmyk == NULL || input == NULL || output == NULL || num_pixels <= 0)
90 return;
91
92 /*
93 * Loop through it all...
94 */
95
96 channels = (const short **)cmyk->channels;
97 black_lut = cmyk->black_lut;
98 color_lut = cmyk->color_lut;
99 ink_limit = cmyk->ink_limit;
100
101 switch (cmyk->num_channels)
102 {
103 case 1 : /* Black */
104 while (num_pixels > 0)
105 {
106 /*
107 * Get the input black value and then set the corresponding color
108 * channel values...
109 */
110
111 k = *input++;
112 *output++ = channels[0][k];
113
114 num_pixels --;
115 }
116 break;
117
118 case 2 : /* Black, light black */
119 while (num_pixels > 0)
120 {
121 /*
122 * Get the input black value and then set the corresponding color
123 * channel values...
124 */
125
126 k = *input++;
127 output[0] = channels[0][k];
128 output[1] = channels[1][k];
129
130 if (ink_limit)
131 {
132 ink = output[0] + output[1];
133
134 if (ink > ink_limit)
135 {
136 output[0] = ink_limit * output[0] / ink;
137 output[1] = ink_limit * output[1] / ink;
138 }
139 }
140
141 output += 2;
142 num_pixels --;
143 }
144 break;
145
146 case 3 : /* CMY */
147 while (num_pixels > 0)
148 {
149 /*
150 * Get the input black value and then set the corresponding color
151 * channel values...
152 */
153
154 k = *input++;
155 output[0] = channels[0][k];
156 output[1] = channels[1][k];
157 output[2] = channels[2][k];
158
159 if (ink_limit)
160 {
161 ink = output[0] + output[1] + output[2];
162
163 if (ink > ink_limit)
164 {
165 output[0] = ink_limit * output[0] / ink;
166 output[1] = ink_limit * output[1] / ink;
167 output[2] = ink_limit * output[2] / ink;
168 }
169 }
170
171 output += 3;
172 num_pixels --;
173 }
174 break;
175
176 case 4 : /* CMYK */
177 while (num_pixels > 0)
178 {
179 /*
180 * Get the input black value and then set the corresponding color
181 * channel values...
182 */
183
184 k = *input++;
185 *output++ = 0;
186 *output++ = 0;
187 *output++ = 0;
188 *output++ = channels[3][k];
189
190 num_pixels --;
191 }
192 break;
193
194 case 6 : /* CcMmYK */
195 while (num_pixels > 0)
196 {
197 /*
198 * Get the input black value and then set the corresponding color
199 * channel values...
200 */
201
202 k = *input++;
203 *output++ = 0;
204 *output++ = 0;
205 *output++ = 0;
206 *output++ = 0;
207 *output++ = 0;
208 *output++ = channels[5][k];
209
210 num_pixels --;
211 }
212 break;
213
214 case 7 : /* CcMmYKk */
215 while (num_pixels > 0)
216 {
217 /*
218 * Get the input black value and then set the corresponding color
219 * channel values...
220 */
221
222 k = *input++;
223 output[0] = 0;
224 output[1] = 0;
225 output[2] = 0;
226 output[3] = 0;
227 output[4] = 0;
228 output[5] = channels[5][k];
229 output[6] = channels[6][k];
230
231 if (ink_limit)
232 {
233 ink = output[5] + output[6];
234
235 if (ink > ink_limit)
236 {
237 output[5] = ink_limit * output[5] / ink;
238 output[6] = ink_limit * output[6] / ink;
239 }
240 }
241
242 output += 7;
243 num_pixels --;
244 }
245 break;
246 }
247}
248
249
250/*
251 * 'cupsCMYKDoCMYK()' - Do a CMYK separation...
252 */
253
254void
255cupsCMYKDoCMYK(const cups_cmyk_t *cmyk,
256 /* I - Color separation */
257 const unsigned char *input,
258 /* I - Input grayscale pixels */
259 short *output,
260 /* O - Output Device-N pixels */
261 int num_pixels)
262 /* I - Number of pixels */
263{
264 int c, /* Current cyan value */
265 m, /* Current magenta value */
266 y, /* Current yellow value */
267 k; /* Current black value */
268 const short **channels; /* Copy of channel LUTs */
269 const unsigned char *black_lut, /* Black LUT */
270 *color_lut; /* Color LUT */
271 int ink, /* Amount of ink */
272 ink_limit; /* Ink limit from separation */
273
274
275 /*
276 * Range check input...
277 */
278
279 if (cmyk == NULL || input == NULL || output == NULL || num_pixels <= 0)
280 return;
281
282 /*
283 * Loop through it all...
284 */
285
286 channels = (const short **)cmyk->channels;
287 black_lut = cmyk->black_lut;
288 color_lut = cmyk->color_lut;
289 ink_limit = cmyk->ink_limit;
290
291 switch (cmyk->num_channels)
292 {
293 case 1 : /* Black */
294 while (num_pixels > 0)
295 {
296 /*
297 * Get the input black value and then set the corresponding color
298 * channel values...
299 */
300
301 c = *input++;
302 m = *input++;
303 y = *input++;
304 k = *input++ + (c * 31 + m * 61 + y * 8) / 100;
305
306 if (k < 255)
307 *output++ = channels[0][k];
308 else
309 *output++ = channels[0][255];
310
311 num_pixels --;
312 }
313 break;
314
315 case 2 : /* Black, light black */
316 while (num_pixels > 0)
317 {
318 /*
319 * Get the input black value and then set the corresponding color
320 * channel values...
321 */
322
323 c = *input++;
324 m = *input++;
325 y = *input++;
326 k = *input++ + (c * 31 + m * 61 + y * 8) / 100;
327
328 if (k < 255)
329 {
330 output[0] = channels[0][k];
331 output[1] = channels[1][k];
332 }
333 else
334 {
335 output[0] = channels[0][255];
336 output[1] = channels[1][255];
337 }
338
339 if (ink_limit)
340 {
341 ink = output[0] + output[1];
342
343 if (ink > ink_limit)
344 {
345 output[0] = ink_limit * output[0] / ink;
346 output[1] = ink_limit * output[1] / ink;
347 }
348 }
349
350 output += 2;
351 num_pixels --;
352 }
353 break;
354
355 case 3 : /* CMY */
356 while (num_pixels > 0)
357 {
358 /*
359 * Get the input black value and then set the corresponding color
360 * channel values...
361 */
362
363 c = *input++;
364 m = *input++;
365 y = *input++;
366 k = *input++;
367 c += k;
368 m += k;
369 y += k;
370
371 if (c < 255)
372 output[0] = channels[0][c];
373 else
374 output[0] = channels[0][255];
375
376 if (m < 255)
377 output[1] = channels[1][m];
378 else
379 output[1] = channels[1][255];
380
381 if (y < 255)
382 output[2] = channels[2][y];
383 else
384 output[2] = channels[2][255];
385
386 if (ink_limit)
387 {
388 ink = output[0] + output[1] + output[2];
389
390 if (ink > ink_limit)
391 {
392 output[0] = ink_limit * output[0] / ink;
393 output[1] = ink_limit * output[1] / ink;
394 output[2] = ink_limit * output[2] / ink;
395 }
396 }
397
398 output += 3;
399 num_pixels --;
400 }
401 break;
402
403 case 4 : /* CMYK */
404 while (num_pixels > 0)
405 {
406 /*
407 * Get the input black value and then set the corresponding color
408 * channel values...
409 */
410
411 c = *input++;
412 m = *input++;
413 y = *input++;
414 k = *input++;
415
416 output[0] = channels[0][c];
417 output[1] = channels[1][m];
418 output[2] = channels[2][y];
419 output[3] = channels[3][k];
420
421 if (ink_limit)
422 {
423 ink = output[0] + output[1] + output[2] + output[3];
424
425 if (ink > ink_limit)
426 {
427 output[0] = ink_limit * output[0] / ink;
428 output[1] = ink_limit * output[1] / ink;
429 output[2] = ink_limit * output[2] / ink;
430 output[3] = ink_limit * output[3] / ink;
431 }
432 }
433
434 output += 4;
435 num_pixels --;
436 }
437 break;
438
439 case 6 : /* CcMmYK */
440 while (num_pixels > 0)
441 {
442 /*
443 * Get the input black value and then set the corresponding color
444 * channel values...
445 */
446
447 c = *input++;
448 m = *input++;
449 y = *input++;
450 k = *input++;
451
452 output[0] = channels[0][c];
453 output[1] = channels[1][c];
454 output[2] = channels[2][m];
455 output[3] = channels[3][m];
456 output[4] = channels[4][y];
457 output[5] = channels[5][k];
458
459 if (ink_limit)
460 {
461 ink = output[0] + output[1] + output[2] + output[3] +
462 output[4] + output[5];
463
464 if (ink > ink_limit)
465 {
466 output[0] = ink_limit * output[0] / ink;
467 output[1] = ink_limit * output[1] / ink;
468 output[2] = ink_limit * output[2] / ink;
469 output[3] = ink_limit * output[3] / ink;
470 output[4] = ink_limit * output[4] / ink;
471 output[5] = ink_limit * output[5] / ink;
472 }
473 }
474
475 output += 6;
476 num_pixels --;
477 }
478 break;
479
480 case 7 : /* CcMmYKk */
481 while (num_pixels > 0)
482 {
483 /*
484 * Get the input black value and then set the corresponding color
485 * channel values...
486 */
487
488 c = *input++;
489 m = *input++;
490 y = *input++;
491 k = *input++;
492
493 output[0] = channels[0][c];
494 output[1] = channels[1][c];
495 output[2] = channels[2][m];
496 output[3] = channels[3][m];
497 output[4] = channels[4][y];
498 output[5] = channels[5][k];
499 output[6] = channels[6][k];
500
501 if (ink_limit)
502 {
503 ink = output[0] + output[1] + output[2] + output[3] +
504 output[4] + output[5] + output[6];
505
506 if (ink > ink_limit)
507 {
508 output[0] = ink_limit * output[0] / ink;
509 output[1] = ink_limit * output[1] / ink;
510 output[2] = ink_limit * output[2] / ink;
511 output[3] = ink_limit * output[3] / ink;
512 output[4] = ink_limit * output[4] / ink;
513 output[5] = ink_limit * output[5] / ink;
514 output[6] = ink_limit * output[6] / ink;
515 }
516 }
517
518 output += 7;
519 num_pixels --;
520 }
521 break;
522 }
523}
524
525
526/*
527 * 'cupsCMYKDoGray()' - Do a grayscale separation...
528 */
529
530void
531cupsCMYKDoGray(const cups_cmyk_t *cmyk,
532 /* I - Color separation */
533 const unsigned char *input,
534 /* I - Input grayscale pixels */
535 short *output,
536 /* O - Output Device-N pixels */
537 int num_pixels)
538 /* I - Number of pixels */
539{
540 int k, /* Current black value */
541 kc; /* Current black color value */
542 const short **channels; /* Copy of channel LUTs */
543 const unsigned char *black_lut, /* Black LUT */
544 *color_lut; /* Color LUT */
545 int ink, /* Amount of ink */
546 ink_limit; /* Ink limit from separation */
547
548
549 /*
550 * Range check input...
551 */
552
553 if (cmyk == NULL || input == NULL || output == NULL || num_pixels <= 0)
554 return;
555
556 /*
557 * Loop through it all...
558 */
559
560 channels = (const short **)cmyk->channels;
561 black_lut = cmyk->black_lut;
562 color_lut = cmyk->color_lut;
563 ink_limit = cmyk->ink_limit;
564
565 switch (cmyk->num_channels)
566 {
567 case 1 : /* Black */
568 while (num_pixels > 0)
569 {
570 /*
571 * Get the input black value and then set the corresponding color
572 * channel values...
573 */
574
575 k = cups_scmy_lut[*input++];
576 *output++ = channels[0][k];
577
578 num_pixels --;
579 }
580 break;
581
582 case 2 : /* Black, light black */
583 while (num_pixels > 0)
584 {
585 /*
586 * Get the input black value and then set the corresponding color
587 * channel values...
588 */
589
590 k = cups_scmy_lut[*input++];
591 output[0] = channels[0][k];
592 output[1] = channels[1][k];
593
594 if (ink_limit)
595 {
596 ink = output[0] + output[1];
597
598 if (ink > ink_limit)
599 {
600 output[0] = ink_limit * output[0] / ink;
601 output[1] = ink_limit * output[1] / ink;
602 }
603 }
604
605 output += 2;
606 num_pixels --;
607 }
608 break;
609
610 case 3 : /* CMY */
611 while (num_pixels > 0)
612 {
613 /*
614 * Get the input black value and then set the corresponding color
615 * channel values...
616 */
617
618 k = cups_scmy_lut[*input++];
619 output[0] = channels[0][k];
620 output[1] = channels[1][k];
621 output[2] = channels[2][k];
622
623 if (ink_limit)
624 {
625 ink = output[0] + output[1] + output[2];
626
627 if (ink > ink_limit)
628 {
629 output[0] = ink_limit * output[0] / ink;
630 output[1] = ink_limit * output[1] / ink;
631 output[2] = ink_limit * output[2] / ink;
632 }
633 }
634
635 output += 3;
636 num_pixels --;
637 }
638 break;
639
640 case 4 : /* CMYK */
641 while (num_pixels > 0)
642 {
643 /*
644 * Get the input black value and then set the corresponding color
645 * channel values...
646 */
647
648 k = cups_scmy_lut[*input++];
649 kc = cmyk->color_lut[k];
650 k = cmyk->black_lut[k];
651 output[0] = channels[0][kc];
652 output[1] = channels[1][kc];
653 output[2] = channels[2][kc];
654 output[3] = channels[3][k];
655
656 if (ink_limit)
657 {
658 ink = output[0] + output[1] + output[2] + output[3];
659
660 if (ink > ink_limit)
661 {
662 output[0] = ink_limit * output[0] / ink;
663 output[1] = ink_limit * output[1] / ink;
664 output[2] = ink_limit * output[2] / ink;
665 output[3] = ink_limit * output[3] / ink;
666 }
667 }
668
669 output += 4;
670 num_pixels --;
671 }
672 break;
673
674 case 6 : /* CcMmYK */
675 while (num_pixels > 0)
676 {
677 /*
678 * Get the input black value and then set the corresponding color
679 * channel values...
680 */
681
682 k = cups_scmy_lut[*input++];
683 kc = cmyk->color_lut[k];
684 k = cmyk->black_lut[k];
685 output[0] = channels[0][kc];
686 output[1] = channels[1][kc];
687 output[2] = channels[2][kc];
688 output[3] = channels[3][kc];
689 output[4] = channels[4][kc];
690 output[5] = channels[5][k];
691
692 if (ink_limit)
693 {
694 ink = output[0] + output[1] + output[2] + output[3] +
695 output[4] + output[5];
696
697 if (ink > ink_limit)
698 {
699 output[0] = ink_limit * output[0] / ink;
700 output[1] = ink_limit * output[1] / ink;
701 output[2] = ink_limit * output[2] / ink;
702 output[3] = ink_limit * output[3] / ink;
703 output[4] = ink_limit * output[4] / ink;
704 output[5] = ink_limit * output[5] / ink;
705 }
706 }
707
708 output += 6;
709 num_pixels --;
710 }
711 break;
712
713 case 7 : /* CcMmYKk */
714 while (num_pixels > 0)
715 {
716 /*
717 * Get the input black value and then set the corresponding color
718 * channel values...
719 */
720
721 k = cups_scmy_lut[*input++];
722 kc = cmyk->color_lut[k];
723 k = cmyk->black_lut[k];
724 output[0] = channels[0][kc];
725 output[1] = channels[1][kc];
726 output[2] = channels[2][kc];
727 output[3] = channels[3][kc];
728 output[4] = channels[4][kc];
729 output[5] = channels[5][k];
730 output[6] = channels[6][k];
731
732 if (ink_limit)
733 {
734 ink = output[0] + output[1] + output[2] + output[3] +
735 output[4] + output[5] + output[6];
736
737 if (ink > ink_limit)
738 {
739 output[0] = ink_limit * output[0] / ink;
740 output[1] = ink_limit * output[1] / ink;
741 output[2] = ink_limit * output[2] / ink;
742 output[3] = ink_limit * output[3] / ink;
743 output[4] = ink_limit * output[4] / ink;
744 output[5] = ink_limit * output[5] / ink;
745 output[6] = ink_limit * output[6] / ink;
746 }
747 }
748
749 output += 7;
750 num_pixels --;
751 }
752 break;
753 }
754}
755
756
757/*
758 * 'cupsCMYKDoRGB()' - Do an sRGB separation...
759 */
760
761void
762cupsCMYKDoRGB(const cups_cmyk_t *cmyk,
763 /* I - Color separation */
764 const unsigned char *input,
765 /* I - Input grayscale pixels */
766 short *output,
767 /* O - Output Device-N pixels */
768 int num_pixels)
769 /* I - Number of pixels */
770{
771 int c, /* Current cyan value */
772 m, /* Current magenta value */
773 y, /* Current yellow value */
774 k, /* Current black value */
775 kc, /* Current black color value */
776 km; /* Maximum black value */
777 const short **channels; /* Copy of channel LUTs */
778 const unsigned char *black_lut, /* Black LUT */
779 *color_lut; /* Color LUT */
780 int ink, /* Amount of ink */
781 ink_limit; /* Ink limit from separation */
782
783
784 /*
785 * Range check input...
786 */
787
788 if (cmyk == NULL || input == NULL || output == NULL || num_pixels <= 0)
789 return;
790
791 /*
792 * Loop through it all...
793 */
794
795 channels = (const short **)cmyk->channels;
796 black_lut = cmyk->black_lut;
797 color_lut = cmyk->color_lut;
798 ink_limit = cmyk->ink_limit;
799
800 switch (cmyk->num_channels)
801 {
802 case 1 : /* Black */
803 while (num_pixels > 0)
804 {
805 /*
806 * Get the input black value and then set the corresponding color
807 * channel values...
808 */
809
810 c = cups_scmy_lut[*input++];
811 m = cups_scmy_lut[*input++];
812 y = cups_scmy_lut[*input++];
813 k = (c * 31 + m * 61 + y * 8) / 100;
814
815 *output++ = channels[0][k];
816
817 num_pixels --;
818 }
819 break;
820
821 case 2 : /* Black, light black */
822 while (num_pixels > 0)
823 {
824 /*
825 * Get the input black value and then set the corresponding color
826 * channel values...
827 */
828
829 c = cups_scmy_lut[*input++];
830 m = cups_scmy_lut[*input++];
831 y = cups_scmy_lut[*input++];
832 k = (c * 31 + m * 61 + y * 8) / 100;
833
834 output[0] = channels[0][k];
835 output[1] = channels[1][k];
836
837 if (ink_limit)
838 {
839 ink = output[0] + output[1];
840
841 if (ink > ink_limit)
842 {
843 output[0] = ink_limit * output[0] / ink;
844 output[1] = ink_limit * output[1] / ink;
845 }
846 }
847
848 output += 2;
849 num_pixels --;
850 }
851 break;
852
853 case 3 : /* CMY */
854 while (num_pixels > 0)
855 {
856 /*
857 * Get the input black value and then set the corresponding color
858 * channel values...
859 */
860
861 c = cups_scmy_lut[*input++];
862 m = cups_scmy_lut[*input++];
863 y = cups_scmy_lut[*input++];
864
865 output[0] = channels[0][c];
866 output[1] = channels[1][m];
867 output[2] = channels[2][y];
868
869 if (ink_limit)
870 {
871 ink = output[0] + output[1] + output[2];
872
873 if (ink > ink_limit)
874 {
875 output[0] = ink_limit * output[0] / ink;
876 output[1] = ink_limit * output[1] / ink;
877 output[2] = ink_limit * output[2] / ink;
878 }
879 }
880
881 output += 3;
882 num_pixels --;
883 }
884 break;
885
886 case 4 : /* CMYK */
887 while (num_pixels > 0)
888 {
889 /*
890 * Get the input black value and then set the corresponding color
891 * channel values...
892 */
893
894 c = cups_scmy_lut[*input++];
895 m = cups_scmy_lut[*input++];
896 y = cups_scmy_lut[*input++];
897 k = min(c, min(m, y));
898
899 if ((km = max(c, max(m, y))) > k)
900 k = k * k * k / (km * km);
901
902 kc = cmyk->color_lut[k] - k;
903 k = cmyk->black_lut[k];
904 c += kc;
905 m += kc;
906 y += kc;
907
908 output[0] = channels[0][c];
909 output[1] = channels[1][m];
910 output[2] = channels[2][y];
911 output[3] = channels[3][k];
912
913 if (ink_limit)
914 {
915 ink = output[0] + output[1] + output[2] + output[3];
916
917 if (ink > ink_limit)
918 {
919 output[0] = ink_limit * output[0] / ink;
920 output[1] = ink_limit * output[1] / ink;
921 output[2] = ink_limit * output[2] / ink;
922 output[3] = ink_limit * output[3] / ink;
923 }
924 }
925
926 output += 4;
927 num_pixels --;
928 }
929 break;
930
931 case 6 : /* CcMmYK */
932 while (num_pixels > 0)
933 {
934 /*
935 * Get the input black value and then set the corresponding color
936 * channel values...
937 */
938
939 c = cups_scmy_lut[*input++];
940 m = cups_scmy_lut[*input++];
941 y = cups_scmy_lut[*input++];
942 k = min(c, min(m, y));
943
944 if ((km = max(c, max(m, y))) > k)
945 k = k * k * k / (km * km);
946
947 kc = cmyk->color_lut[k] - k;
948 k = cmyk->black_lut[k];
949 c += kc;
950 m += kc;
951 y += kc;
952
953 output[0] = channels[0][c];
954 output[1] = channels[1][c];
955 output[2] = channels[2][m];
956 output[3] = channels[3][m];
957 output[4] = channels[4][y];
958 output[5] = channels[5][k];
959
960 if (ink_limit)
961 {
962 ink = output[0] + output[1] + output[2] + output[3] +
963 output[4] + output[5];
964
965 if (ink > ink_limit)
966 {
967 output[0] = ink_limit * output[0] / ink;
968 output[1] = ink_limit * output[1] / ink;
969 output[2] = ink_limit * output[2] / ink;
970 output[3] = ink_limit * output[3] / ink;
971 output[4] = ink_limit * output[4] / ink;
972 output[5] = ink_limit * output[5] / ink;
973 }
974 }
975
976 output += 6;
977 num_pixels --;
978 }
979 break;
980
981 case 7 : /* CcMmYKk */
982 while (num_pixels > 0)
983 {
984 /*
985 * Get the input black value and then set the corresponding color
986 * channel values...
987 */
988
989 c = cups_scmy_lut[*input++];
990 m = cups_scmy_lut[*input++];
991 y = cups_scmy_lut[*input++];
992 k = min(c, min(m, y));
993
994 if ((km = max(c, max(m, y))) > k)
995 k = k * k * k / (km * km);
996
997 kc = cmyk->color_lut[k] - k;
998 k = cmyk->black_lut[k];
999 c += kc;
1000 m += kc;
1001 y += kc;
1002
1003 output[0] = channels[0][c];
1004 output[1] = channels[1][c];
1005 output[2] = channels[2][m];
1006 output[3] = channels[3][m];
1007 output[4] = channels[4][y];
1008 output[5] = channels[5][k];
1009 output[6] = channels[6][k];
1010
1011 if (ink_limit)
1012 {
1013 ink = output[0] + output[1] + output[2] + output[3] +
1014 output[4] + output[5] + output[6];
1015
1016 if (ink > ink_limit)
1017 {
1018 output[0] = ink_limit * output[0] / ink;
1019 output[1] = ink_limit * output[1] / ink;
1020 output[2] = ink_limit * output[2] / ink;
1021 output[3] = ink_limit * output[3] / ink;
1022 output[4] = ink_limit * output[4] / ink;
1023 output[5] = ink_limit * output[5] / ink;
1024 output[6] = ink_limit * output[6] / ink;
1025 }
1026 }
1027
1028 output += 7;
1029 num_pixels --;
1030 }
1031 break;
1032 }
1033}
1034
1035
1036/*
1037 * 'cupsCMYKLoad()' - Load a CMYK color profile from PPD attributes.
1038 */
1039
1040cups_cmyk_t * /* O - CMYK color separation */
1041cupsCMYKLoad(ppd_file_t *ppd, /* I - PPD file */
1042 const char *colormodel, /* I - ColorModel value */
1043 const char *media, /* I - MediaType value */
1044 const char *resolution) /* I - Resolution value */
1045{
1046 cups_cmyk_t *cmyk; /* CMYK color separation */
1047 char spec[PPD_MAX_NAME]; /* Profile name */
1048 ppd_attr_t *attr; /* Attribute from PPD file */
1049 int num_channels; /* Number of color components */
1050 float gamval, /* Gamma correction value */
1051 density, /* Density value */
1052 light, /* Light ink limit */
1053 dark, /* Light ink cut-off */
1054 lower, /* Start of black ink */
1055 upper; /* End of color ink */
1056 int num_xypoints; /* Number of X,Y points */
1057 float xypoints[100 * 2], /* X,Y points */
1058 *xyptr; /* Current X,Y point */
1059
1060
1061 /*
1062 * Range check input...
1063 */
1064
1065 if (ppd == NULL || colormodel == NULL || resolution == NULL || media == NULL)
1066 return (NULL);
1067
1068 /*
1069 * Find the following attributes:
1070 *
1071 * cupsAllGamma - Set default curve using gamma + density
1072 * cupsAllXY - Set default curve using XY points
1073 * cupsBlackGamma - Set black curve using gamma + density
1074 * cupsBlackGeneration - Set black generation
1075 * cupsBlackLightDark - Set black light/dark transition
1076 * cupsBlackXY - Set black curve using XY points
1077 * cupsCyanGamma - Set cyan curve using gamma + density
1078 * cupsCyanLightDark - Set cyan light/dark transition
1079 * cupsCyanXY - Set cyan curve using XY points
1080 * cupsInkChannels - Set number of color channels
1081 * cupsInkLimit - Set total ink limit
1082 * cupsLightBlackGamma - Set light black curve using gamma + density
1083 * cupsLightBlackXY - Set light black curve using XY points
1084 * cupsLightCyanGamma - Set light cyan curve using gamma + density
1085 * cupsLightCyanXY - Set light cyan curve using XY points
1086 * cupsLightMagentaGamma - Set light magenta curve using gamma + density
1087 * cupsLightMagentaXY - Set light magenta curve using XY points
1088 * cupsMagentaGamma - Set magenta curve using gamma + density
1089 * cupsMagentaLightDark - Set magenta light/dark transition
1090 * cupsMagentaXY - Set magenta curve using XY points
1091 * cupsYellowGamma - Set yellow curve using gamma + density
1092 * cupsYellowXY - Set yellow curve using XY points
1093 *
1094 * The only required attribute is cupsInkChannels.
1095 *
1096 * The *XY attributes have precedence over the *Gamma attributes, and
1097 * the *Light* attributes have precedence over the corresponding
1098 * *LightDark* attributes.
1099 */
1100
1101 /*
1102 * Get the required cupsInkChannels attribute...
1103 */
1104
1105 if ((attr = cupsFindAttr(ppd, "cupsInkChannels", colormodel, media,
1106 resolution, spec, sizeof(spec))) == NULL)
1107 return (NULL);
1108
1109 num_channels = atoi(attr->value);
1110
1111 if (num_channels < 1 || num_channels > 7 || num_channels == 5)
1112 return (NULL);
1113
1114 if ((cmyk = cupsCMYKNew(num_channels)) == NULL)
1115 return (NULL);
1116
1117 /*
1118 * Get the optional cupsInkLimit attribute...
1119 */
1120
1121 if ((attr = cupsFindAttr(ppd, "cupsInkLimit", colormodel, media,
1122 resolution, spec, sizeof(spec))) != NULL)
1123 cupsCMYKSetInkLimit(cmyk, atof(attr->value));
1124
1125 /*
1126 * Get the optional cupsBlackGeneration attribute...
1127 */
1128
1129 if ((attr = cupsFindAttr(ppd, "cupsBlackGeneration", colormodel, media,
1130 resolution, spec, sizeof(spec))) != NULL)
1131 {
1132 if (sscanf(attr->value, "%f%f", &lower, &upper) == 2)
1133 cupsCMYKSetBlack(cmyk, lower, upper);
1134 }
1135
1136 /*
1137 * Get the optional cupsBlackXY or cupsBlackGamma attributes...
1138 */
1139
1140 if (num_channels != 3)
1141 {
1142 if ((attr = cupsFindAttr(ppd, "cupsBlackXY", colormodel, media,
1143 resolution, spec, sizeof(spec))) != NULL)
1144 {
1145 for (num_xypoints = 0, xyptr = xypoints;
1146 attr != NULL && attr->value != NULL && num_xypoints < 100;
1147 attr = ppdFindNextAttr(ppd, "cupsBlackXY", spec))
1148 if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
1149 {
1150 num_xypoints ++;
1151 xyptr += 2;
1152 }
1153
1154 switch (num_channels)
1155 {
1156 case 1 :
1157 case 2 :
1158 cupsCMYKSetCurve(cmyk, 0, num_xypoints, xypoints);
1159 break;
1160 case 4 :
1161 cupsCMYKSetCurve(cmyk, 3, num_xypoints, xypoints);
1162 break;
1163 case 6 :
1164 case 7 :
1165 cupsCMYKSetCurve(cmyk, 5, num_xypoints, xypoints);
1166 break;
1167 }
1168 }
1169 else if ((attr = cupsFindAttr(ppd, "cupsBlackGamma", colormodel,
1170 media, resolution, spec,
1171 sizeof(spec))) != NULL)
1172 {
1173 if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
1174 switch (num_channels)
1175 {
1176 case 1 :
1177 case 2 :
1178 cupsCMYKSetGamma(cmyk, 0, gamval, density);
1179 break;
1180 case 4 :
1181 cupsCMYKSetGamma(cmyk, 3, gamval, density);
1182 break;
1183 case 6 :
1184 case 7 :
1185 cupsCMYKSetGamma(cmyk, 5, gamval, density);
1186 break;
1187 }
1188 }
1189 else if ((attr = cupsFindAttr(ppd, "cupsAllXY", colormodel, media,
1190 resolution, spec, sizeof(spec))) != NULL)
1191 {
1192 for (num_xypoints = 0, xyptr = xypoints;
1193 attr != NULL && attr->value != NULL && num_xypoints < 100;
1194 attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
1195 if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
1196 {
1197 num_xypoints ++;
1198 xyptr += 2;
1199 }
1200
1201 switch (num_channels)
1202 {
1203 case 1 :
1204 case 2 :
1205 cupsCMYKSetCurve(cmyk, 0, num_xypoints, xypoints);
1206 break;
1207 case 4 :
1208 cupsCMYKSetCurve(cmyk, 3, num_xypoints, xypoints);
1209 break;
1210 case 6 :
1211 case 7 :
1212 cupsCMYKSetCurve(cmyk, 5, num_xypoints, xypoints);
1213 break;
1214 }
1215 }
1216 else if ((attr = cupsFindAttr(ppd, "cupsAllGamma", colormodel,
1217 media, resolution, spec,
1218 sizeof(spec))) != NULL &&
1219 num_channels != 3)
1220 {
1221 if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
1222 switch (num_channels)
1223 {
1224 case 1 :
1225 case 2 :
1226 cupsCMYKSetGamma(cmyk, 0, gamval, density);
1227 break;
1228 case 4 :
1229 cupsCMYKSetGamma(cmyk, 3, gamval, density);
1230 break;
1231 case 6 :
1232 case 7 :
1233 cupsCMYKSetGamma(cmyk, 5, gamval, density);
1234 break;
1235 }
1236 }
1237 }
1238
1239 if (num_channels > 2)
1240 {
1241 /*
1242 * Get the optional cupsCyanXY or cupsCyanGamma attributes...
1243 */
1244
1245 if ((attr = cupsFindAttr(ppd, "cupsCyanXY", colormodel, media,
1246 resolution, spec, sizeof(spec))) != NULL)
1247 {
1248 for (num_xypoints = 0, xyptr = xypoints;
1249 attr != NULL && attr->value != NULL && num_xypoints < 100;
1250 attr = ppdFindNextAttr(ppd, "cupsCyanXY", spec))
1251 if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
1252 {
1253 num_xypoints ++;
1254 xyptr += 2;
1255 }
1256
1257 cupsCMYKSetCurve(cmyk, 0, num_xypoints, xypoints);
1258 }
1259 else if ((attr = cupsFindAttr(ppd, "cupsCyanGamma", colormodel, media,
1260 resolution, spec, sizeof(spec))) != NULL)
1261 {
1262 if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
1263 cupsCMYKSetGamma(cmyk, 0, gamval, density);
1264 }
1265 else if ((attr = cupsFindAttr(ppd, "cupsAllXY", colormodel, media,
1266 resolution, spec, sizeof(spec))) != NULL)
1267 {
1268 for (num_xypoints = 0, xyptr = xypoints;
1269 attr != NULL && attr->value != NULL && num_xypoints < 100;
1270 attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
1271 if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
1272 {
1273 num_xypoints ++;
1274 xyptr += 2;
1275 }
1276
1277 cupsCMYKSetCurve(cmyk, 0, num_xypoints, xypoints);
1278 }
1279 else if ((attr = cupsFindAttr(ppd, "cupsAllGamma", colormodel, media,
1280 resolution, spec, sizeof(spec))) != NULL)
1281 {
1282 if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
1283 cupsCMYKSetGamma(cmyk, 0, gamval, density);
1284 }
1285
1286 /*
1287 * Get the optional cupsMagentaXY or cupsMagentaGamma attributes...
1288 */
1289
1290 if ((attr = cupsFindAttr(ppd, "cupsMagentaXY", colormodel, media,
1291 resolution, spec, sizeof(spec))) != NULL)
1292 {
1293 for (num_xypoints = 0, xyptr = xypoints;
1294 attr != NULL && attr->value != NULL && num_xypoints < 100;
1295 attr = ppdFindNextAttr(ppd, "cupsMagentaXY", spec))
1296 if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
1297 {
1298 num_xypoints ++;
1299 xyptr += 2;
1300 }
1301
1302 switch (num_channels)
1303 {
1304 case 3 :
1305 case 4 :
1306 cupsCMYKSetCurve(cmyk, 1, num_xypoints, xypoints);
1307 break;
1308 case 6 :
1309 case 7 :
1310 cupsCMYKSetCurve(cmyk, 2, num_xypoints, xypoints);
1311 break;
1312 }
1313 }
1314 else if ((attr = cupsFindAttr(ppd, "cupsMagentaGamma", colormodel, media,
1315 resolution, spec, sizeof(spec))) != NULL)
1316 {
1317 if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
1318 switch (num_channels)
1319 {
1320 case 3 :
1321 case 4 :
1322 cupsCMYKSetGamma(cmyk, 1, gamval, density);
1323 break;
1324 case 6 :
1325 case 7 :
1326 cupsCMYKSetGamma(cmyk, 2, gamval, density);
1327 break;
1328 }
1329 }
1330 else if ((attr = cupsFindAttr(ppd, "cupsAllXY", colormodel, media,
1331 resolution, spec, sizeof(spec))) != NULL)
1332 {
1333 for (num_xypoints = 0, xyptr = xypoints;
1334 attr != NULL && attr->value != NULL && num_xypoints < 100;
1335 attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
1336 if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
1337 {
1338 num_xypoints ++;
1339 xyptr += 2;
1340 }
1341
1342 switch (num_channels)
1343 {
1344 case 3 :
1345 case 4 :
1346 cupsCMYKSetCurve(cmyk, 1, num_xypoints, xypoints);
1347 break;
1348 case 6 :
1349 case 7 :
1350 cupsCMYKSetCurve(cmyk, 2, num_xypoints, xypoints);
1351 break;
1352 }
1353 }
1354 else if ((attr = cupsFindAttr(ppd, "cupsAllGamma", colormodel, media,
1355 resolution, spec, sizeof(spec))) != NULL)
1356 {
1357 if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
1358 switch (num_channels)
1359 {
1360 case 3 :
1361 case 4 :
1362 cupsCMYKSetGamma(cmyk, 1, gamval, density);
1363 break;
1364 case 6 :
1365 case 7 :
1366 cupsCMYKSetGamma(cmyk, 2, gamval, density);
1367 break;
1368 }
1369 }
1370
1371 /*
1372 * Get the optional cupsYellowXY or cupsYellowGamma attributes...
1373 */
1374
1375 if ((attr = cupsFindAttr(ppd, "cupsYellowXY", colormodel, media,
1376 resolution, spec, sizeof(spec))) != NULL)
1377 {
1378 for (num_xypoints = 0, xyptr = xypoints;
1379 attr != NULL && attr->value != NULL && num_xypoints < 100;
1380 attr = ppdFindNextAttr(ppd, "cupsYellowXY", spec))
1381 if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
1382 {
1383 num_xypoints ++;
1384 xyptr += 2;
1385 }
1386
1387 switch (num_channels)
1388 {
1389 case 3 :
1390 case 4 :
1391 cupsCMYKSetCurve(cmyk, 2, num_xypoints, xypoints);
1392 break;
1393 case 6 :
1394 case 7 :
1395 cupsCMYKSetCurve(cmyk, 4, num_xypoints, xypoints);
1396 break;
1397 }
1398 }
1399 else if ((attr = cupsFindAttr(ppd, "cupsYellowGamma", colormodel, media,
1400 resolution, spec, sizeof(spec))) != NULL)
1401 {
1402 if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
1403 switch (num_channels)
1404 {
1405 case 3 :
1406 case 4 :
1407 cupsCMYKSetGamma(cmyk, 2, gamval, density);
1408 break;
1409 case 6 :
1410 case 7 :
1411 cupsCMYKSetGamma(cmyk, 4, gamval, density);
1412 break;
1413 }
1414 }
1415 else if ((attr = cupsFindAttr(ppd, "cupsAllXY", colormodel, media,
1416 resolution, spec, sizeof(spec))) != NULL)
1417 {
1418 for (num_xypoints = 0, xyptr = xypoints;
1419 attr != NULL && attr->value != NULL && num_xypoints < 100;
1420 attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
1421 if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
1422 {
1423 num_xypoints ++;
1424 xyptr += 2;
1425 }
1426
1427 switch (num_channels)
1428 {
1429 case 3 :
1430 case 4 :
1431 cupsCMYKSetCurve(cmyk, 2, num_xypoints, xypoints);
1432 break;
1433 case 6 :
1434 case 7 :
1435 cupsCMYKSetCurve(cmyk, 4, num_xypoints, xypoints);
1436 break;
1437 }
1438 }
1439 else if ((attr = cupsFindAttr(ppd, "cupsAllGamma", colormodel, media,
1440 resolution, spec, sizeof(spec))) != NULL)
1441 {
1442 if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
1443 switch (num_channels)
1444 {
1445 case 3 :
1446 case 4 :
1447 cupsCMYKSetGamma(cmyk, 2, gamval, density);
1448 break;
1449 case 6 :
1450 case 7 :
1451 cupsCMYKSetGamma(cmyk, 4, gamval, density);
1452 break;
1453 }
1454 }
1455 }
1456
1457 /*
1458 * Get the optional cupsLightBlackXY, cupsLightBlackGamma, or
1459 * cupsBlackLtDk attributes...
1460 */
1461
1462 if (num_channels == 2 || num_channels == 7)
1463 {
1464 if ((attr = cupsFindAttr(ppd, "cupsLightBlackXY", colormodel, media,
1465 resolution, spec, sizeof(spec))) != NULL)
1466 {
1467 for (num_xypoints = 0, xyptr = xypoints;
1468 attr != NULL && attr->value != NULL && num_xypoints < 100;
1469 attr = ppdFindNextAttr(ppd, "cupsLightBlackXY", spec))
1470 if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
1471 {
1472 num_xypoints ++;
1473 xyptr += 2;
1474 }
1475
1476 switch (num_channels)
1477 {
1478 case 2 :
1479 cupsCMYKSetCurve(cmyk, 1, num_xypoints, xypoints);
1480 break;
1481 case 7 :
1482 cupsCMYKSetCurve(cmyk, 6, num_xypoints, xypoints);
1483 break;
1484 }
1485 }
1486 else if ((attr = cupsFindAttr(ppd, "cupsLightBlackGamma", colormodel,
1487 media, resolution, spec,
1488 sizeof(spec))) != NULL)
1489 {
1490 if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
1491 switch (num_channels)
1492 {
1493 case 2 :
1494 cupsCMYKSetGamma(cmyk, 1, gamval, density);
1495 break;
1496 case 7 :
1497 cupsCMYKSetGamma(cmyk, 6, gamval, density);
1498 break;
1499 }
1500 }
1501 else if ((attr = cupsFindAttr(ppd, "cupsBlackLtDk", colormodel, media,
1502 resolution, spec, sizeof(spec))) != NULL)
1503 {
1504 if (sscanf(attr->value, "%f%f", &light, &dark) == 2)
1505 switch (num_channels)
1506 {
1507 case 2 :
1508 cupsCMYKSetLtDk(cmyk, 0, light, dark);
1509 break;
1510 case 7 :
1511 cupsCMYKSetLtDk(cmyk, 5, light, dark);
1512 break;
1513 }
1514 else
1515 fprintf(stderr, "ERROR: Bad cupsBlackLtDk value \"%s\"!\n",
1516 attr->value);
1517 }
1518 else
1519 fprintf(stderr, "WARNING: No light black attribute found for %s!\n",
1520 spec);
1521 }
1522
1523 if (num_channels >= 6)
1524 {
1525 /*
1526 * Get the optional cupsLightCyanXY, cupsLightCyanGamma, or
1527 * cupsCyanLtDk attributes...
1528 */
1529
1530 if ((attr = cupsFindAttr(ppd, "cupsLightCyanXY", colormodel, media,
1531 resolution, spec, sizeof(spec))) != NULL)
1532 {
1533 for (num_xypoints = 0, xyptr = xypoints;
1534 attr != NULL && attr->value != NULL && num_xypoints < 100;
1535 attr = ppdFindNextAttr(ppd, "cupsLightCyanXY", spec))
1536 if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
1537 {
1538 num_xypoints ++;
1539 xyptr += 2;
1540 }
1541
1542 cupsCMYKSetCurve(cmyk, 1, num_xypoints, xypoints);
1543 }
1544 else if ((attr = cupsFindAttr(ppd, "cupsLightCyanGamma", colormodel,
1545 media, resolution, spec,
1546 sizeof(spec))) != NULL)
1547 {
1548 if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
1549 cupsCMYKSetGamma(cmyk, 1, gamval, density);
1550 }
1551 else if ((attr = cupsFindAttr(ppd, "cupsCyanLtDk", colormodel, media,
1552 resolution, spec, sizeof(spec))) != NULL)
1553 {
1554 if (sscanf(attr->value, "%f%f", &light, &dark) == 2)
1555 cupsCMYKSetLtDk(cmyk, 0, light, dark);
1556 else
1557 fprintf(stderr, "ERROR: Bad cupsCyanLtDk value \"%s\"!\n",
1558 attr->value);
1559 }
1560 else
1561 fprintf(stderr, "WARNING: No light cyan attribute found for %s!\n",
1562 spec);
1563
1564 /*
1565 * Get the optional cupsLightMagentaXY, cupsLightMagentaGamma, or
1566 * cupsMagentaLtDk attributes...
1567 */
1568
1569 if ((attr = cupsFindAttr(ppd, "cupsLightMagentaXY", colormodel, media,
1570 resolution, spec, sizeof(spec))) != NULL)
1571 {
1572 for (num_xypoints = 0, xyptr = xypoints;
1573 attr != NULL && attr->value != NULL && num_xypoints < 100;
1574 attr = ppdFindNextAttr(ppd, "cupsLightMagentaXY", spec))
1575 if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
1576 {
1577 num_xypoints ++;
1578 xyptr += 2;
1579 }
1580
1581 cupsCMYKSetCurve(cmyk, 3, num_xypoints, xypoints);
1582 }
1583 else if ((attr = cupsFindAttr(ppd, "cupsLightMagentaGamma", colormodel,
1584 media, resolution, spec,
1585 sizeof(spec))) != NULL)
1586 {
1587 if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
1588 cupsCMYKSetGamma(cmyk, 3, gamval, density);
1589 }
1590 else if ((attr = cupsFindAttr(ppd, "cupsMagentaLtDk", colormodel, media,
1591 resolution, spec, sizeof(spec))) != NULL)
1592 {
1593 if (sscanf(attr->value, "%f%f", &light, &dark) == 2)
1594 cupsCMYKSetLtDk(cmyk, 2, light, dark);
1595 else
1596 fprintf(stderr, "ERROR: Bad cupsMagentaLtDk value \"%s\"!\n",
1597 attr->value);
1598 }
1599 else
1600 fprintf(stderr, "WARNING: No light magenta attribute found for %s!\n",
1601 spec);
1602 }
1603
1604 /*
1605 * Return the new profile...
1606 */
1607
1608 return (cmyk);
1609}
1610
1611
1612/*
1613 * 'cupsCMYKNew()' - Create a new CMYK color separation.
1614 */
1615
1616cups_cmyk_t * /* O - New CMYK separation or NULL */
1617cupsCMYKNew(int num_channels) /* I - Number of color components */
1618{
1619 cups_cmyk_t *cmyk; /* New color separation */
1620 int i; /* Looping var */
1621
1622
1623 /*
1624 * Range-check the input...
1625 */
1626
1627 if (num_channels < 1)
1628 return (NULL);
1629
1630 /*
1631 * Allocate memory for the separation...
1632 */
1633
1634 if ((cmyk = calloc(1, sizeof(cups_cmyk_t))) == NULL)
1635 return (NULL);
1636
1637 /*
1638 * Allocate memory for the LUTs...
1639 */
1640
1641 cmyk->num_channels = num_channels;
1642
1643 if ((cmyk->channels[0] = calloc(num_channels * 256, sizeof(short))) == NULL)
1644 {
1645 free(cmyk);
1646 return (NULL);
1647 }
1648
1649 for (i = 1; i < num_channels; i ++)
1650 cmyk->channels[i] = cmyk->channels[0] + i * 256;
1651
1652 /*
1653 * Fill in the LUTs with unity transitions...
1654 */
1655
1656 for (i = 0; i < 256; i ++)
1657 cmyk->black_lut[i] = i;
1658
1659 switch (num_channels)
1660 {
1661 case 1 : /* K */
1662 case 2 : /* Kk */
1663 for (i = 0; i < 256; i ++)
1664 {
1665 cmyk->channels[0][i] = CUPS_MAX_LUT * i / 255;
1666 }
1667 break;
1668 case 3 : /* CMY */
1669 for (i = 0; i < 256; i ++)
1670 {
1671 cmyk->channels[0][i] = CUPS_MAX_LUT * i / 255;
1672 cmyk->channels[1][i] = CUPS_MAX_LUT * i / 255;
1673 cmyk->channels[2][i] = CUPS_MAX_LUT * i / 255;
1674 }
1675 break;
1676 case 4 : /* CMYK */
1677 for (i = 0; i < 256; i ++)
1678 {
1679 cmyk->channels[0][i] = CUPS_MAX_LUT * i / 255;
1680 cmyk->channels[1][i] = CUPS_MAX_LUT * i / 255;
1681 cmyk->channels[2][i] = CUPS_MAX_LUT * i / 255;
1682 cmyk->channels[3][i] = CUPS_MAX_LUT * i / 255;
1683 }
1684 break;
1685 case 6 : /* CcMmYK */
1686 case 7 : /* CcMmYKk */
1687 for (i = 0; i < 256; i ++)
1688 {
1689 cmyk->channels[0][i] = CUPS_MAX_LUT * i / 255;
1690 cmyk->channels[2][i] = CUPS_MAX_LUT * i / 255;
1691 cmyk->channels[4][i] = CUPS_MAX_LUT * i / 255;
1692 cmyk->channels[5][i] = CUPS_MAX_LUT * i / 255;
1693 }
1694 break;
1695 }
1696
1697 /*
1698 * Return the separation...
1699 */
1700
1701 return (cmyk);
1702}
1703
1704
1705/*
1706 * 'cupsCMYKSetBlack()' - Set the transition range for CMY to black.
1707 */
1708
1709void
1710cupsCMYKSetBlack(cups_cmyk_t *cmyk, /* I - CMYK color separation */
1711 float lower, /* I - No black ink */
1712 float upper) /* I - Only black ink */
1713{
1714 int i, /* Looping var */
1715 delta, /* Difference between lower and upper */
1716 ilower, /* Lower level from 0 to 255 */
1717 iupper; /* Upper level from 0 to 255 */
1718
1719
1720 /*
1721 * Range check input...
1722 */
1723
1724 if (cmyk == NULL || lower < 0.0 || lower > 1.0 || upper < 0.0 || upper > 1.0 ||
1725 lower > upper)
1726 return;
1727
1728 /*
1729 * Convert lower and upper to integers from 0 to 255...
1730 */
1731
1732 ilower = (int)(255.0 * lower + 0.5);
1733 iupper = (int)(255.0 * upper + 0.5);
1734 delta = iupper - ilower;
1735
1736 /*
1737 * Generate the CMY-only data...
1738 */
1739
1740 for (i = 0; i < ilower; i ++)
1741 {
1742 cmyk->black_lut[i] = 0;
1743 cmyk->color_lut[i] = i;
1744 }
1745
1746 /*
1747 * Then the transition data...
1748 */
1749
1750 for (; i < iupper; i ++)
1751 {
1752 cmyk->black_lut[i] = iupper * (i - ilower) / delta;
1753 cmyk->color_lut[i] = ilower - ilower * (i - ilower) / delta;
1754 }
1755
1756 /*
1757 * Then the K-only data...
1758 */
1759
1760 for (; i < 256; i ++)
1761 {
1762 cmyk->black_lut[i] = i;
1763 cmyk->color_lut[i] = 0;
1764 }
1765
1766 fprintf(stderr, "DEBUG: cupsCMYKSetBlack(cmyk, lower=%.3f, upper=%.3f)\n", lower, upper);
1767
1768 for (i = 0; i < 256; i += 17)
1769 fprintf(stderr, "DEBUG: %3d = %3dk + %3dc\n", i,
1770 cmyk->black_lut[i], cmyk->color_lut[i]);
1771}
1772
1773
1774/*
1775 * 'cupsCMYKSetCurve()' - Set a color transform curve using points.
1776 */
1777
1778void
1779cupsCMYKSetCurve(cups_cmyk_t *cmyk, /* I - CMYK color separation */
1780 int channel, /* I - Color channel */
1781 int num_xypoints,
1782 /* I - Number of X,Y points */
1783 const float *xypoints) /* I - X,Y points */
1784{
1785 int i; /* Looping var */
1786 int xstart; /* Start position */
1787 int xend; /* End position */
1788 int xdelta; /* Difference in position */
1789 int ystart; /* Start value */
1790 int yend; /* End value */
1791 int ydelta; /* Difference in value */
1792
1793
1794 /*
1795 * Range check input...
1796 */
1797
1798 if (cmyk == NULL || channel < 0 || channel >= cmyk->num_channels ||
1799 num_xypoints < 1 || xypoints == NULL)
1800 return;
1801
1802 /*
1803 * Initialize the lookup table for the specified channel...
1804 */
1805
1806 for (xstart = xend = 0, ystart = yend = 0;
1807 num_xypoints > 0;
1808 num_xypoints --, xypoints += 2, xstart = xend, ystart = yend)
1809 {
1810 xend = (int)(255.0 * xypoints[1] + 0.5);
1811 yend = (int)(CUPS_MAX_LUT * xypoints[0] + 0.5);
1812 xdelta = xend - xstart;
1813 ydelta = yend - ystart;
1814
1815 for (i = xstart; i < xend; i ++)
1816 cmyk->channels[channel][i] = ystart + ydelta * (i - xstart) / xdelta;
1817 }
1818
1819 /*
1820 * Initialize any trailing values to the maximum of the last data point...
1821 */
1822
1823 for (i = xend; i < 256; i ++)
1824 cmyk->channels[channel][i] = yend;
1825
1826 fprintf(stderr, "DEBUG: cupsCMYKSetXY(cmyk, channel=%d, num_xypoints=%d, "
1827 "xypoints=[%.3f %.3f %.3f %.3f ...])\n", channel,
1828 num_xypoints, xypoints[0], xypoints[1], xypoints[2], xypoints[3]);
1829
1830 for (i = 0; i < 256; i += 17)
1831 fprintf(stderr, "DEBUG: %3d = %4d\n", i,
1832 cmyk->channels[channel + 0][i]);
1833}
1834
1835
1836/*
1837 * 'cupsCMYKSetGamma()' - Set a color transform curve using gamma and density.
1838 */
1839
1840void
1841cupsCMYKSetGamma(cups_cmyk_t *cmyk, /* I - CMYK color separation */
1842 int channel, /* I - Ink channel */
1843 float gamval, /* I - Gamma correction */
1844 float density) /* I - Maximum density */
1845{
1846 int i; /* Looping var */
1847
1848
1849 /*
1850 * Range check input...
1851 */
1852
1853 if (cmyk == NULL || channel < 0 || channel >= cmyk->num_channels ||
1854 gamval <= 0.0 || density <= 0.0 || density > 1.0)
1855 return;
1856
1857 /*
1858 * Initialize the lookup table for the specified channel...
1859 */
1860
1861 for (i = 0; i < 256; i ++)
1862 cmyk->channels[channel][i] = (int)(density * CUPS_MAX_LUT *
1863 pow((float)i / 255.0, gamval) + 0.5);
1864
1865 fprintf(stderr, "DEBUG: cupsCMYKSetGamma(cmyk, channel=%d, gamval=%.3f, "
1866 "density=%.3f)\n", channel, gamval, density);
1867
1868 for (i = 0; i < 256; i += 17)
1869 fprintf(stderr, "DEBUG: %3d = %4d\n", i,
1870 cmyk->channels[channel + 0][i]);
1871}
1872
1873
1874/*
1875 * 'cupsCMYKSetInkLimit()' - Set the limit on the amount of ink.
1876 */
1877
1878void
1879cupsCMYKSetInkLimit(cups_cmyk_t *cmyk, /* I - CMYK color separation */
1880 float limit) /* I - Limit of ink */
1881{
1882 if (!cmyk || limit < 0.0)
1883 return;
1884
1885 cmyk->ink_limit = limit * CUPS_MAX_LUT;
1886}
1887
1888
1889/*
1890 * 'cupsCMYKSetLtDk()' - Set light/dark ink transforms.
1891 */
1892
1893void
1894cupsCMYKSetLtDk(cups_cmyk_t *cmyk, /* I - CMYK color separation */
1895 int channel, /* I - Dark ink channel (+1 for light) */
1896 float light, /* I - Light ink only level */
1897 float dark) /* I - Dark ink only level */
1898{
1899 int i, /* Looping var */
1900 delta, /* Difference between lower and upper */
1901 ilight, /* Light level from 0 to 255 */
1902 idark; /* Dark level from 0 to 255 */
1903 short lut[256]; /* Original LUT data */
1904
1905
1906 /*
1907 * Range check input...
1908 */
1909
1910 if (cmyk == NULL || light < 0.0 || light > 1.0 || dark < 0.0 || dark > 1.0 ||
1911 light > dark || channel < 0 || channel > (cmyk->num_channels - 2))
1912 return;
1913
1914 /*
1915 * Convert lower and upper to integers from 0 to 255...
1916 */
1917
1918 ilight = (int)(255.0 * light + 0.5);
1919 idark = (int)(255.0 * dark + 0.5);
1920 delta = idark - ilight;
1921
1922 /*
1923 * Copy the dark ink LUT...
1924 */
1925
1926 memcpy(lut, cmyk->channels[channel], sizeof(lut));
1927
1928 /*
1929 * Generate the light-only data...
1930 */
1931
1932 for (i = 0; i < ilight; i ++)
1933 {
1934 cmyk->channels[channel + 0][i] = 0;
1935 cmyk->channels[channel + 1][i] = CUPS_MAX_LUT * i / ilight;
1936 }
1937
1938 /*
1939 * Then the transition data...
1940 */
1941
1942 for (; i < idark; i ++)
1943 {
1944 cmyk->channels[channel + 0][i] = CUPS_MAX_LUT * idark * (i - ilight) /
1945 delta / 255;
1946 cmyk->channels[channel + 1][i] = CUPS_MAX_LUT - CUPS_MAX_LUT *
1947 (i - ilight) / delta;
1948 }
1949
1950 /*
1951 * Then the K-only data...
1952 */
1953
1954 for (; i < 256; i ++)
1955 {
1956 cmyk->channels[channel + 0][i] = CUPS_MAX_LUT * i / 255;
1957 cmyk->channels[channel + 1][i] = 0;
1958 }
1959
1960 fprintf(stderr, "DEBUG: cupsCMYKSetLtDk(cmyk, channel=%d, light=%.3f, "
1961 "dark=%.3f)\n", channel, light, dark);
1962
1963 for (i = 0; i < 256; i += 17)
1964 fprintf(stderr, "DEBUG: %3d = %4dlt + %4ddk\n", i,
1965 cmyk->channels[channel + 0][i], cmyk->channels[channel + 1][i]);
1966}
1967
1968
1969/*
1970 * End of "$Id$".
1971 */