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