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