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