• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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