• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *   RGB color separation code for CUPS.
3  *
4  *   Copyright 2007 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  *   cupsRGBDelete() - Delete a color separation.
15  *   cupsRGBDoGray() - Do a grayscale separation...
16  *   cupsRGBDoRGB()  - Do a RGB separation...
17  *   cupsRGBLoad()   - Load a RGB color profile from a PPD file.
18  *   cupsRGBNew()    - Create a new RGB color separation.
19  */
20 
21 /*
22  * Include necessary headers.
23  */
24 
25 #include "driver.h"
26 
27 
28 /*
29  * 'cupsRGBDelete()' - Delete a color separation.
30  */
31 
32 void
cupsRGBDelete(cups_rgb_t * rgbptr)33 cupsRGBDelete(cups_rgb_t *rgbptr)	/* I - Color separation */
34 {
35   if (rgbptr == NULL)
36     return;
37 
38   free(rgbptr->colors[0][0][0]);
39   free(rgbptr->colors[0][0]);
40   free(rgbptr->colors[0]);
41   free(rgbptr->colors);
42   free(rgbptr);
43 }
44 
45 
46 /*
47  * 'cupsRGBDoGray()' - Do a grayscale separation...
48  */
49 
50 void
cupsRGBDoGray(cups_rgb_t * rgbptr,const unsigned char * input,unsigned char * output,int num_pixels)51 cupsRGBDoGray(cups_rgb_t          *rgbptr,
52 					/* I - Color separation */
53 	      const unsigned char *input,
54 					/* I - Input grayscale pixels */
55 	      unsigned char       *output,
56 					/* O - Output Device-N pixels */
57 	      int                 num_pixels)
58 					/* I - Number of pixels */
59 {
60   int			i;		/* Looping var */
61   int			lastgray;	/* Previous grayscale */
62   int			xs, ys, zs,	/* Current RGB row offsets */
63 			g, gi, gm0, gm1;/* Current gray index and multipliers ... */
64   const unsigned char	*color;		/* Current color data */
65   int			tempg;		/* Current separation color */
66   int			rgbsize;	/* Separation data size */
67 
68 
69  /*
70   * Range check input...
71   */
72 
73   if (!rgbptr || !input || !output || num_pixels <= 0)
74     return;
75 
76  /*
77   * Initialize variables used for the duration of the separation...
78   */
79 
80   lastgray = -1;
81   rgbsize  = rgbptr->num_channels;
82   xs       = rgbptr->cube_size * rgbptr->cube_size * rgbptr->num_channels;
83   ys       = rgbptr->cube_size * rgbptr->num_channels;
84   zs       = rgbptr->num_channels;
85 
86  /*
87   * Loop through it all...
88   */
89 
90   while (num_pixels > 0)
91   {
92    /*
93     * See if the next pixel is a cached value...
94     */
95 
96     num_pixels --;
97 
98     g = cups_srgb_lut[*input++];
99 
100     if (g == lastgray)
101     {
102      /*
103       * Copy previous color and continue...
104       */
105 
106       memcpy(output, output - rgbptr->num_channels, rgbsize);
107 
108       output += rgbptr->num_channels;
109       continue;
110     }
111     else if (g == 0x00 && rgbptr->cache_init)
112     {
113      /*
114       * Copy black color and continue...
115       */
116 
117       memcpy(output, rgbptr->black, rgbsize);
118 
119       output += rgbptr->num_channels;
120       continue;
121     }
122     else if (g == 0xff && rgbptr->cache_init)
123     {
124      /*
125       * Copy white color and continue...
126       */
127 
128       memcpy(output, rgbptr->white, rgbsize);
129 
130       output += rgbptr->num_channels;
131       continue;
132     }
133 
134    /*
135     * Nope, figure this one out on our own...
136     */
137 
138     gi  = rgbptr->cube_index[g];
139     gm0 = rgbptr->cube_mult[g];
140     gm1 = 256 - gm0;
141 
142     color = rgbptr->colors[gi][gi][gi];
143 
144     for (i = 0; i < rgbptr->num_channels; i ++, color ++)
145     {
146       tempg = (color[0] * gm0 + color[xs + ys + zs] * gm1) / 256;
147 
148       if (tempg > 255)
149         *output++ = 255;
150       else if (tempg < 0)
151         *output++ = 0;
152       else
153         *output++ = tempg;
154     }
155   }
156 }
157 
158 
159 /*
160  * 'cupsRGBDoRGB()' - Do a RGB separation...
161  */
162 
163 void
cupsRGBDoRGB(cups_rgb_t * rgbptr,const unsigned char * input,unsigned char * output,int num_pixels)164 cupsRGBDoRGB(cups_rgb_t          *rgbptr,
165 					/* I - Color separation */
166 	     const unsigned char *input,
167 					/* I - Input RGB pixels */
168 	     unsigned char       *output,
169 					/* O - Output Device-N pixels */
170 	     int                 num_pixels)
171 					/* I - Number of pixels */
172 {
173   int			i;		/* Looping var */
174   int			rgb,		/* Current RGB color */
175 			lastrgb;	/* Previous RGB color */
176   int			r, ri, rm0, rm1, rs,
177 					/* Current red index, multipliexs, and row offset */
178 			g, gi, gm0, gm1, gs,
179 					/* Current green ... */
180 			b, bi, bm0, bm1, bs;
181 					/* Current blue ... */
182   const unsigned char	*color;		/* Current color data */
183   int			tempr,		/* Current separation colors */
184 			tempg,		/* ... */
185 			tempb ;		/* ... */
186   int			rgbsize;	/* Separation data size */
187 
188 
189  /*
190   * Range check input...
191   */
192 
193   if (!rgbptr || !input || !output || num_pixels <= 0)
194     return;
195 
196  /*
197   * Initialize variables used for the duration of the separation...
198   */
199 
200   lastrgb = -1;
201   rgbsize = rgbptr->num_channels;
202   rs      = rgbptr->cube_size * rgbptr->cube_size * rgbptr->num_channels;
203   gs      = rgbptr->cube_size * rgbptr->num_channels;
204   bs      = rgbptr->num_channels;
205 
206  /*
207   * Loop through it all...
208   */
209 
210   while (num_pixels > 0)
211   {
212    /*
213     * See if the next pixel is a cached value...
214     */
215 
216     num_pixels --;
217 
218     r   = cups_srgb_lut[*input++];
219     g   = cups_srgb_lut[*input++];
220     b   = cups_srgb_lut[*input++];
221     rgb = (((r << 8) | g) << 8) | b;
222 
223     if (rgb == lastrgb)
224     {
225      /*
226       * Copy previous color and continue...
227       */
228 
229       memcpy(output, output - rgbptr->num_channels, rgbsize);
230 
231       output += rgbptr->num_channels;
232       continue;
233     }
234     else if (rgb == 0x000000 && rgbptr->cache_init)
235     {
236      /*
237       * Copy black color and continue...
238       */
239 
240       memcpy(output, rgbptr->black, rgbsize);
241 
242       output += rgbptr->num_channels;
243       continue;
244     }
245     else if (rgb == 0xffffff && rgbptr->cache_init)
246     {
247      /*
248       * Copy white color and continue...
249       */
250 
251       memcpy(output, rgbptr->white, rgbsize);
252 
253       output += rgbptr->num_channels;
254       continue;
255     }
256 
257    /*
258     * Nope, figure this one out on our own...
259     */
260 
261     ri  = rgbptr->cube_index[r];
262     rm0 = rgbptr->cube_mult[r];
263     rm1 = 256 - rm0;
264 
265     gi  = rgbptr->cube_index[g];
266     gm0 = rgbptr->cube_mult[g];
267     gm1 = 256 - gm0;
268 
269     bi  = rgbptr->cube_index[b];
270     bm0 = rgbptr->cube_mult[b];
271     bm1 = 256 - bm0;
272 
273     color = rgbptr->colors[ri][gi][bi];
274 
275     for (i = rgbptr->num_channels; i > 0; i --, color ++)
276     {
277       tempb = (color[0] * bm0 + color[bs] * bm1) / 256;
278       tempg = tempb  * gm0;
279       tempb = (color[gs] * gm0 + color[gs + bs] * bm1) / 256;
280       tempg = (tempg + tempb  * gm1) / 256;
281 
282       tempr = tempg * rm0;
283 
284       tempb = (color[rs] * bm0 + color[rs + bs] * bm1) / 256;
285       tempg = tempb  * gm0;
286       tempb = (color[rs + gs] * bm0 + color[rs + gs + bs] * bm1) / 256;
287       tempg = (tempg + tempb  * gm1) / 256;
288 
289       tempr = (tempr + tempg * rm1) / 256;
290 
291       if (tempr > 255)
292         *output++ = 255;
293       else if (tempr < 0)
294         *output++ = 0;
295       else
296         *output++ = tempr;
297     }
298   }
299 }
300 
301 
302 /*
303  * 'cupsRGBLoad()' - Load a RGB color profile from a PPD file.
304  */
305 
306 cups_rgb_t *				/* O - New color profile */
cupsRGBLoad(ppd_file_t * ppd,const char * colormodel,const char * media,const char * resolution)307 cupsRGBLoad(ppd_file_t *ppd,		/* I - PPD file */
308             const char *colormodel,	/* I - Color model */
309             const char *media,		/* I - Media type */
310             const char *resolution)	/* I - Resolution */
311 {
312   int		i,			/* Looping var */
313 		cube_size,		/* Size of color lookup cube */
314 		num_channels,		/* Number of color channels */
315 		num_samples;		/* Number of color samples */
316   cups_sample_t	*samples;		/* Color samples */
317   float		values[7];		/* Color sample values */
318   char		spec[PPD_MAX_NAME];	/* Profile name */
319   ppd_attr_t	*attr;			/* Attribute from PPD file */
320   cups_rgb_t	*rgbptr;		/* RGB color profile */
321 
322 
323  /*
324   * Find the following attributes:
325   *
326   *    cupsRGBProfile  - Specifies the cube size, number of channels, and
327   *                      number of samples
328   *    cupsRGBSample   - Specifies an RGB to CMYK color sample
329   */
330 
331   if ((attr = cupsFindAttr(ppd, "cupsRGBProfile", colormodel, media,
332                            resolution, spec, sizeof(spec))) == NULL)
333   {
334     fputs("DEBUG2: No cupsRGBProfile attribute found for the current settings!\n", stderr);
335     return (NULL);
336   }
337 
338   if (!attr->value || sscanf(attr->value, "%d%d%d", &cube_size, &num_channels,
339                              &num_samples) != 3)
340   {
341     fprintf(stderr, "ERROR: Bad cupsRGBProfile attribute \'%s\'!\n",
342             attr->value ? attr->value : "(null)");
343     return (NULL);
344   }
345 
346   if (cube_size < 2 || cube_size > 16 ||
347       num_channels < 1 || num_channels > CUPS_MAX_RGB ||
348       num_samples != (cube_size * cube_size * cube_size))
349   {
350     fprintf(stderr, "ERROR: Bad cupsRGBProfile attribute \'%s\'!\n",
351             attr->value);
352     return (NULL);
353   }
354 
355  /*
356   * Allocate memory for the samples and read them...
357   */
358 
359   if ((samples = calloc(num_samples, sizeof(cups_sample_t))) == NULL)
360   {
361     fputs("ERROR: Unable to allocate memory for RGB profile!\n", stderr);
362     return (NULL);
363   }
364 
365  /*
366   * Read all of the samples...
367   */
368 
369   for (i = 0; i < num_samples; i ++)
370     if ((attr = ppdFindNextAttr(ppd, "cupsRGBSample", spec)) == NULL)
371       break;
372     else if (!attr->value)
373     {
374       fputs("ERROR: Bad cupsRGBSample value!\n", stderr);
375       break;
376     }
377     else if (sscanf(attr->value, "%f%f%f%f%f%f%f", values + 0,
378                     values + 1, values + 2, values + 3, values + 4, values + 5,
379                     values + 6) != (3 + num_channels))
380     {
381       fputs("ERROR: Bad cupsRGBSample value!\n", stderr);
382       break;
383     }
384     else
385     {
386       samples[i].rgb[0]    = (int)(255.0 * values[0] + 0.5);
387       samples[i].rgb[1]    = (int)(255.0 * values[1] + 0.5);
388       samples[i].rgb[2]    = (int)(255.0 * values[2] + 0.5);
389       samples[i].colors[0] = (int)(255.0 * values[3] + 0.5);
390       if (num_channels > 1)
391 	samples[i].colors[1] = (int)(255.0 * values[4] + 0.5);
392       if (num_channels > 2)
393 	samples[i].colors[2] = (int)(255.0 * values[5] + 0.5);
394       if (num_channels > 3)
395 	samples[i].colors[3] = (int)(255.0 * values[6] + 0.5);
396     }
397 
398  /*
399   * If everything went OK, create the color profile...
400   */
401 
402   if (i == num_samples)
403     rgbptr = cupsRGBNew(num_samples, samples, cube_size, num_channels);
404   else
405     rgbptr = NULL;
406 
407  /*
408   * Free the temporary sample array and return...
409   */
410 
411   free(samples);
412 
413   return (rgbptr);
414 }
415 
416 
417 /*
418  * 'cupsRGBNew()' - Create a new RGB color separation.
419  */
420 
421 cups_rgb_t *				/* O - New color separation or NULL */
cupsRGBNew(int num_samples,cups_sample_t * samples,int cube_size,int num_channels)422 cupsRGBNew(int           num_samples,	/* I - Number of samples */
423 	   cups_sample_t *samples,	/* I - Samples */
424 	   int           cube_size,	/* I - Size of LUT cube */
425            int           num_channels)	/* I - Number of color components */
426 {
427   cups_rgb_t		*rgbptr;	/* New color separation */
428   int			i;		/* Looping var */
429   int			r, g, b;	/* Current RGB */
430   int			tempsize;	/* Sibe of main arrays */
431   unsigned char		*tempc;		/* Pointer for C arrays */
432   unsigned char		**tempb ;	/* Pointer for Z arrays */
433   unsigned char		***tempg;	/* Pointer for Y arrays */
434   unsigned char		****tempr;	/* Pointer for X array */
435   unsigned char		rgb[3];		/* Temporary RGB value */
436 
437 
438  /*
439   * Range-check the input...
440   */
441 
442   if (!samples || num_samples != (cube_size * cube_size * cube_size) ||
443       num_channels <= 0 || num_channels > CUPS_MAX_RGB)
444     return (NULL);
445 
446  /*
447   * Allocate memory for the separation...
448   */
449 
450   if ((rgbptr = calloc(1, sizeof(cups_rgb_t))) == NULL)
451     return (NULL);
452 
453  /*
454   * Allocate memory for the samples and the LUT cube...
455   */
456 
457   tempsize = cube_size * cube_size * cube_size;	/* FUTURE: num_samples < cs^3 */
458 
459   tempc = calloc(tempsize, num_channels);
460   tempb = calloc(tempsize, sizeof(unsigned char *));
461   tempg = calloc(cube_size * cube_size, sizeof(unsigned char **));
462   tempr = calloc(cube_size, sizeof(unsigned char ***));
463 
464   if (tempc == NULL || tempb  == NULL || tempg == NULL || tempr == NULL)
465   {
466     free(rgbptr);
467 
468     if (tempc)
469       free(tempc);
470 
471     if (tempb)
472       free(tempb);
473 
474     if (tempg)
475       free(tempg);
476 
477     if (tempr)
478       free(tempr);
479 
480     return (NULL);
481   }
482 
483  /*
484   * Fill in the arrays...
485   */
486 
487   for (i = 0, r = 0; r < cube_size; r ++)
488   {
489     tempr[r] = tempg + r * cube_size;
490 
491     for (g = 0; g < cube_size; g ++)
492     {
493       tempr[r][g] = tempb + i;
494 
495       for (b = 0; b < cube_size; b ++, i ++)
496         tempr[r][g][b] = tempc + i * num_channels;
497     }
498   }
499 
500   for (i = 0; i < num_samples; i ++)
501   {
502     r = samples[i].rgb[0] * (cube_size - 1) / 255;
503     g = samples[i].rgb[1] * (cube_size - 1) / 255;
504     b = samples[i].rgb[2] * (cube_size - 1) / 255;
505 
506     memcpy(tempr[r][g][b], samples[i].colors, num_channels);
507   }
508 
509   rgbptr->cube_size    = cube_size;
510   rgbptr->num_channels = num_channels;
511   rgbptr->colors       = tempr;
512 
513  /*
514   * Generate the lookup tables for the cube indices and multipliers...
515   */
516 
517   for (i = 0; i < 256; i ++)
518   {
519     rgbptr->cube_index[i] = i * (cube_size - 1) / 256;
520 
521     if (i == 0)
522       rgbptr->cube_mult[i] = 256;
523     else
524       rgbptr->cube_mult[i] = 255 - ((i * (cube_size - 1)) & 255);
525   }
526 
527  /*
528   * Generate the black and white cache values for the separation...
529   */
530 
531   rgb[0] = 0;
532   rgb[1] = 0;
533   rgb[2] = 0;
534 
535   cupsRGBDoRGB(rgbptr, rgb, rgbptr->black, 1);
536 
537   rgb[0] = 255;
538   rgb[1] = 255;
539   rgb[2] = 255;
540 
541   cupsRGBDoRGB(rgbptr, rgb, rgbptr->white, 1);
542 
543   rgbptr->cache_init = 1;
544 
545  /*
546   * Return the separation...
547   */
548 
549   return (rgbptr);
550 }
551 
552