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