Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
 
188
};
189
 
190
private const fixed_colorant_names_list DeviceRGBComponents = {
191
	"Red",
192
	"Green",
193
	"Blue",
194
 
195
};
196
 
197
private const fixed_colorant_names_list DeviceCMYKComponents = {
198
	"Cyan",
199
	"Magenta",
200
	"Yellow",
201
	"Black",
202
 
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
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
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
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
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
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
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
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
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
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 *
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
}