]>
git.ipfire.org Git - thirdparty/cups.git/blob - driver/rgb.c
4 * RGB color separation code for CUPS.
6 * Copyright 2007 by Apple Inc.
7 * Copyright 1993-2005 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
17 * cupsRGBDelete() - Delete a color separation.
18 * cupsRGBDoGray() - Do a grayscale separation...
19 * cupsRGBDoRGB() - Do a RGB separation...
20 * cupsRGBLoad() - Load a RGB color profile from a PPD file.
21 * cupsRGBNew() - Create a new RGB color separation.
25 * Include necessary headers.
32 * 'cupsRGBDelete()' - Delete a color separation.
36 cupsRGBDelete(cups_rgb_t
*rgbptr
) /* I - Color separation */
41 free(rgbptr
->colors
[0][0][0]);
42 free(rgbptr
->colors
[0][0]);
43 free(rgbptr
->colors
[0]);
50 * 'cupsRGBDoGray()' - Do a grayscale separation...
54 cupsRGBDoGray(cups_rgb_t
*rgbptr
,
55 /* I - Color separation */
56 const unsigned char *input
,
57 /* I - Input grayscale pixels */
58 unsigned char *output
,
59 /* O - Output Device-N pixels */
61 /* I - Number of pixels */
63 int i
; /* Looping var */
64 int lastgray
; /* Previous grayscale */
65 int xs
, ys
, zs
, /* Current RGB row offsets */
66 g
, gi
, gm0
, gm1
;/* Current gray index and multipliers ... */
67 const unsigned char *color
; /* Current color data */
68 int tempg
; /* Current separation color */
69 int rgbsize
; /* Separation data size */
73 * Range check input...
76 if (!rgbptr
|| !input
|| !output
|| num_pixels
<= 0)
80 * Initialize variables used for the duration of the separation...
84 rgbsize
= rgbptr
->num_channels
;
85 xs
= rgbptr
->cube_size
* rgbptr
->cube_size
* rgbptr
->num_channels
;
86 ys
= rgbptr
->cube_size
* rgbptr
->num_channels
;
87 zs
= rgbptr
->num_channels
;
90 * Loop through it all...
93 while (num_pixels
> 0)
96 * See if the next pixel is a cached value...
101 g
= cups_srgb_lut
[*input
++];
106 * Copy previous color and continue...
109 memcpy(output
, output
- rgbptr
->num_channels
, rgbsize
);
111 output
+= rgbptr
->num_channels
;
114 else if (g
== 0x00 && rgbptr
->cache_init
)
117 * Copy black color and continue...
120 memcpy(output
, rgbptr
->black
, rgbsize
);
122 output
+= rgbptr
->num_channels
;
125 else if (g
== 0xff && rgbptr
->cache_init
)
128 * Copy white color and continue...
131 memcpy(output
, rgbptr
->white
, rgbsize
);
133 output
+= rgbptr
->num_channels
;
138 * Nope, figure this one out on our own...
141 gi
= rgbptr
->cube_index
[g
];
142 gm0
= rgbptr
->cube_mult
[g
];
145 color
= rgbptr
->colors
[gi
][gi
][gi
];
147 for (i
= 0; i
< rgbptr
->num_channels
; i
++, color
++)
149 tempg
= (color
[0] * gm0
+ color
[xs
+ ys
+ zs
] * gm1
) / 256;
163 * 'cupsRGBDoRGB()' - Do a RGB separation...
167 cupsRGBDoRGB(cups_rgb_t
*rgbptr
,
168 /* I - Color separation */
169 const unsigned char *input
,
170 /* I - Input RGB pixels */
171 unsigned char *output
,
172 /* O - Output Device-N pixels */
174 /* I - Number of pixels */
176 int i
; /* Looping var */
177 int rgb
, /* Current RGB color */
178 lastrgb
; /* Previous RGB color */
179 int r
, ri
, rm0
, rm1
, rs
,
180 /* Current red index, multipliexs, and row offset */
182 /* Current green ... */
184 /* Current blue ... */
185 const unsigned char *color
; /* Current color data */
186 int tempr
, /* Current separation colors */
189 int rgbsize
; /* Separation data size */
193 * Range check input...
196 if (!rgbptr
|| !input
|| !output
|| num_pixels
<= 0)
200 * Initialize variables used for the duration of the separation...
204 rgbsize
= rgbptr
->num_channels
;
205 rs
= rgbptr
->cube_size
* rgbptr
->cube_size
* rgbptr
->num_channels
;
206 gs
= rgbptr
->cube_size
* rgbptr
->num_channels
;
207 bs
= rgbptr
->num_channels
;
210 * Loop through it all...
213 while (num_pixels
> 0)
216 * See if the next pixel is a cached value...
221 r
= cups_srgb_lut
[*input
++];
222 g
= cups_srgb_lut
[*input
++];
223 b
= cups_srgb_lut
[*input
++];
224 rgb
= (((r
<< 8) | g
) << 8) | b
;
229 * Copy previous color and continue...
232 memcpy(output
, output
- rgbptr
->num_channels
, rgbsize
);
234 output
+= rgbptr
->num_channels
;
237 else if (rgb
== 0x000000 && rgbptr
->cache_init
)
240 * Copy black color and continue...
243 memcpy(output
, rgbptr
->black
, rgbsize
);
245 output
+= rgbptr
->num_channels
;
248 else if (rgb
== 0xffffff && rgbptr
->cache_init
)
251 * Copy white color and continue...
254 memcpy(output
, rgbptr
->white
, rgbsize
);
256 output
+= rgbptr
->num_channels
;
261 * Nope, figure this one out on our own...
264 ri
= rgbptr
->cube_index
[r
];
265 rm0
= rgbptr
->cube_mult
[r
];
268 gi
= rgbptr
->cube_index
[g
];
269 gm0
= rgbptr
->cube_mult
[g
];
272 bi
= rgbptr
->cube_index
[b
];
273 bm0
= rgbptr
->cube_mult
[b
];
276 color
= rgbptr
->colors
[ri
][gi
][bi
];
278 for (i
= rgbptr
->num_channels
; i
> 0; i
--, color
++)
280 tempb
= (color
[0] * bm0
+ color
[bs
] * bm1
) / 256;
282 tempb
= (color
[gs
] * gm0
+ color
[gs
+ bs
] * bm1
) / 256;
283 tempg
= (tempg
+ tempb
* gm1
) / 256;
287 tempb
= (color
[rs
] * bm0
+ color
[rs
+ bs
] * bm1
) / 256;
289 tempb
= (color
[rs
+ gs
] * bm0
+ color
[rs
+ gs
+ bs
] * bm1
) / 256;
290 tempg
= (tempg
+ tempb
* gm1
) / 256;
292 tempr
= (tempr
+ tempg
* rm1
) / 256;
306 * 'cupsRGBLoad()' - Load a RGB color profile from a PPD file.
309 cups_rgb_t
* /* O - New color profile */
310 cupsRGBLoad(ppd_file_t
*ppd
, /* I - PPD file */
311 const char *colormodel
, /* I - Color model */
312 const char *media
, /* I - Media type */
313 const char *resolution
) /* I - Resolution */
315 int i
, /* Looping var */
316 cube_size
, /* Size of color lookup cube */
317 num_channels
, /* Number of color channels */
318 num_samples
; /* Number of color samples */
319 cups_sample_t
*samples
; /* Color samples */
320 float values
[7]; /* Color sample values */
321 char spec
[PPD_MAX_NAME
]; /* Profile name */
322 ppd_attr_t
*attr
; /* Attribute from PPD file */
323 cups_rgb_t
*rgbptr
; /* RGB color profile */
327 * Find the following attributes:
329 * cupsRGBProfile - Specifies the cube size, number of channels, and
331 * cupsRGBSample - Specifies an RGB to CMYK color sample
334 if ((attr
= cupsFindAttr(ppd
, "cupsRGBProfile", colormodel
, media
,
335 resolution
, spec
, sizeof(spec
))) == NULL
)
337 fputs("DEBUG2: No cupsRGBProfile attribute found for the current settings!\n", stderr
);
341 if (!attr
->value
|| sscanf(attr
->value
, "%d%d%d", &cube_size
, &num_channels
,
344 fprintf(stderr
, "ERROR: Bad cupsRGBProfile attribute \'%s\'!\n",
345 attr
->value
? attr
->value
: "(null)");
349 if (cube_size
< 2 || cube_size
> 16 ||
350 num_channels
< 1 || num_channels
> CUPS_MAX_RGB
||
351 num_samples
!= (cube_size
* cube_size
* cube_size
))
353 fprintf(stderr
, "ERROR: Bad cupsRGBProfile attribute \'%s\'!\n",
359 * Allocate memory for the samples and read them...
362 if ((samples
= calloc(num_samples
, sizeof(cups_sample_t
))) == NULL
)
364 fputs("ERROR: Unable to allocate memory for RGB profile!\n", stderr
);
369 * Read all of the samples...
372 for (i
= 0; i
< num_samples
; i
++)
373 if ((attr
= ppdFindNextAttr(ppd
, "cupsRGBSample", spec
)) == NULL
)
375 else if (!attr
->value
)
377 fputs("ERROR: Bad cupsRGBSample value!\n", stderr
);
380 else if (sscanf(attr
->value
, "%f%f%f%f%f%f%f", values
+ 0,
381 values
+ 1, values
+ 2, values
+ 3, values
+ 4, values
+ 5,
382 values
+ 6) != (3 + num_channels
))
384 fputs("ERROR: Bad cupsRGBSample value!\n", stderr
);
389 samples
[i
].rgb
[0] = (int)(255.0 * values
[0] + 0.5);
390 samples
[i
].rgb
[1] = (int)(255.0 * values
[1] + 0.5);
391 samples
[i
].rgb
[2] = (int)(255.0 * values
[2] + 0.5);
392 samples
[i
].colors
[0] = (int)(255.0 * values
[3] + 0.5);
393 if (num_channels
> 1)
394 samples
[i
].colors
[1] = (int)(255.0 * values
[4] + 0.5);
395 if (num_channels
> 2)
396 samples
[i
].colors
[2] = (int)(255.0 * values
[5] + 0.5);
397 if (num_channels
> 3)
398 samples
[i
].colors
[3] = (int)(255.0 * values
[6] + 0.5);
402 * If everything went OK, create the color profile...
405 if (i
== num_samples
)
406 rgbptr
= cupsRGBNew(num_samples
, samples
, cube_size
, num_channels
);
411 * Free the temporary sample array and return...
421 * 'cupsRGBNew()' - Create a new RGB color separation.
424 cups_rgb_t
* /* O - New color separation or NULL */
425 cupsRGBNew(int num_samples
, /* I - Number of samples */
426 cups_sample_t
*samples
, /* I - Samples */
427 int cube_size
, /* I - Size of LUT cube */
428 int num_channels
) /* I - Number of color components */
430 cups_rgb_t
*rgbptr
; /* New color separation */
431 int i
; /* Looping var */
432 int r
, g
, b
; /* Current RGB */
433 int tempsize
; /* Sibe of main arrays */
434 unsigned char *tempc
; /* Pointer for C arrays */
435 unsigned char **tempb
; /* Pointer for Z arrays */
436 unsigned char ***tempg
; /* Pointer for Y arrays */
437 unsigned char ****tempr
; /* Pointer for X array */
438 unsigned char rgb
[3]; /* Temporary RGB value */
442 * Range-check the input...
445 if (!samples
|| num_samples
!= (cube_size
* cube_size
* cube_size
) ||
446 num_channels
<= 0 || num_channels
> CUPS_MAX_RGB
)
450 * Allocate memory for the separation...
453 if ((rgbptr
= calloc(1, sizeof(cups_rgb_t
))) == NULL
)
457 * Allocate memory for the samples and the LUT cube...
460 tempsize
= cube_size
* cube_size
* cube_size
; /* FUTURE: num_samples < cs^3 */
462 tempc
= calloc(tempsize
, num_channels
);
463 tempb
= calloc(tempsize
, sizeof(unsigned char *));
464 tempg
= calloc(cube_size
* cube_size
, sizeof(unsigned char **));
465 tempr
= calloc(cube_size
, sizeof(unsigned char ***));
467 if (tempc
== NULL
|| tempb
== NULL
|| tempg
== NULL
|| tempr
== NULL
)
487 * Fill in the arrays...
490 for (i
= 0, r
= 0; r
< cube_size
; r
++)
492 tempr
[r
] = tempg
+ r
* cube_size
;
494 for (g
= 0; g
< cube_size
; g
++)
496 tempr
[r
][g
] = tempb
+ i
;
498 for (b
= 0; b
< cube_size
; b
++, i
++)
499 tempr
[r
][g
][b
] = tempc
+ i
* num_channels
;
503 for (i
= 0; i
< num_samples
; i
++)
505 r
= samples
[i
].rgb
[0] * (cube_size
- 1) / 255;
506 g
= samples
[i
].rgb
[1] * (cube_size
- 1) / 255;
507 b
= samples
[i
].rgb
[2] * (cube_size
- 1) / 255;
509 memcpy(tempr
[r
][g
][b
], samples
[i
].colors
, num_channels
);
512 rgbptr
->cube_size
= cube_size
;
513 rgbptr
->num_channels
= num_channels
;
514 rgbptr
->colors
= tempr
;
517 * Generate the lookup tables for the cube indices and multipliers...
520 for (i
= 0; i
< 256; i
++)
522 rgbptr
->cube_index
[i
] = i
* (cube_size
- 1) / 256;
525 rgbptr
->cube_mult
[i
] = 256;
527 rgbptr
->cube_mult
[i
] = 255 - ((i
* (cube_size
- 1)) & 255);
531 * Generate the black and white cache values for the separation...
538 cupsRGBDoRGB(rgbptr
, rgb
, rgbptr
->black
, 1);
544 cupsRGBDoRGB(rgbptr
, rgb
, rgbptr
->white
, 1);
546 rgbptr
->cache_init
= 1;
549 * Return the separation...