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