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