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