1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied, modified
8 or distributed except as expressly authorized under the terms of that
9 license. Refer to licensing information at http://www.artifex.com/
10 or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11 San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
12 */
13
14 /*$Id: gdevxcf.c 8250 2007-09-25 13:31:24Z giles $ */
15 /* Gimp (XCF) export device, supporting DeviceN color models. */
16
17 #include "math_.h"
18 #include "gdevprn.h"
19 #include "gsparam.h"
20 #include "gscrd.h"
21 #include "gscrdp.h"
22 #include "gxlum.h"
23 #include "gdevdcrd.h"
24 #include "gstypes.h"
25 #include "icc.h"
26 #include "gxdcconv.h"
27
28 /* Define the device parameters. */
29 #ifndef X_DPI
30 # define X_DPI 72
31 #endif
32 #ifndef Y_DPI
33 # define Y_DPI 72
34 #endif
35
36 /* The device descriptor */
37 static dev_proc_get_params(xcf_get_params);
38 static dev_proc_put_params(xcf_put_params);
39 static dev_proc_print_page(xcf_print_page);
40 static dev_proc_map_color_rgb(xcf_map_color_rgb);
41 static dev_proc_get_color_mapping_procs(get_spotrgb_color_mapping_procs);
42 #if 0
43 static dev_proc_get_color_mapping_procs(get_spotcmyk_color_mapping_procs);
44 #endif
45 static dev_proc_get_color_mapping_procs(get_xcf_color_mapping_procs);
46 static dev_proc_get_color_comp_index(xcf_get_color_comp_index);
47 static dev_proc_encode_color(xcf_encode_color);
48 static dev_proc_decode_color(xcf_decode_color);
49
50 /*
51 * Type definitions associated with the fixed color model names.
52 */
53 typedef const char * fixed_colorant_name;
54 typedef fixed_colorant_name fixed_colorant_names_list[];
55
56 /*
57 * Structure for holding SeparationNames and SeparationOrder elements.
58 */
59 typedef struct gs_separation_names_s {
60 int num_names;
61 const gs_param_string * names[GX_DEVICE_COLOR_MAX_COMPONENTS];
62 } gs_separation_names;
63
64 /* This is redundant with color_info.cm_name. We may eliminate this
65 typedef and use the latter string for everything. */
66 typedef enum {
67 XCF_DEVICE_GRAY,
68 XCF_DEVICE_RGB,
69 XCF_DEVICE_CMYK,
70 XCF_DEVICE_N
71 } xcf_color_model;
72
73 /*
74 * A structure definition for a DeviceN type device
75 */
76 typedef struct xcf_device_s {
77 gx_device_common;
78 gx_prn_device_common;
79
80 /* ... device-specific parameters ... */
81
82 xcf_color_model color_model;
83
84 /*
85 * Bits per component (device colorant). Currently only 1 and 8 are
86 * supported.
87 */
88 int bitspercomponent;
89
90 /*
91 * Pointer to the colorant names for the color model. This will be
92 * null if we have DeviceN type device. The actual possible colorant
93 * names are those in this list plus those in the separation_names
94 * list (below).
95 */
96 const fixed_colorant_names_list * std_colorant_names;
97 int num_std_colorant_names; /* Number of names in list */
98
99 /*
100 * Separation names (if any).
101 */
102 gs_separation_names separation_names;
103
104 /*
105 * Separation Order (if specified).
106 */
107 gs_separation_names separation_order;
108
109 /* ICC color profile objects, for color conversion. */
110 char profile_rgb_fn[256];
111 icmLuBase *lu_rgb;
112 int lu_rgb_outn;
113
114 char profile_cmyk_fn[256];
115 icmLuBase *lu_cmyk;
116 int lu_cmyk_outn;
117
118 char profile_out_fn[256];
119 icmLuBase *lu_out;
120 } xcf_device;
121
122 /*
123 * Macro definition for DeviceN procedures
124 */
125 #define device_procs(get_color_mapping_procs)\
126 { gdev_prn_open,\
127 gx_default_get_initial_matrix,\
128 NULL, /* sync_output */\
129 gdev_prn_output_page, /* output_page */\
130 gdev_prn_close, /* close */\
131 NULL, /* map_rgb_color - not used */\
132 xcf_map_color_rgb, /* map_color_rgb */\
133 NULL, /* fill_rectangle */\
134 NULL, /* tile_rectangle */\
135 NULL, /* copy_mono */\
136 NULL, /* copy_color */\
137 NULL, /* draw_line */\
138 NULL, /* get_bits */\
139 xcf_get_params, /* get_params */\
140 xcf_put_params, /* put_params */\
141 NULL, /* map_cmyk_color - not used */\
142 NULL, /* get_xfont_procs */\
143 NULL, /* get_xfont_device */\
144 NULL, /* map_rgb_alpha_color */\
145 gx_page_device_get_page_device, /* get_page_device */\
146 NULL, /* get_alpha_bits */\
147 NULL, /* copy_alpha */\
148 NULL, /* get_band */\
149 NULL, /* copy_rop */\
150 NULL, /* fill_path */\
151 NULL, /* stroke_path */\
152 NULL, /* fill_mask */\
153 NULL, /* fill_trapezoid */\
154 NULL, /* fill_parallelogram */\
155 NULL, /* fill_triangle */\
156 NULL, /* draw_thin_line */\
157 NULL, /* begin_image */\
158 NULL, /* image_data */\
159 NULL, /* end_image */\
160 NULL, /* strip_tile_rectangle */\
161 NULL, /* strip_copy_rop */\
162 NULL, /* get_clipping_box */\
163 NULL, /* begin_typed_image */\
164 NULL, /* get_bits_rectangle */\
165 NULL, /* map_color_rgb_alpha */\
166 NULL, /* create_compositor */\
167 NULL, /* get_hardware_params */\
168 NULL, /* text_begin */\
169 NULL, /* finish_copydevice */\
170 NULL, /* begin_transparency_group */\
171 NULL, /* end_transparency_group */\
172 NULL, /* begin_transparency_mask */\
173 NULL, /* end_transparency_mask */\
174 NULL, /* discard_transparency_layer */\
175 get_color_mapping_procs, /* get_color_mapping_procs */\
176 xcf_get_color_comp_index, /* get_color_comp_index */\
177 xcf_encode_color, /* encode_color */\
178 xcf_decode_color /* decode_color */\
179 }
180
181
182 static const fixed_colorant_names_list DeviceGrayComponents = {
183 "Gray",
184 0 /* List terminator */
185 };
186
187 static const fixed_colorant_names_list DeviceRGBComponents = {
188 "Red",
189 "Green",
190 "Blue",
191 0 /* List terminator */
192 };
193
194 static const fixed_colorant_names_list DeviceCMYKComponents = {
195 "Cyan",
196 "Magenta",
197 "Yellow",
198 "Black",
199 0 /* List terminator */
200 };
201
202
203 /*
204 * Example device with RGB and spot color support
205 */
206 static const gx_device_procs spot_rgb_procs = device_procs(get_spotrgb_color_mapping_procs);
207
208 const xcf_device gs_xcf_device =
209 {
210 prn_device_body_extended(xcf_device, spot_rgb_procs, "xcf",
211 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
212 X_DPI, Y_DPI, /* X and Y hardware resolution */
213 0, 0, 0, 0, /* margins */
214 GX_DEVICE_COLOR_MAX_COMPONENTS, 3, /* MaxComponents, NumComp */
215 GX_CINFO_POLARITY_ADDITIVE, /* Polarity */
216 24, 0, /* Depth, Gray_index, */
217 255, 255, 256, 256, /* MaxGray, MaxColor, DitherGray, DitherColor */
218 GX_CINFO_UNKNOWN_SEP_LIN, /* Let check_device_separable set up values */
219 "DeviceN", /* Process color model name */
220 xcf_print_page), /* Printer page print routine */
221 /* DeviceN device specific parameters */
222 XCF_DEVICE_RGB, /* Color model */
223 8, /* Bits per color - must match ncomp, depth, etc. above */
224 (&DeviceRGBComponents), /* Names of color model colorants */
225 3, /* Number colorants for RGB */
226 {0}, /* SeparationNames */
227 {0} /* SeparationOrder names */
228 };
229
230 static const gx_device_procs spot_cmyk_procs = device_procs(get_xcf_color_mapping_procs);
231
232 const xcf_device gs_xcfcmyk_device =
233 {
234 prn_device_body_extended(xcf_device, spot_cmyk_procs, "xcfcmyk",
235 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
236 X_DPI, Y_DPI, /* X and Y hardware resolution */
237 0, 0, 0, 0, /* margins */
238 GX_DEVICE_COLOR_MAX_COMPONENTS, 4, /* MaxComponents, NumComp */
239 GX_CINFO_POLARITY_SUBTRACTIVE, /* Polarity */
240 32, 0, /* Depth, Gray_index, */
241 255, 255, 256, 256, /* MaxGray, MaxColor, DitherGray, DitherColor */
242 GX_CINFO_UNKNOWN_SEP_LIN, /* Let check_device_separable set up values */
243 "DeviceN", /* Process color model name */
244 xcf_print_page), /* Printer page print routine */
245 /* DeviceN device specific parameters */
246 XCF_DEVICE_CMYK, /* Color model */
247 8, /* Bits per color - must match ncomp, depth, etc. above */
248 (&DeviceCMYKComponents), /* Names of color model colorants */
249 4, /* Number colorants for RGB */
250 {0}, /* SeparationNames */
251 {0} /* SeparationOrder names */
252 };
253
254 /*
255 * The following procedures are used to map the standard color spaces into
256 * the color components for the spotrgb device.
257 */
258 static void
gray_cs_to_spotrgb_cm(gx_device * dev,frac gray,frac out[])259 gray_cs_to_spotrgb_cm(gx_device * dev, frac gray, frac out[])
260 {
261 /* TO_DO_DEVICEN This routine needs to include the effects of the SeparationOrder array */
262 int i = ((xcf_device *)dev)->separation_names.num_names;
263
264 out[0] = out[1] = out[2] = gray;
265 for(; i>0; i--) /* Clear spot colors */
266 out[2 + i] = 0;
267 }
268
269 static void
rgb_cs_to_spotrgb_cm(gx_device * dev,const gs_imager_state * pis,frac r,frac g,frac b,frac out[])270 rgb_cs_to_spotrgb_cm(gx_device * dev, const gs_imager_state *pis,
271 frac r, frac g, frac b, frac out[])
272 {
273 /* TO_DO_DEVICEN This routine needs to include the effects of the SeparationOrder array */
274 int i = ((xcf_device *)dev)->separation_names.num_names;
275
276 out[0] = r;
277 out[1] = g;
278 out[2] = b;
279 for(; i>0; i--) /* Clear spot colors */
280 out[2 + i] = 0;
281 }
282
283 static void
cmyk_cs_to_spotrgb_cm(gx_device * dev,frac c,frac m,frac y,frac k,frac out[])284 cmyk_cs_to_spotrgb_cm(gx_device * dev, frac c, frac m, frac y, frac k, frac out[])
285 {
286 /* TO_DO_DEVICEN This routine needs to include the effects of the SeparationOrder array */
287 int i = ((xcf_device *)dev)->separation_names.num_names;
288
289 color_cmyk_to_rgb(c, m, y, k, NULL, out);
290 for(; i>0; i--) /* Clear spot colors */
291 out[2 + i] = 0;
292 }
293
294 static void
gray_cs_to_spotcmyk_cm(gx_device * dev,frac gray,frac out[])295 gray_cs_to_spotcmyk_cm(gx_device * dev, frac gray, frac out[])
296 {
297 /* TO_DO_DEVICEN This routine needs to include the effects of the SeparationOrder array */
298 int i = ((xcf_device *)dev)->separation_names.num_names;
299
300 out[0] = out[1] = out[2] = 0;
301 out[3] = frac_1 - gray;
302 for(; i>0; i--) /* Clear spot colors */
303 out[3 + i] = 0;
304 }
305
306 static void
rgb_cs_to_spotcmyk_cm(gx_device * dev,const gs_imager_state * pis,frac r,frac g,frac b,frac out[])307 rgb_cs_to_spotcmyk_cm(gx_device * dev, const gs_imager_state *pis,
308 frac r, frac g, frac b, frac out[])
309 {
310 /* TO_DO_DEVICEN This routine needs to include the effects of the SeparationOrder array */
311 xcf_device *xdev = (xcf_device *)dev;
312 int n = xdev->separation_names.num_names;
313 int i;
314
315 color_rgb_to_cmyk(r, g, b, pis, out);
316 for(i = 0; i < n; i++) /* Clear spot colors */
317 out[4 + i] = 0;
318 }
319
320 static void
cmyk_cs_to_spotcmyk_cm(gx_device * dev,frac c,frac m,frac y,frac k,frac out[])321 cmyk_cs_to_spotcmyk_cm(gx_device * dev, frac c, frac m, frac y, frac k, frac out[])
322 {
323 /* TO_DO_DEVICEN This routine needs to include the effects of the SeparationOrder array */
324 xcf_device *xdev = (xcf_device *)dev;
325 int n = xdev->separation_names.num_names;
326 int i;
327
328 out[0] = c;
329 out[1] = m;
330 out[2] = y;
331 out[3] = k;
332 for(i = 0; i < n; i++) /* Clear spot colors */
333 out[4 + i] = 0;
334 }
335
336 static void
cmyk_cs_to_spotn_cm(gx_device * dev,frac c,frac m,frac y,frac k,frac out[])337 cmyk_cs_to_spotn_cm(gx_device * dev, frac c, frac m, frac y, frac k, frac out[])
338 {
339 /* TO_DO_DEVICEN This routine needs to include the effects of the SeparationOrder array */
340 xcf_device *xdev = (xcf_device *)dev;
341 int n = xdev->separation_names.num_names;
342 icmLuBase *luo = xdev->lu_cmyk;
343 int i;
344
345 if (luo != NULL) {
346 double in[4];
347 double tmp[MAX_CHAN];
348 int outn = xdev->lu_cmyk_outn;
349
350 in[0] = frac2float(c);
351 in[1] = frac2float(m);
352 in[2] = frac2float(y);
353 in[3] = frac2float(k);
354 luo->lookup(luo, tmp, in);
355 for (i = 0; i < outn; i++)
356 out[i] = float2frac(tmp[i]);
357 for (; i < n + 4; i++)
358 out[i] = 0;
359 } else {
360 /* If no profile given, assume CMYK */
361 out[0] = c;
362 out[1] = m;
363 out[2] = y;
364 out[3] = k;
365 for(i = 0; i < n; i++) /* Clear spot colors */
366 out[4 + i] = 0;
367 }
368 }
369
370 static void
gray_cs_to_spotn_cm(gx_device * dev,frac gray,frac out[])371 gray_cs_to_spotn_cm(gx_device * dev, frac gray, frac out[])
372 {
373 /* TO_DO_DEVICEN This routine needs to include the effects of the SeparationOrder array */
374
375 cmyk_cs_to_spotn_cm(dev, 0, 0, 0, frac_1 - gray, out);
376 }
377
378 static void
rgb_cs_to_spotn_cm(gx_device * dev,const gs_imager_state * pis,frac r,frac g,frac b,frac out[])379 rgb_cs_to_spotn_cm(gx_device * dev, const gs_imager_state *pis,
380 frac r, frac g, frac b, frac out[])
381 {
382 /* TO_DO_DEVICEN This routine needs to include the effects of the SeparationOrder array */
383 xcf_device *xdev = (xcf_device *)dev;
384 int n = xdev->separation_names.num_names;
385 icmLuBase *luo = xdev->lu_rgb;
386 int i;
387
388 if (luo != NULL) {
389 double in[3];
390 double tmp[MAX_CHAN];
391 int outn = xdev->lu_rgb_outn;
392
393 in[0] = frac2float(r);
394 in[1] = frac2float(g);
395 in[2] = frac2float(b);
396 luo->lookup(luo, tmp, in);
397 for (i = 0; i < outn; i++)
398 out[i] = float2frac(tmp[i]);
399 for (; i < n + 4; i++)
400 out[i] = 0;
401 } else {
402 frac cmyk[4];
403
404 color_rgb_to_cmyk(r, g, b, pis, cmyk);
405 cmyk_cs_to_spotn_cm(dev, cmyk[0], cmyk[1], cmyk[2], cmyk[3],
406 out);
407 }
408 }
409
410 static const gx_cm_color_map_procs spotRGB_procs = {
411 gray_cs_to_spotrgb_cm, rgb_cs_to_spotrgb_cm, cmyk_cs_to_spotrgb_cm
412 };
413
414 static const gx_cm_color_map_procs spotCMYK_procs = {
415 gray_cs_to_spotcmyk_cm, rgb_cs_to_spotcmyk_cm, cmyk_cs_to_spotcmyk_cm
416 };
417
418 static const gx_cm_color_map_procs spotN_procs = {
419 gray_cs_to_spotn_cm, rgb_cs_to_spotn_cm, cmyk_cs_to_spotn_cm
420 };
421
422 /*
423 * These are the handlers for returning the list of color space
424 * to color model conversion routines.
425 */
426 static const gx_cm_color_map_procs *
get_spotrgb_color_mapping_procs(const gx_device * dev)427 get_spotrgb_color_mapping_procs(const gx_device * dev)
428 {
429 return &spotRGB_procs;
430 }
431
432 #if 0
433 static const gx_cm_color_map_procs *
434 get_spotcmyk_color_mapping_procs(const gx_device * dev)
435 {
436 return &spotCMYK_procs;
437 }
438 #endif
439
440
441 static const gx_cm_color_map_procs *
get_xcf_color_mapping_procs(const gx_device * dev)442 get_xcf_color_mapping_procs(const gx_device * dev)
443 {
444 const xcf_device *xdev = (const xcf_device *)dev;
445
446 if (xdev->color_model == XCF_DEVICE_RGB)
447 return &spotRGB_procs;
448 else if (xdev->color_model == XCF_DEVICE_CMYK)
449 return &spotCMYK_procs;
450 else if (xdev->color_model == XCF_DEVICE_N)
451 return &spotN_procs;
452 else
453 return NULL;
454 }
455
456 /*
457 * Encode a list of colorant values into a gx_color_index_value.
458 */
459 static gx_color_index
xcf_encode_color(gx_device * dev,const gx_color_value colors[])460 xcf_encode_color(gx_device *dev, const gx_color_value colors[])
461 {
462 int bpc = ((xcf_device *)dev)->bitspercomponent;
463 int drop = sizeof(gx_color_value) * 8 - bpc;
464 gx_color_index color = 0;
465 int i = 0;
466 int ncomp = dev->color_info.num_components;
467
468 for (; i<ncomp; i++) {
469 color <<= bpc;
470 color |= (colors[i] >> drop);
471 }
472 return (color == gx_no_color_index ? color ^ 1 : color);
473 }
474
475 /*
476 * Decode a gx_color_index value back to a list of colorant values.
477 */
478 static int
xcf_decode_color(gx_device * dev,gx_color_index color,gx_color_value * out)479 xcf_decode_color(gx_device * dev, gx_color_index color, gx_color_value * out)
480 {
481 int bpc = ((xcf_device *)dev)->bitspercomponent;
482 int drop = sizeof(gx_color_value) * 8 - bpc;
483 int mask = (1 << bpc) - 1;
484 int i = 0;
485 int ncomp = dev->color_info.num_components;
486
487 for (; i<ncomp; i++) {
488 out[ncomp - i - 1] = (color & mask) << drop;
489 color >>= bpc;
490 }
491 return 0;
492 }
493
494 /*
495 * Convert a gx_color_index to RGB.
496 */
497 static int
xcf_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value rgb[3])498 xcf_map_color_rgb(gx_device *dev, gx_color_index color, gx_color_value rgb[3])
499 {
500 xcf_device *xdev = (xcf_device *)dev;
501
502 if (xdev->color_model == XCF_DEVICE_RGB)
503 return xcf_decode_color(dev, color, rgb);
504 /* TODO: return reasonable values. */
505 rgb[0] = 0;
506 rgb[1] = 0;
507 rgb[2] = 0;
508 return 0;
509 }
510
511 /*
512 * This routine will extract a specified set of bits from a buffer and pack
513 * them into a given buffer.
514 *
515 * Parameters:
516 * source - The source of the data
517 * dest - The destination for the data
518 * depth - The size of the bits per pixel - must be a multiple of 8
519 * first_bit - The location of the first data bit (LSB).
520 * bit_width - The number of bits to be extracted.
521 * npixel - The number of pixels.
522 *
523 * Returns:
524 * Length of the output line (in bytes)
525 * Data in dest.
526 */
527 #if 0
528 static int
529 repack_data(byte * source, byte * dest, int depth, int first_bit,
530 int bit_width, int npixel)
531 {
532 int in_nbyte = depth >> 3; /* Number of bytes per input pixel */
533 int out_nbyte = bit_width >> 3; /* Number of bytes per output pixel */
534 gx_color_index mask = 1;
535 gx_color_index data;
536 int i, j, length = 0;
537 int in_byte_loc = 0, out_byte_loc = 0;
538 byte temp;
539 byte * out = dest;
540 int max_bit_byte = 8 - bit_width;
541
542 mask = (mask << bit_width) - 1;
543 for (i=0; i<npixel; i++) {
544 /* Get the pixel data */
545 if (!in_nbyte) { /* Multiple pixels per byte */
546 data = *source;
547 data >>= in_byte_loc;
548 in_byte_loc += depth;
549 if (in_byte_loc >= 8) { /* If finished with byte */
550 in_byte_loc = 0;
551 source++;
552 }
553 }
554 else { /* One or more bytes per pixel */
555 data = *source++;
556 for (j=1; j<in_nbyte; j++)
557 data = (data << 8) + *source++;
558 }
559 data >>= first_bit;
560 data &= mask;
561
562 /* Put the output data */
563 if (!out_nbyte) { /* Multiple pixels per byte */
564 temp = *out & ~(mask << out_byte_loc);
565 *out = temp | (data << out_byte_loc);
566 out_byte_loc += bit_width;
567 if (out_byte_loc > max_bit_byte) { /* If finished with byte */
568 out_byte_loc = 0;
569 out++;
570 }
571 }
572 else { /* One or more bytes per pixel */
573 *out++ = data >> ((out_nbyte - 1) * 8);
574 for (j=1; j<out_nbyte; j++) {
575 *out++ = data >> ((out_nbyte - 1 - j) * 8);
576 }
577 }
578 }
579 /* Return the number of bytes in the destination buffer. */
580 length = out - dest;
581 if (out_byte_loc) /* If partially filled last byte */
582 length++;
583 return length;
584 }
585 #endif /* 0 */
586
587 static int
xcf_open_profile(xcf_device * xdev,char * profile_fn,icmLuBase ** pluo,int * poutn)588 xcf_open_profile(xcf_device *xdev, char *profile_fn, icmLuBase **pluo,
589 int *poutn)
590 {
591 icmFile *fp;
592 icc *icco;
593 icmLuBase *luo;
594
595 dlprintf1("xcf_open_profile %s\n", profile_fn);
596 fp = new_icmFileStd_name(profile_fn, (char *)"r");
597 if (fp == NULL)
598 return_error(gs_error_undefinedfilename);
599 icco = new_icc();
600 if (icco == NULL)
601 return_error(gs_error_VMerror);
602 if (icco->read(icco, fp, 0))
603 return_error(gs_error_rangecheck);
604 luo = icco->get_luobj(icco, icmFwd, icmDefaultIntent, icmSigDefaultData, icmLuOrdNorm);
605 if (luo == NULL)
606 return_error(gs_error_rangecheck);
607 *pluo = luo;
608 luo->spaces(luo, NULL, NULL, NULL, poutn, NULL, NULL, NULL, NULL);
609 return 0;
610 }
611
612 static int
xcf_open_profiles(xcf_device * xdev)613 xcf_open_profiles(xcf_device *xdev)
614 {
615 int code = 0;
616 if (xdev->lu_out == NULL && xdev->profile_out_fn[0]) {
617 code = xcf_open_profile(xdev, xdev->profile_out_fn,
618 &xdev->lu_out, NULL);
619 }
620 if (code >= 0 && xdev->lu_rgb == NULL && xdev->profile_rgb_fn[0]) {
621 code = xcf_open_profile(xdev, xdev->profile_rgb_fn,
622 &xdev->lu_rgb, &xdev->lu_rgb_outn);
623 }
624 if (code >= 0 && xdev->lu_cmyk == NULL && xdev->profile_cmyk_fn[0]) {
625 code = xcf_open_profile(xdev, xdev->profile_cmyk_fn,
626 &xdev->lu_cmyk, &xdev->lu_cmyk_outn);
627 }
628 return code;
629 }
630
631 #define set_param_array(a, d, s)\
632 (a.data = d, a.size = s, a.persistent = false);
633
634 /* Get parameters. We provide a default CRD. */
635 static int
xcf_get_params(gx_device * pdev,gs_param_list * plist)636 xcf_get_params(gx_device * pdev, gs_param_list * plist)
637 {
638 xcf_device *xdev = (xcf_device *)pdev;
639 int code;
640 bool seprs = false;
641 gs_param_string_array scna;
642 gs_param_string pos;
643 gs_param_string prgbs;
644 gs_param_string pcmyks;
645
646 set_param_array(scna, NULL, 0);
647
648 if ( (code = gdev_prn_get_params(pdev, plist)) < 0 ||
649 (code = sample_device_crd_get_params(pdev, plist, "CRDDefault")) < 0 ||
650 (code = param_write_name_array(plist, "SeparationColorNames", &scna)) < 0 ||
651 (code = param_write_bool(plist, "Separations", &seprs)) < 0)
652 return code;
653
654 pos.data = (const byte *)xdev->profile_out_fn,
655 pos.size = strlen(xdev->profile_out_fn),
656 pos.persistent = false;
657 code = param_write_string(plist, "ProfileOut", &pos);
658 if (code < 0)
659 return code;
660
661 prgbs.data = (const byte *)xdev->profile_rgb_fn,
662 prgbs.size = strlen(xdev->profile_rgb_fn),
663 prgbs.persistent = false;
664 code = param_write_string(plist, "ProfileRgb", &prgbs);
665
666 pcmyks.data = (const byte *)xdev->profile_cmyk_fn,
667 pcmyks.size = strlen(xdev->profile_cmyk_fn),
668 pcmyks.persistent = false;
669 code = param_write_string(plist, "ProfileCmyk", &prgbs);
670
671 return code;
672 }
673 #undef set_param_array
674
675 #define compare_color_names(name, name_size, str, str_size) \
676 (name_size == str_size && \
677 (strncmp((const char *)name, (const char *)str, name_size) == 0))
678
679 /*
680 * This routine will check if a name matches any item in a list of process model
681 * color component names.
682 */
683 static bool
check_process_color_names(const fixed_colorant_names_list * pcomp_list,const gs_param_string * pstring)684 check_process_color_names(const fixed_colorant_names_list * pcomp_list,
685 const gs_param_string * pstring)
686 {
687 if (pcomp_list) {
688 const fixed_colorant_name * plist = *pcomp_list;
689 uint size = pstring->size;
690
691 while( *plist) {
692 if (compare_color_names(*plist, strlen(*plist), pstring->data, size)) {
693 return true;
694 }
695 plist++;
696 }
697 }
698 return false;
699 }
700
701 /*
702 * This utility routine calculates the number of bits required to store
703 * color information. In general the values are rounded up to an even
704 * byte boundary except those cases in which mulitple pixels can evenly
705 * into a single byte.
706 *
707 * The parameter are:
708 * ncomp - The number of components (colorants) for the device. Valid
709 * values are 1 to GX_DEVICE_COLOR_MAX_COMPONENTS
710 * bpc - The number of bits per component. Valid values are 1, 2, 4, 5,
711 * and 8.
712 * Input values are not tested for validity.
713 */
714 static int
bpc_to_depth(int ncomp,int bpc)715 bpc_to_depth(int ncomp, int bpc)
716 {
717 static const byte depths[4][8] = {
718 {1, 2, 0, 4, 8, 0, 0, 8},
719 {2, 4, 0, 8, 16, 0, 0, 16},
720 {4, 8, 0, 16, 16, 0, 0, 24},
721 {4, 8, 0, 16, 32, 0, 0, 32}
722 };
723
724 if (ncomp <=4 && bpc <= 8)
725 return depths[ncomp -1][bpc-1];
726 else
727 return (ncomp * bpc + 7) & 0xf8;
728 }
729
730 #define BEGIN_ARRAY_PARAM(pread, pname, pa, psize, e)\
731 BEGIN\
732 switch (code = pread(plist, (param_name = pname), &(pa))) {\
733 case 0:\
734 if ((pa).size != psize) {\
735 ecode = gs_note_error(gs_error_rangecheck);\
736 (pa).data = 0; /* mark as not filled */\
737 } else
738 #define END_ARRAY_PARAM(pa, e)\
739 goto e;\
740 default:\
741 ecode = code;\
742 e: param_signal_error(plist, param_name, ecode);\
743 case 1:\
744 (pa).data = 0; /* mark as not filled */\
745 }\
746 END
747
748 static int
xcf_param_read_fn(gs_param_list * plist,const char * name,gs_param_string * pstr,int max_len)749 xcf_param_read_fn(gs_param_list *plist, const char *name,
750 gs_param_string *pstr, int max_len)
751 {
752 int code = param_read_string(plist, name, pstr);
753
754 if (code == 0) {
755 if (pstr->size >= max_len)
756 param_signal_error(plist, name, code = gs_error_rangecheck);
757 } else {
758 pstr->data = 0;
759 }
760 return code;
761 }
762
763 /* Compare a C string and a gs_param_string. */
764 static bool
param_string_eq(const gs_param_string * pcs,const char * str)765 param_string_eq(const gs_param_string *pcs, const char *str)
766 {
767 return (strlen(str) == pcs->size &&
768 !strncmp(str, (const char *)pcs->data, pcs->size));
769 }
770
771 static int
xcf_set_color_model(xcf_device * xdev,xcf_color_model color_model)772 xcf_set_color_model(xcf_device *xdev, xcf_color_model color_model)
773 {
774 xdev->color_model = color_model;
775 if (color_model == XCF_DEVICE_GRAY) {
776 xdev->std_colorant_names = &DeviceGrayComponents;
777 xdev->num_std_colorant_names = 1;
778 xdev->color_info.cm_name = "DeviceGray";
779 xdev->color_info.polarity = GX_CINFO_POLARITY_ADDITIVE;
780 } else if (color_model == XCF_DEVICE_RGB) {
781 xdev->std_colorant_names = &DeviceRGBComponents;
782 xdev->num_std_colorant_names = 3;
783 xdev->color_info.cm_name = "DeviceRGB";
784 xdev->color_info.polarity = GX_CINFO_POLARITY_ADDITIVE;
785 } else if (color_model == XCF_DEVICE_CMYK) {
786 xdev->std_colorant_names = &DeviceCMYKComponents;
787 xdev->num_std_colorant_names = 4;
788 xdev->color_info.cm_name = "DeviceCMYK";
789 xdev->color_info.polarity = GX_CINFO_POLARITY_SUBTRACTIVE;
790 } else if (color_model == XCF_DEVICE_N) {
791 xdev->std_colorant_names = &DeviceCMYKComponents;
792 xdev->num_std_colorant_names = 4;
793 xdev->color_info.cm_name = "DeviceN";
794 xdev->color_info.polarity = GX_CINFO_POLARITY_SUBTRACTIVE;
795 } else {
796 return -1;
797 }
798
799 return 0;
800 }
801
802 /* Set parameters. We allow setting the number of bits per component. */
803 static int
xcf_put_params(gx_device * pdev,gs_param_list * plist)804 xcf_put_params(gx_device * pdev, gs_param_list * plist)
805 {
806 xcf_device * const pdevn = (xcf_device *) pdev;
807 gx_device_color_info save_info;
808 gs_param_name param_name;
809 int npcmcolors;
810 int num_spot = pdevn->separation_names.num_names;
811 int ecode = 0;
812 int code;
813 gs_param_string_array scna;
814 gs_param_string po;
815 gs_param_string prgb;
816 gs_param_string pcmyk;
817 gs_param_string pcm;
818 xcf_color_model color_model = pdevn->color_model;
819
820 BEGIN_ARRAY_PARAM(param_read_name_array, "SeparationColorNames", scna, scna.size, scne) {
821 break;
822 } END_ARRAY_PARAM(scna, scne);
823
824 if (code >= 0)
825 code = xcf_param_read_fn(plist, "ProfileOut", &po,
826 sizeof(pdevn->profile_out_fn));
827 if (code >= 0)
828 code = xcf_param_read_fn(plist, "ProfileRgb", &prgb,
829 sizeof(pdevn->profile_rgb_fn));
830 if (code >= 0)
831 code = xcf_param_read_fn(plist, "ProfileCmyk", &pcmyk,
832 sizeof(pdevn->profile_cmyk_fn));
833
834 if (code >= 0)
835 code = param_read_name(plist, "ProcessColorModel", &pcm);
836 if (code == 0) {
837 if (param_string_eq (&pcm, "DeviceGray"))
838 color_model = XCF_DEVICE_GRAY;
839 else if (param_string_eq (&pcm, "DeviceRGB"))
840 color_model = XCF_DEVICE_RGB;
841 else if (param_string_eq (&pcm, "DeviceCMYK"))
842 color_model = XCF_DEVICE_CMYK;
843 else if (param_string_eq (&pcm, "DeviceN"))
844 color_model = XCF_DEVICE_N;
845 else {
846 param_signal_error(plist, "ProcessColorModel",
847 code = gs_error_rangecheck);
848 }
849 }
850 if (code < 0)
851 ecode = code;
852
853 /*
854 * Save the color_info in case gdev_prn_put_params fails, and for
855 * comparison.
856 */
857 save_info = pdevn->color_info;
858 ecode = xcf_set_color_model(pdevn, color_model);
859 if (ecode == 0)
860 ecode = gdev_prn_put_params(pdev, plist);
861 if (ecode < 0) {
862 pdevn->color_info = save_info;
863 return ecode;
864 }
865
866 /* Separations are only valid with a subrtractive color model */
867 if (pdev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE) {
868 /*
869 * Process the separation color names. Remove any names that already
870 * match the process color model colorant names for the device.
871 */
872 if (scna.data != 0) {
873 int i;
874 int num_names = scna.size;
875 const fixed_colorant_names_list * pcomp_names =
876 ((xcf_device *)pdev)->std_colorant_names;
877
878 for (i = num_spot = 0; i < num_names; i++) {
879 if (!check_process_color_names(pcomp_names, &scna.data[i]))
880 pdevn->separation_names.names[num_spot++] = &scna.data[i];
881 }
882 pdevn->separation_names.num_names = num_spot;
883 if (pdevn->is_open)
884 gs_closedevice(pdev);
885 }
886 npcmcolors = pdevn->num_std_colorant_names;
887 pdevn->color_info.num_components = npcmcolors + num_spot;
888 /*
889 * The DeviceN device can have zero components if nothing has been
890 * specified. This causes some problems so force at least one
891 * component until something is specified.
892 */
893 if (!pdevn->color_info.num_components)
894 pdevn->color_info.num_components = 1;
895 pdevn->color_info.depth = bpc_to_depth(pdevn->color_info.num_components,
896 pdevn->bitspercomponent);
897 if (pdevn->color_info.depth != save_info.depth) {
898 gs_closedevice(pdev);
899 }
900 }
901
902 if (po.data != 0) {
903 memcpy(pdevn->profile_out_fn, po.data, po.size);
904 pdevn->profile_out_fn[po.size] = 0;
905 }
906 if (prgb.data != 0) {
907 memcpy(pdevn->profile_rgb_fn, prgb.data, prgb.size);
908 pdevn->profile_rgb_fn[prgb.size] = 0;
909 }
910 if (pcmyk.data != 0) {
911 memcpy(pdevn->profile_cmyk_fn, pcmyk.data, pcmyk.size);
912 pdevn->profile_cmyk_fn[pcmyk.size] = 0;
913 }
914 code = xcf_open_profiles(pdevn);
915
916 return code;
917 }
918
919
920 /*
921 * This routine will check to see if the color component name match those
922 * that are available amoung the current device's color components.
923 *
924 * Parameters:
925 * dev - pointer to device data structure.
926 * pname - pointer to name (zero termination not required)
927 * nlength - length of the name
928 *
929 * This routine returns a positive value (0 to n) which is the device colorant
930 * number if the name is found. It returns a negative value if not found.
931 */
932 static int
xcf_get_color_comp_index(gx_device * dev,const char * pname,int name_size,int component_type)933 xcf_get_color_comp_index(gx_device * dev, const char * pname, int name_size,
934 int component_type)
935 {
936 /* TO_DO_DEVICEN This routine needs to include the effects of the SeparationOrder array */
937 const fixed_colorant_names_list * list = ((const xcf_device *)dev)->std_colorant_names;
938 const fixed_colorant_name * pcolor = *list;
939 int color_component_number = 0;
940 int i;
941
942 /* Check if the component is in the implied list. */
943 if (pcolor) {
944 while( *pcolor) {
945 if (compare_color_names(pname, name_size, *pcolor, strlen(*pcolor)))
946 return color_component_number;
947 pcolor++;
948 color_component_number++;
949 }
950 }
951
952 /* Check if the component is in the separation names list. */
953 {
954 const gs_separation_names * separations = &((const xcf_device *)dev)->separation_names;
955 int num_spot = separations->num_names;
956
957 for (i=0; i<num_spot; i++) {
958 if (compare_color_names((const char *)separations->names[i]->data,
959 separations->names[i]->size, pname, name_size)) {
960 return color_component_number;
961 }
962 color_component_number++;
963 }
964 }
965
966 return -1;
967 }
968
969
970 /* ------ Private definitions ------ */
971
972 /* All two-byte quantities are stored MSB-first! */
973 #if arch_is_big_endian
974 # define assign_u16(a,v) a = (v)
975 # define assign_u32(a,v) a = (v)
976 #else
977 # define assign_u16(a,v) a = ((v) >> 8) + ((v) << 8)
978 # define assign_u32(a,v) a = (((v) >> 24) & 0xff) + (((v) >> 8) & 0xff00) + (((v) & 0xff00) << 8) + (((v) & 0xff) << 24)
979 #endif
980
981 typedef struct {
982 FILE *f;
983 int offset;
984
985 int width;
986 int height;
987 int base_bytes_pp; /* almost always 3 (rgb) */
988 int n_extra_channels;
989
990 int n_tiles_x;
991 int n_tiles_y;
992 int n_tiles;
993 int n_levels;
994
995 /* byte offset of image data */
996 int image_data_off;
997 } xcf_write_ctx;
998
999 #define TILE_WIDTH 64
1000 #define TILE_HEIGHT 64
1001
1002 static int
xcf_calc_levels(int size,int tile_size)1003 xcf_calc_levels(int size, int tile_size)
1004 {
1005 int levels = 1;
1006 while (size > tile_size) {
1007 size >>= 1;
1008 levels++;
1009 }
1010 return levels;
1011 }
1012
1013 static int
xcf_setup_tiles(xcf_write_ctx * xc,xcf_device * dev)1014 xcf_setup_tiles(xcf_write_ctx *xc, xcf_device *dev)
1015 {
1016 xc->base_bytes_pp = 3;
1017 xc->n_extra_channels = dev->separation_names.num_names;
1018 xc->width = dev->width;
1019 xc->height = dev->height;
1020 xc->n_tiles_x = (dev->width + TILE_WIDTH - 1) / TILE_WIDTH;
1021 xc->n_tiles_y = (dev->height + TILE_HEIGHT - 1) / TILE_HEIGHT;
1022 xc->n_tiles = xc->n_tiles_x * xc->n_tiles_y;
1023 xc->n_levels = max(xcf_calc_levels(dev->width, TILE_WIDTH),
1024 xcf_calc_levels(dev->height, TILE_HEIGHT));
1025
1026 return 0;
1027 }
1028
1029 /* Return value: Size of tile in pixels. */
1030 static int
xcf_tile_sizeof(xcf_write_ctx * xc,int tile_idx)1031 xcf_tile_sizeof(xcf_write_ctx *xc, int tile_idx)
1032 {
1033 int tile_i = tile_idx % xc->n_tiles_x;
1034 int tile_j = tile_idx / xc->n_tiles_x;
1035 int tile_size_x = min(TILE_WIDTH, xc->width - tile_i * TILE_WIDTH);
1036 int tile_size_y = min(TILE_HEIGHT, xc->height - tile_j * TILE_HEIGHT);
1037 return tile_size_x * tile_size_y;
1038 }
1039
1040 static int
xcf_write(xcf_write_ctx * xc,const byte * buf,int size)1041 xcf_write(xcf_write_ctx *xc, const byte *buf, int size) {
1042 int code;
1043
1044 code = fwrite(buf, 1, size, xc->f);
1045 if (code < 0)
1046 return code;
1047 xc->offset += code;
1048 return 0;
1049 }
1050
1051 static int
xcf_write_32(xcf_write_ctx * xc,bits32 v)1052 xcf_write_32(xcf_write_ctx *xc, bits32 v)
1053 {
1054 bits32 buf;
1055
1056 assign_u32(buf, v);
1057 return xcf_write(xc, (byte *)&buf, 4);
1058 }
1059
1060 static int
xcf_write_image_props(xcf_write_ctx * xc)1061 xcf_write_image_props(xcf_write_ctx *xc)
1062 {
1063 int code = 0;
1064
1065 xcf_write_32(xc, 0);
1066 xcf_write_32(xc, 0);
1067
1068 return code;
1069 }
1070
1071 /**
1072 * Return value: Number of bytes needed to write layer.
1073 **/
1074 static int
xcf_base_size(xcf_write_ctx * xc,const char * layer_name)1075 xcf_base_size(xcf_write_ctx *xc, const char *layer_name)
1076 {
1077 int bytes_pp = xc->base_bytes_pp + xc->n_extra_channels;
1078
1079 return 17 + strlen (layer_name) + /* header and name */
1080 8 + /* layer props */
1081 12 + xc->n_levels * 16 + /* layer tile hierarchy */
1082 12 + xc->n_tiles * 4 + /* tile offsets */
1083 xc->width * xc->height * bytes_pp; /* image data */
1084 }
1085
1086
1087 static int
xcf_channel_size(xcf_write_ctx * xc,int name_size)1088 xcf_channel_size(xcf_write_ctx *xc, int name_size)
1089 {
1090 return 17 + name_size + /* header and name */
1091 8 + /* channel props */
1092 4 + xc->n_levels * 16 + /* channel tile hiearchy */
1093 12 + xc->n_tiles * 4; /* tile offsets */
1094 }
1095
1096 static int
xcf_write_header(xcf_write_ctx * xc,xcf_device * pdev)1097 xcf_write_header(xcf_write_ctx *xc, xcf_device *pdev)
1098 {
1099 int code = 0;
1100 const char *layer_name = "Background";
1101 int level;
1102 int tile_offset;
1103 int tile_idx;
1104 int n_extra_channels = xc->n_extra_channels;
1105 int bytes_pp = xc->base_bytes_pp + n_extra_channels;
1106 int channel_idx;
1107
1108 xcf_write(xc, (const byte *)"gimp xcf file", 14);
1109 xcf_write_32(xc, xc->width);
1110 xcf_write_32(xc, xc->height);
1111 xcf_write_32(xc, 0);
1112
1113 xcf_write_image_props(xc);
1114
1115 /* layer offsets */
1116 xcf_write_32(xc, xc->offset + 12 + 4 * n_extra_channels);
1117 xcf_write_32(xc, 0);
1118
1119 /* channel offsets */
1120 tile_offset = xc->offset + 4 + 4 * n_extra_channels +
1121 xcf_base_size(xc, layer_name);
1122 for (channel_idx = 0; channel_idx < n_extra_channels; channel_idx++) {
1123 const gs_param_string *separation_name =
1124 pdev->separation_names.names[channel_idx];
1125 dlprintf1("tile offset: %d\n", tile_offset);
1126 xcf_write_32(xc, tile_offset);
1127 tile_offset += xcf_channel_size(xc, separation_name->size);
1128 }
1129 xcf_write_32(xc, 0);
1130
1131 /* layer */
1132 xcf_write_32(xc, xc->width);
1133 xcf_write_32(xc, xc->height);
1134 xcf_write_32(xc, 0);
1135 xcf_write_32(xc, strlen(layer_name) + 1);
1136 xcf_write(xc, (const byte *)layer_name, strlen(layer_name) + 1);
1137
1138 /* layer props */
1139 xcf_write_32(xc, 0);
1140 xcf_write_32(xc, 0);
1141
1142 /* layer tile hierarchy */
1143 xcf_write_32(xc, xc->offset + 8);
1144 xcf_write_32(xc, 0);
1145
1146 xcf_write_32(xc, xc->width);
1147 xcf_write_32(xc, xc->height);
1148 xcf_write_32(xc, xc->base_bytes_pp);
1149 xcf_write_32(xc, xc->offset + (1 + xc->n_levels) * 4);
1150 tile_offset = xc->offset + xc->width * xc->height * bytes_pp +
1151 xc->n_tiles * 4 + 12;
1152 for (level = 1; level < xc->n_levels; level++) {
1153 xcf_write_32(xc, tile_offset);
1154 tile_offset += 12;
1155 }
1156 xcf_write_32(xc, 0);
1157
1158 /* layer tile offsets */
1159 xcf_write_32(xc, xc->width);
1160 xcf_write_32(xc, xc->height);
1161 tile_offset = xc->offset + (xc->n_tiles + 1) * 4;
1162 for (tile_idx = 0; tile_idx < xc->n_tiles; tile_idx++) {
1163 xcf_write_32(xc, tile_offset);
1164 tile_offset += xcf_tile_sizeof(xc, tile_idx) * bytes_pp;
1165 }
1166 xcf_write_32(xc, 0);
1167
1168 xc->image_data_off = xc->offset;
1169
1170 return code;
1171 }
1172
1173 static void
xcf_shuffle_to_tile(xcf_write_ctx * xc,byte ** tile_data,const byte * row,int y)1174 xcf_shuffle_to_tile(xcf_write_ctx *xc, byte **tile_data, const byte *row,
1175 int y)
1176 {
1177 int tile_j = y / TILE_HEIGHT;
1178 int yrem = y % TILE_HEIGHT;
1179 int tile_i;
1180 int base_bytes_pp = xc->base_bytes_pp;
1181 int n_extra_channels = xc->n_extra_channels;
1182 int row_idx = 0;
1183
1184 for (tile_i = 0; tile_i < xc->n_tiles_x; tile_i++) {
1185 int x;
1186 int tile_width = min(TILE_WIDTH, xc->width - tile_i * TILE_WIDTH);
1187 int tile_height = min(TILE_HEIGHT, xc->height - tile_j * TILE_HEIGHT);
1188 byte *base_ptr = tile_data[tile_i] +
1189 yrem * tile_width * base_bytes_pp;
1190 int extra_stride = tile_width * tile_height;
1191 byte *extra_ptr = tile_data[tile_i] + extra_stride * base_bytes_pp +
1192 yrem * tile_width;
1193
1194 int base_idx = 0;
1195
1196 for (x = 0; x < tile_width; x++) {
1197 int plane_idx;
1198 for (plane_idx = 0; plane_idx < base_bytes_pp; plane_idx++)
1199 base_ptr[base_idx++] = row[row_idx++];
1200 for (plane_idx = 0; plane_idx < n_extra_channels; plane_idx++)
1201 extra_ptr[plane_idx * extra_stride + x] = 255 ^ row[row_idx++];
1202 }
1203 }
1204 }
1205
1206 static void
xcf_icc_to_tile(xcf_write_ctx * xc,byte ** tile_data,const byte * row,int y,icmLuBase * luo)1207 xcf_icc_to_tile(xcf_write_ctx *xc, byte **tile_data, const byte *row,
1208 int y, icmLuBase *luo)
1209 {
1210 int tile_j = y / TILE_HEIGHT;
1211 int yrem = y % TILE_HEIGHT;
1212 int tile_i;
1213 int base_bytes_pp = xc->base_bytes_pp;
1214 int n_extra_channels = xc->n_extra_channels;
1215 int row_idx = 0;
1216 int inn, outn;
1217
1218 luo->spaces(luo, NULL, &inn, NULL, &outn, NULL, NULL, NULL, NULL);
1219
1220 for (tile_i = 0; tile_i < xc->n_tiles_x; tile_i++) {
1221 int x;
1222 int tile_width = min(TILE_WIDTH, xc->width - tile_i * TILE_WIDTH);
1223 int tile_height = min(TILE_HEIGHT, xc->height - tile_j * TILE_HEIGHT);
1224 byte *base_ptr = tile_data[tile_i] +
1225 yrem * tile_width * base_bytes_pp;
1226 int extra_stride = tile_width * tile_height;
1227 byte *extra_ptr = tile_data[tile_i] + extra_stride * base_bytes_pp +
1228 yrem * tile_width;
1229 double in[MAX_CHAN], out[MAX_CHAN];
1230
1231 int base_idx = 0;
1232
1233 for (x = 0; x < tile_width; x++) {
1234 int plane_idx;
1235
1236 for (plane_idx = 0; plane_idx < inn; plane_idx++)
1237 in[plane_idx] = row[row_idx++] * (1.0 / 255);
1238 luo->lookup(luo, out, in);
1239 for (plane_idx = 0; plane_idx < outn; plane_idx++)
1240 base_ptr[base_idx++] = (int)(0.5 + 255 * out[plane_idx]);
1241 for (plane_idx = 0; plane_idx < n_extra_channels; plane_idx++)
1242 extra_ptr[plane_idx * extra_stride + x] = 255 ^ row[row_idx++];
1243 }
1244 }
1245 }
1246
1247 static int
xcf_write_image_data(xcf_write_ctx * xc,gx_device_printer * pdev)1248 xcf_write_image_data(xcf_write_ctx *xc, gx_device_printer *pdev)
1249 {
1250 int code = 0;
1251 int raster = gdev_prn_raster(pdev);
1252 int tile_i, tile_j;
1253 byte **tile_data;
1254 byte *line;
1255 int base_bytes_pp = xc->base_bytes_pp;
1256 int n_extra_channels = xc->n_extra_channels;
1257 int bytes_pp = base_bytes_pp + n_extra_channels;
1258 int chan_idx;
1259 xcf_device *xdev = (xcf_device *)pdev;
1260 icmLuBase *luo = xdev->lu_out;
1261
1262 line = gs_alloc_bytes(pdev->memory, raster, "xcf_write_image_data");
1263 tile_data = (byte **)gs_alloc_bytes(pdev->memory,
1264 xc->n_tiles_x * sizeof(byte *),
1265 "xcf_write_image_data");
1266 for (tile_i = 0; tile_i < xc->n_tiles_x; tile_i++) {
1267 int tile_bytes = xcf_tile_sizeof(xc, tile_i) * bytes_pp;
1268
1269 tile_data[tile_i] = gs_alloc_bytes(pdev->memory, tile_bytes,
1270 "xcf_write_image_data");
1271 }
1272 for (tile_j = 0; tile_j < xc->n_tiles_y; tile_j++) {
1273 int y0, y1;
1274 int y;
1275 byte *row;
1276
1277 y0 = tile_j * TILE_HEIGHT;
1278 y1 = min(xc->height, y0 + TILE_HEIGHT);
1279 for (y = y0; y < y1; y++) {
1280 code = gdev_prn_get_bits(pdev, y, line, &row);
1281 if (luo == NULL)
1282 xcf_shuffle_to_tile(xc, tile_data, row, y);
1283 else
1284 xcf_icc_to_tile(xc, tile_data, row, y, luo);
1285 }
1286 for (tile_i = 0; tile_i < xc->n_tiles_x; tile_i++) {
1287 int tile_idx = tile_j * xc->n_tiles_x + tile_i;
1288 int tile_size = xcf_tile_sizeof(xc, tile_idx);
1289 int base_size = tile_size * base_bytes_pp;
1290
1291 xcf_write(xc, tile_data[tile_i], base_size);
1292 for (chan_idx = 0; chan_idx < n_extra_channels; chan_idx++) {
1293 xcf_write(xc, tile_data[tile_i] + base_size +
1294 tile_size * chan_idx, tile_size);
1295 }
1296 }
1297 }
1298
1299 for (tile_i = 0; tile_i < xc->n_tiles_x; tile_i++) {
1300 gs_free_object(pdev->memory, tile_data[tile_i],
1301 "xcf_write_image_data");
1302 }
1303 gs_free_object(pdev->memory, tile_data, "xcf_write_image_data");
1304 gs_free_object(pdev->memory, line, "xcf_write_image_data");
1305 return code;
1306 }
1307
1308 static int
xcf_write_fake_hierarchy(xcf_write_ctx * xc)1309 xcf_write_fake_hierarchy(xcf_write_ctx *xc)
1310 {
1311 int widthf = xc->width, heightf = xc->height;
1312 int i;
1313
1314 for (i = 1; i < xc->n_levels; i++) {
1315 widthf >>= 1;
1316 heightf >>= 1;
1317 xcf_write_32(xc, widthf);
1318 xcf_write_32(xc, heightf);
1319 xcf_write_32(xc, 0);
1320 }
1321 return 0;
1322 }
1323
1324 static int
xcf_write_footer(xcf_write_ctx * xc,xcf_device * pdev)1325 xcf_write_footer(xcf_write_ctx *xc, xcf_device *pdev)
1326 {
1327 int code = 0;
1328 int base_bytes_pp = xc->base_bytes_pp;
1329 int n_extra_channels = xc->n_extra_channels;
1330 int bytes_pp = base_bytes_pp + n_extra_channels;
1331 int chan_idx;
1332
1333 xcf_write_fake_hierarchy(xc);
1334
1335 for (chan_idx = 0; chan_idx < xc->n_extra_channels; chan_idx++) {
1336 const gs_param_string *separation_name =
1337 pdev->separation_names.names[chan_idx];
1338 byte nullbyte[] = { 0 };
1339 int level;
1340 int offset;
1341 int tile_idx;
1342
1343 dlprintf2("actual tile offset: %d %d\n", xc->offset, (int)arch_sizeof_color_index);
1344 xcf_write_32(xc, xc->width);
1345 xcf_write_32(xc, xc->height);
1346 xcf_write_32(xc, separation_name->size + 1);
1347 xcf_write(xc, separation_name->data, separation_name->size);
1348 xcf_write(xc, nullbyte, 1);
1349
1350 /* channel props */
1351 xcf_write_32(xc, 0);
1352 xcf_write_32(xc, 0);
1353
1354 /* channel tile hierarchy */
1355 xcf_write_32(xc, xc->offset + 4);
1356
1357 xcf_write_32(xc, xc->width);
1358 xcf_write_32(xc, xc->height);
1359 xcf_write_32(xc, 1);
1360 xcf_write_32(xc, xc->offset + xc->n_levels * 16 - 8);
1361 offset = xc->offset + xc->n_levels * 4;
1362 for (level = 1; level < xc->n_levels; level++) {
1363 xcf_write_32(xc, offset);
1364 offset += 12;
1365 }
1366 xcf_write_32(xc, 0);
1367 xcf_write_fake_hierarchy(xc);
1368
1369 /* channel tile offsets */
1370 xcf_write_32(xc, xc->width);
1371 xcf_write_32(xc, xc->height);
1372 offset = xc->image_data_off;
1373 for (tile_idx = 0; tile_idx < xc->n_tiles; tile_idx++) {
1374 int tile_size = xcf_tile_sizeof(xc, tile_idx);
1375
1376 xcf_write_32(xc, offset + (base_bytes_pp + chan_idx) * tile_size);
1377 offset += bytes_pp * tile_size;
1378 }
1379 xcf_write_32(xc, 0);
1380
1381 }
1382 return code;
1383 }
1384
1385 static int
xcf_print_page(gx_device_printer * pdev,FILE * file)1386 xcf_print_page(gx_device_printer *pdev, FILE *file)
1387 {
1388 xcf_write_ctx xc;
1389
1390 xc.f = file;
1391 xc.offset = 0;
1392
1393 xcf_setup_tiles(&xc, (xcf_device *)pdev);
1394 xcf_write_header(&xc, (xcf_device *)pdev);
1395 xcf_write_image_data(&xc, pdev);
1396 xcf_write_footer(&xc, (xcf_device *)pdev);
1397
1398 return 0;
1399 }
1400