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