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