1 /* Copyright (C) 1995, 2000 Aladdin Enterprises, 2004 Artifex Software Inc. 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: gdevtsep.c,v 1.9 2005/08/30 06:38:44 igor Exp $ */
18 /* tiffgray device: 8-bit Gray uncompressed TIFF device */
19 /* tiff32nc device: 32-bit CMYK uncompressed TIFF device */
20 /* tiffsep device: Generate individual TIFF gray files for each separation. */
21
22 #include "gdevprn.h"
23 #include "gdevtifs.h"
24 #include "gdevdevn.h"
25 #include "gsequivc.h"
26
27 /*
28 * Some of the code in this module is based upon the gdevtfnx.c module.
29 * gdevtfnx.c has the following message:
30 * Thanks to Alan Barclay <alan@escribe.co.uk> for donating the original
31 * version of this code to Ghostscript.
32 */
33
34 /* ------ The device descriptors ------ */
35
36 /* Default X and Y resolution */
37 #define X_DPI 72
38 #define Y_DPI 72
39
40 /* ------ The tiffgray device ------ */
41
42 typedef struct gx_device_tiff_s {
43 gx_device_common;
44 gx_prn_device_common;
45 gdev_tiff_state tiff;
46 } gx_device_tiff;
47
48 private dev_proc_print_page(tiffgray_print_page);
49
50 private const gx_device_procs tiffgray_procs =
51 prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
52 gx_default_gray_map_rgb_color, gx_default_gray_map_color_rgb);
53
54 const gx_device_printer gs_tiffgray_device = {
55 prn_device_body(gx_device_tiff, tiffgray_procs, "tiffgray",
56 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
57 X_DPI, Y_DPI,
58 0, 0, 0, 0, /* Margins */
59 1, 8, 255, 0, 256, 0, tiffgray_print_page)
60 };
61
62 /* ------ Private definitions ------ */
63
64 /* Define our TIFF directory - sorted by tag number */
65 typedef struct tiff_gray_directory_s {
66 TIFF_dir_entry BitsPerSample;
67 TIFF_dir_entry Compression;
68 TIFF_dir_entry Photometric;
69 TIFF_dir_entry FillOrder;
70 TIFF_dir_entry SamplesPerPixel;
71 } tiff_gray_directory;
72
73 private const tiff_gray_directory dir_gray_template =
74 {
75 {TIFFTAG_BitsPerSample, TIFF_SHORT, 1, 8},
76 {TIFFTAG_Compression, TIFF_SHORT, 1, Compression_none},
77 {TIFFTAG_Photometric, TIFF_SHORT, 1, Photometric_min_is_black},
78 {TIFFTAG_FillOrder, TIFF_SHORT, 1, FillOrder_MSB2LSB},
79 {TIFFTAG_SamplesPerPixel, TIFF_SHORT, 1, 1},
80 };
81
82 typedef struct tiff_gray_values_s {
83 TIFF_ushort bps[1];
84 } tiff_gray_values;
85
86 private const tiff_gray_values val_gray_template = {
87 {8}
88 };
89
90 /* ------ Private functions ------ */
91
92 private int
tiffgray_print_page(gx_device_printer * pdev,FILE * file)93 tiffgray_print_page(gx_device_printer * pdev, FILE * file)
94 {
95 gx_device_tiff *const tfdev = (gx_device_tiff *)pdev;
96 int code;
97
98 /* Write the page directory. */
99 code = gdev_tiff_begin_page(pdev, &tfdev->tiff, file,
100 (const TIFF_dir_entry *)&dir_gray_template,
101 sizeof(dir_gray_template) / sizeof(TIFF_dir_entry),
102 (const byte *)&val_gray_template,
103 sizeof(val_gray_template), 0);
104 if (code < 0)
105 return code;
106
107 /* Write the page data. */
108 {
109 int y;
110 int raster = gdev_prn_raster(pdev);
111 byte *line = gs_alloc_bytes(pdev->memory, raster, "tiffgray_print_page");
112 byte *row;
113
114 if (line == 0)
115 return_error(gs_error_VMerror);
116 for (y = 0; y < pdev->height; ++y) {
117 code = gdev_prn_get_bits(pdev, y, line, &row);
118 if (code < 0)
119 break;
120 fwrite((char *)row, raster, 1, file);
121 }
122 gdev_tiff_end_strip(&tfdev->tiff, file);
123 gdev_tiff_end_page(&tfdev->tiff, file);
124 gs_free_object(pdev->memory, line, "tiffgray_print_page");
125 }
126
127 return code;
128 }
129
130 /* ------ The tiff32nc device ------ */
131
132 private dev_proc_print_page(tiff32nc_print_page);
133
134 #define cmyk_procs(p_map_color_rgb, p_map_cmyk_color)\
135 gdev_prn_open, NULL, NULL, gdev_prn_output_page, gdev_prn_close,\
136 NULL, p_map_color_rgb, NULL, NULL, NULL, NULL, NULL, NULL,\
137 gdev_prn_get_params, gdev_prn_put_params,\
138 p_map_cmyk_color, NULL, NULL, NULL, gx_page_device_get_page_device
139
140 /* 8-bit-per-plane separated CMYK color. */
141
142 private const gx_device_procs tiff32nc_procs = {
143 cmyk_procs(cmyk_8bit_map_color_cmyk, cmyk_8bit_map_cmyk_color)
144 };
145
146 const gx_device_printer gs_tiff32nc_device = {
147 prn_device_body(gx_device_tiff, tiff32nc_procs, "tiff32nc",
148 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
149 X_DPI, Y_DPI,
150 0, 0, 0, 0, /* Margins */
151 4, 32, 255, 255, 256, 256, tiff32nc_print_page)
152 };
153
154 /* ------ Private definitions ------ */
155
156 /* Define our TIFF directory - sorted by tag number */
157 typedef struct tiff_cmyk_directory_s {
158 TIFF_dir_entry BitsPerSample;
159 TIFF_dir_entry Compression;
160 TIFF_dir_entry Photometric;
161 TIFF_dir_entry FillOrder;
162 TIFF_dir_entry SamplesPerPixel;
163 } tiff_cmyk_directory;
164
165 typedef struct tiff_cmyk_values_s {
166 TIFF_ushort bps[4];
167 } tiff_cmyk_values;
168
169 private const tiff_cmyk_values val_cmyk_template = {
170 {8, 8, 8 ,8}
171 };
172
173 private const tiff_cmyk_directory dir_cmyk_template =
174 {
175 /* C's ridiculous rules about & and arrays require bps[0] here: */
176 {TIFFTAG_BitsPerSample, TIFF_SHORT | TIFF_INDIRECT, 4, offset_of(tiff_cmyk_values, bps[0])},
177 {TIFFTAG_Compression, TIFF_SHORT, 1, Compression_none},
178 {TIFFTAG_Photometric, TIFF_SHORT, 1, Photometric_separated},
179 {TIFFTAG_FillOrder, TIFF_SHORT, 1, FillOrder_MSB2LSB},
180 {TIFFTAG_SamplesPerPixel, TIFF_SHORT, 1, 4},
181 };
182
183 /* ------ Private functions ------ */
184
185 private int
tiff32nc_print_page(gx_device_printer * pdev,FILE * file)186 tiff32nc_print_page(gx_device_printer * pdev, FILE * file)
187 {
188 gx_device_tiff *const tfdev = (gx_device_tiff *)pdev;
189 int code;
190
191 /* Write the page directory. */
192 code = gdev_tiff_begin_page(pdev, &tfdev->tiff, file,
193 (const TIFF_dir_entry *)&dir_cmyk_template,
194 sizeof(dir_cmyk_template) / sizeof(TIFF_dir_entry),
195 (const byte *)&val_cmyk_template,
196 sizeof(val_cmyk_template), 0);
197 if (code < 0)
198 return code;
199
200 /* Write the page data. */
201 {
202 int y;
203 int raster = gdev_prn_raster(pdev);
204 byte *line = gs_alloc_bytes(pdev->memory, raster, "tiff32nc_print_page");
205 byte *row;
206
207 if (line == 0)
208 return_error(gs_error_VMerror);
209 for (y = 0; y < pdev->height; ++y) {
210 code = gdev_prn_get_bits(pdev, y, line, &row);
211 if (code < 0)
212 break;
213 fwrite((char *)row, raster, 1, file);
214 }
215 gdev_tiff_end_strip(&tfdev->tiff, file);
216 gdev_tiff_end_page(&tfdev->tiff, file);
217 gs_free_object(pdev->memory, line, "tiff32nc_print_page");
218 }
219
220 return code;
221 }
222
223 /* ---------- The tiffsep device ------------ */
224
225 #define NUM_CMYK_COMPONENTS 4
226 #define MAX_FILE_NAME_SIZE gp_file_name_sizeof
227 #define MAX_COLOR_VALUE 255 /* We are using 8 bits per colorant */
228
229 /* The device descriptor */
230 private dev_proc_open_device(tiffsep_prn_open);
231 private dev_proc_close_device(tiffsep_prn_close);
232 private dev_proc_get_params(tiffsep_get_params);
233 private dev_proc_put_params(tiffsep_put_params);
234 private dev_proc_print_page(tiffsep_print_page);
235 private dev_proc_get_color_mapping_procs(tiffsep_get_color_mapping_procs);
236 private dev_proc_get_color_comp_index(tiffsep_get_color_comp_index);
237 private dev_proc_encode_color(tiffsep_encode_color);
238 private dev_proc_decode_color(tiffsep_decode_color);
239 private dev_proc_update_spot_equivalent_colors(tiffsep_update_spot_equivalent_colors);
240
241
242 /*
243 * A structure definition for a DeviceN type device
244 */
245 typedef struct tiffsep_device_s {
246 gx_device_common;
247 gx_prn_device_common;
248
249 /* ... device-specific parameters ... */
250
251 gdev_tiff_state tiff_comp; /* tiff state for comp file */
252 /* tiff state for separation files */
253 gdev_tiff_state tiff[GX_DEVICE_COLOR_MAX_COMPONENTS];
254 FILE * sep_file[GX_DEVICE_COLOR_MAX_COMPONENTS];
255 gs_devn_params devn_params; /* DeviceN generated parameters */
256 equivalent_cmyk_color_params equiv_cmyk_colors;
257 } tiffsep_device;
258
259 /* GC procedures */
260 private
ENUM_PTRS_WITH(tiffsep_device_enum_ptrs,tiffsep_device * pdev)261 ENUM_PTRS_WITH(tiffsep_device_enum_ptrs, tiffsep_device *pdev)
262 {
263 if (index < pdev->devn_params.separations.num_separations)
264 ENUM_RETURN(pdev->devn_params.separations.names[index].data);
265 ENUM_PREFIX(st_device_printer,
266 pdev->devn_params.separations.num_separations);
267 }
268
269 ENUM_PTRS_END
RELOC_PTRS_WITH(tiffsep_device_reloc_ptrs,tiffsep_device * pdev)270 private RELOC_PTRS_WITH(tiffsep_device_reloc_ptrs, tiffsep_device *pdev)
271 {
272 RELOC_PREFIX(st_device_printer);
273 {
274 int i;
275
276 for (i = 0; i < pdev->devn_params.separations.num_separations; ++i) {
277 RELOC_PTR(tiffsep_device, devn_params.separations.names[i].data);
278 }
279 }
280 }
281 RELOC_PTRS_END
282
283 /* Even though tiffsep_device_finalize is the same as gx_device_finalize, */
284 /* we need to implement it separately because st_composite_final */
285 /* declares all 3 procedures as private. */
286 private void
tiffsep_device_finalize(void * vpdev)287 tiffsep_device_finalize(void *vpdev)
288 {
289 gx_device_finalize(vpdev);
290 }
291
292 gs_private_st_composite_final(st_tiffsep_device, tiffsep_device,
293 "tiffsep_device", tiffsep_device_enum_ptrs, tiffsep_device_reloc_ptrs,
294 tiffsep_device_finalize);
295
296 /*
297 * Macro definition for tiffsep device procedures
298 */
299 #define device_procs \
300 { tiffsep_prn_open,\
301 gx_default_get_initial_matrix,\
302 NULL, /* sync_output */\
303 gdev_prn_output_page, /* output_page */\
304 tiffsep_prn_close, /* close */\
305 NULL, /* map_rgb_color - not used */\
306 tiffsep_decode_color, /* map_color_rgb */\
307 NULL, /* fill_rectangle */\
308 NULL, /* tile_rectangle */\
309 NULL, /* copy_mono */\
310 NULL, /* copy_color */\
311 NULL, /* draw_line */\
312 NULL, /* get_bits */\
313 tiffsep_get_params, /* get_params */\
314 tiffsep_put_params, /* put_params */\
315 NULL, /* map_cmyk_color - not used */\
316 NULL, /* get_xfont_procs */\
317 NULL, /* get_xfont_device */\
318 NULL, /* map_rgb_alpha_color */\
319 gx_page_device_get_page_device, /* get_page_device */\
320 NULL, /* get_alpha_bits */\
321 NULL, /* copy_alpha */\
322 NULL, /* get_band */\
323 NULL, /* copy_rop */\
324 NULL, /* fill_path */\
325 NULL, /* stroke_path */\
326 NULL, /* fill_mask */\
327 NULL, /* fill_trapezoid */\
328 NULL, /* fill_parallelogram */\
329 NULL, /* fill_triangle */\
330 NULL, /* draw_thin_line */\
331 NULL, /* begin_image */\
332 NULL, /* image_data */\
333 NULL, /* end_image */\
334 NULL, /* strip_tile_rectangle */\
335 NULL, /* strip_copy_rop */\
336 NULL, /* get_clipping_box */\
337 NULL, /* begin_typed_image */\
338 NULL, /* get_bits_rectangle */\
339 NULL, /* map_color_rgb_alpha */\
340 NULL, /* create_compositor */\
341 NULL, /* get_hardware_params */\
342 NULL, /* text_begin */\
343 NULL, /* finish_copydevice */\
344 NULL, /* begin_transparency_group */\
345 NULL, /* end_transparency_group */\
346 NULL, /* begin_transparency_mask */\
347 NULL, /* end_transparency_mask */\
348 NULL, /* discard_transparency_layer */\
349 tiffsep_get_color_mapping_procs,/* get_color_mapping_procs */\
350 tiffsep_get_color_comp_index, /* get_color_comp_index */\
351 tiffsep_encode_color, /* encode_color */\
352 tiffsep_decode_color, /* decode_color */\
353 NULL, /* pattern_manage */\
354 NULL, /* fill_rectangle_hl_color */\
355 NULL, /* include_color_space */\
356 NULL, /* fill_linear_color_scanline */\
357 NULL, /* fill_linear_color_trapezoid */\
358 NULL, /* fill_linear_color_triangle */\
359 tiffsep_update_spot_equivalent_colors /* update_spot_equivalent_colors */\
360 }
361
362 #define tiffsep_device_body(procs, dname, ncomp, pol, depth, mg, mc, cn)\
363 std_device_full_body_type_extended(tiffsep_device, &procs, dname,\
364 &st_tiffsep_device,\
365 (int)((long)(DEFAULT_WIDTH_10THS) * (X_DPI) / 10),\
366 (int)((long)(DEFAULT_HEIGHT_10THS) * (Y_DPI) / 10),\
367 X_DPI, Y_DPI,\
368 GX_DEVICE_COLOR_MAX_COMPONENTS, /* MaxComponents */\
369 ncomp, /* NumComp */\
370 pol, /* Polarity */\
371 depth, 0, /* Depth, GrayIndex */\
372 mg, mc, /* MaxGray, MaxColor */\
373 mg + 1, mc + 1, /* DitherGray, DitherColor */\
374 GX_CINFO_SEP_LIN, /* Linear & Separable */\
375 cn, /* Process color model name */\
376 0, 0, /* offsets */\
377 0, 0, 0, 0 /* margins */\
378 ),\
379 prn_device_body_rest_(tiffsep_print_page),\
380 { 0 }, /* tiff state for comp file */\
381 {{ 0 }}, /* tiff state for separation files */\
382 { 0 } /* separation files */
383
384 /*
385 * Select the default number of components based upon the number of bits
386 * that we have in a gx_color_index
387 */
388 #define NC ((arch_sizeof_color_index <= 8) ? arch_sizeof_color_index : 8)
389
390 /*
391 * TIFF device with CMYK process color model and spot color support.
392 */
393 private const gx_device_procs spot_cmyk_procs = device_procs;
394
395 const tiffsep_device gs_tiffsep_device =
396 {
397 tiffsep_device_body(spot_cmyk_procs, "tiffsep", NC, GX_CINFO_POLARITY_SUBTRACTIVE, NC * 8, MAX_COLOR_VALUE, MAX_COLOR_VALUE, "DeviceCMYK"),
398 /* devn_params specific parameters */
399 { 8, /* Bits per color - must match ncomp, depth, etc. above */
400 DeviceCMYKComponents, /* Names of color model colorants */
401 4, /* Number colorants for CMYK */
402 NC, /* MaxSeparations: our current limit is 8 bytes */
403 {0}, /* SeparationNames */
404 0, /* SeparationOrder names */
405 {0, 1, 2, 3, 4, 5, 6, 7 } /* Initial component SeparationOrder */
406 },
407 { true }, /* equivalent CMYK colors for spot colors */
408 };
409
410 #undef NC
411
412 /*
413 * The following procedures are used to map the standard color spaces into
414 * the color components for the tiffsep device.
415 */
416 private void
tiffsep_gray_cs_to_cm(gx_device * dev,frac gray,frac out[])417 tiffsep_gray_cs_to_cm(gx_device * dev, frac gray, frac out[])
418 {
419 int * map = ((tiffsep_device *) dev)->devn_params.separation_order_map;
420
421 gray_cs_to_devn_cm(dev, map, gray, out);
422 }
423
424 private void
tiffsep_rgb_cs_to_cm(gx_device * dev,const gs_imager_state * pis,frac r,frac g,frac b,frac out[])425 tiffsep_rgb_cs_to_cm(gx_device * dev, const gs_imager_state *pis,
426 frac r, frac g, frac b, frac out[])
427 {
428 int * map = ((tiffsep_device *) dev)->devn_params.separation_order_map;
429
430 rgb_cs_to_devn_cm(dev, map, pis, r, g, b, out);
431 }
432
433 private void
tiffsep_cmyk_cs_to_cm(gx_device * dev,frac c,frac m,frac y,frac k,frac out[])434 tiffsep_cmyk_cs_to_cm(gx_device * dev,
435 frac c, frac m, frac y, frac k, frac out[])
436 {
437 int * map = ((tiffsep_device *) dev)->devn_params.separation_order_map;
438
439 cmyk_cs_to_devn_cm(dev, map, c, m, y, k, out);
440 }
441
442 private const gx_cm_color_map_procs tiffsep_cm_procs = {
443 tiffsep_gray_cs_to_cm,
444 tiffsep_rgb_cs_to_cm,
445 tiffsep_cmyk_cs_to_cm
446 };
447
448 /*
449 * These are the handlers for returning the list of color space
450 * to color model conversion routines.
451 */
452 private const gx_cm_color_map_procs *
tiffsep_get_color_mapping_procs(const gx_device * dev)453 tiffsep_get_color_mapping_procs(const gx_device * dev)
454 {
455 return &tiffsep_cm_procs;
456 }
457 /*
458 * Encode a list of colorant values into a gx_color_index_value.
459 */
460 private gx_color_index
tiffsep_encode_color(gx_device * dev,const gx_color_value colors[])461 tiffsep_encode_color(gx_device *dev, const gx_color_value colors[])
462 {
463 int bpc = ((tiffsep_device *)dev)->devn_params.bitspercomponent;
464 int drop = sizeof(gx_color_value) * 8 - bpc;
465 gx_color_index color = 0;
466 int i = 0;
467 int ncomp = dev->color_info.num_components;
468
469 for (; i < ncomp; i++) {
470 color <<= bpc;
471 color |= (colors[i] >> drop);
472 }
473 return (color == gx_no_color_index ? color ^ 1 : color);
474 }
475
476 /*
477 * Decode a gx_color_index value back to a list of colorant values.
478 */
479 private int
tiffsep_decode_color(gx_device * dev,gx_color_index color,gx_color_value * out)480 tiffsep_decode_color(gx_device * dev, gx_color_index color, gx_color_value * out)
481 {
482 int bpc = ((tiffsep_device *)dev)->devn_params.bitspercomponent;
483 int drop = sizeof(gx_color_value) * 8 - bpc;
484 int mask = (1 << bpc) - 1;
485 int i = 0;
486 int ncomp = dev->color_info.num_components;
487
488 for (; i < ncomp; i++) {
489 out[ncomp - i - 1] = (gx_color_value) ((color & mask) << drop);
490 color >>= bpc;
491 }
492 return 0;
493 }
494
495 /*
496 * Device proc for updating the equivalent CMYK color for spot colors.
497 */
498 private int
tiffsep_update_spot_equivalent_colors(gx_device * dev,const gs_state * pgs)499 tiffsep_update_spot_equivalent_colors(gx_device * dev, const gs_state * pgs)
500 {
501 tiffsep_device * pdev = (tiffsep_device *)dev;
502
503 update_spot_equivalent_cmyk_colors(dev, pgs,
504 &pdev->devn_params, &pdev->equiv_cmyk_colors);
505 return 0;
506 }
507
508 /* Get parameters. We provide a default CRD. */
509 private int
tiffsep_get_params(gx_device * pdev,gs_param_list * plist)510 tiffsep_get_params(gx_device * pdev, gs_param_list * plist)
511 {
512 int code = gdev_prn_get_params(pdev, plist);
513
514 if (code < 0)
515 return code;
516 return devn_get_params(pdev, plist,
517 &(((tiffsep_device *)pdev)->devn_params),
518 &(((tiffsep_device *)pdev)->equiv_cmyk_colors));
519 }
520
521 /* Set parameters. We allow setting the number of bits per component. */
522 private int
tiffsep_put_params(gx_device * pdev,gs_param_list * plist)523 tiffsep_put_params(gx_device * pdev, gs_param_list * plist)
524 {
525 tiffsep_device * const pdevn = (tiffsep_device *) pdev;
526
527 return devn_printer_put_params(pdev, plist,
528 &(pdevn->devn_params), &(pdevn->equiv_cmyk_colors));
529 }
530
531 /*
532 * This routine will check to see if the color component name match those
533 * that are available amoung the current device's color components.
534 *
535 * Parameters:
536 * dev - pointer to device data structure.
537 * pname - pointer to name (zero termination not required)
538 * nlength - length of the name
539 *
540 * This routine returns a positive value (0 to n) which is the device colorant
541 * number if the name is found. It returns GX_DEVICE_COLOR_MAX_COMPONENTS if
542 * the colorant is not being used due to a SeparationOrder device parameter.
543 * It returns a negative value if not found.
544 */
545 private int
tiffsep_get_color_comp_index(gx_device * dev,const char * pname,int name_size,int component_type)546 tiffsep_get_color_comp_index(gx_device * dev, const char * pname,
547 int name_size, int component_type)
548 {
549 tiffsep_device * pdev = (tiffsep_device *) dev;
550
551 /*
552 * We allow more spot colors than we can image. This allows the user
553 * to obtain separations for more than our max of 8 by doing multiple
554 * passes.
555 */
556 return devn_get_color_comp_index(dev,
557 &(pdev->devn_params), &(pdev->equiv_cmyk_colors),
558 pname, name_size, component_type, ALLOW_EXTRA_SPOT_COLORS);
559 }
560
561 /*
562 * There can be a conflict if a separation name is used as part of the file
563 * name for a separation output file. PostScript and PDF do not restrict
564 * the characters inside separation names. However most operating systems
565 * have some sort of restrictions. For instance: /, \, and : have special
566 * meaning under Windows. This implies that there should be some sort of
567 * escape sequence for special characters. This routine exists as a place
568 * to put the handling of that escaping. However it is not actually
569 * implemented.
570 */
571 private void
copy_separation_name(tiffsep_device * pdev,char * buffer,int max_size,int sep_num)572 copy_separation_name(tiffsep_device * pdev,
573 char * buffer, int max_size, int sep_num)
574 {
575 int sep_size = pdev->devn_params.separations.names[sep_num].size;
576
577 /* If name is too long then clip it. */
578 if (sep_size > max_size - 1)
579 sep_size = max_size - 1;
580 memcpy(buffer, pdev->devn_params.separations.names[sep_num].data,
581 sep_size);
582 buffer[sep_size] = 0; /* Terminate string */
583 }
584
585 /*
586 * Create a name for a separation file.
587 */
588 private int
create_separation_file_name(tiffsep_device * pdev,char * buffer,uint max_size,int sep_num)589 create_separation_file_name(tiffsep_device * pdev, char * buffer,
590 uint max_size, int sep_num)
591 {
592 uint base_filename_length = strlen(pdev->fname);
593
594 /*
595 * In most cases it is more convenient if we append '.tif' to the end
596 * of the file name.
597 */
598 #define APPEND_TIF_TO_NAME 1
599 #define SUFFIX_SIZE (4 * APPEND_TIF_TO_NAME)
600
601 memcpy(buffer, pdev->fname, base_filename_length);
602 buffer[base_filename_length] = '.';
603 base_filename_length++;
604
605 if (sep_num < pdev->devn_params.num_std_colorant_names) {
606 if (max_size < strlen(pdev->devn_params.std_colorant_names[sep_num]))
607 return_error(gs_error_rangecheck);
608 strcpy(buffer + base_filename_length,
609 pdev->devn_params.std_colorant_names[sep_num]);
610 }
611 else {
612 sep_num -= pdev->devn_params.num_std_colorant_names;
613 #define USE_SEPARATION_NAME 0 /* See comments before copy_separation_name */
614 #if USE_SEPARATION_NAME
615 copy_separation_name(pdev, buffer + base_filename_length,
616 max_size - SUFFIX_SIZE, sep_num);
617 #else
618 /* Max of 10 chars in %d format */
619 if (max_size < base_filename_length + 11)
620 return_error(gs_error_rangecheck);
621 sprintf(buffer + base_filename_length, "s%d", sep_num);
622 #endif
623 #undef USE_SEPARATION_NAME
624 }
625 #if APPEND_TIF_TO_NAME
626 if (max_size < strlen(buffer) + SUFFIX_SIZE)
627 return_error(gs_error_rangecheck);
628 strcat(buffer, ".tif");
629 #endif
630 return 0;
631 }
632
633 /*
634 * Determine the number of output separations for the tiffsep device.
635 *
636 * There are several factors which affect the number of output separations
637 * for the tiffsep device.
638 *
639 * Due to limitations on the size of a gx_color_index, we are limited to a
640 * maximum of 8 colors per pass. Thus the tiffsep device is set to 8
641 * components. However this is not usually the number of actual separation
642 * files to be created.
643 *
644 * If the SeparationOrder parameter has been specified, then we use it to
645 * select the number and which separation files are created.
646 *
647 * If the SeparationOrder parameter has not been specified, then we use the
648 * nuber of process colors (CMYK) and the number of spot colors unless we
649 * exceed the 8 component maximum for the device.
650 *
651 * Note: Unlike most other devices, the tiffsep device will accept more than
652 * four spot colors. However the extra spot colors will not be imaged
653 * unless they are selected by the SeparationOrder parameter. (This does
654 * allow the user to create more than 8 separations by a making multiple
655 * passes and using the SeparationOrder parameter.)
656 */
657 private int
number_output_separations(int num_dev_comp,int num_std_colorants,int num_order,int num_spot)658 number_output_separations(int num_dev_comp, int num_std_colorants,
659 int num_order, int num_spot)
660 {
661 int num_comp = num_std_colorants + num_spot;
662
663 if (num_comp > num_dev_comp)
664 num_comp = num_dev_comp;
665 if (num_order)
666 num_comp = num_order;
667 return num_comp;
668 }
669
670 /*
671 * This routine creates a list to map the component number to a separation number.
672 * Values less than 4 refer to the CMYK colorants. Higher values refer to a
673 * separation number.
674 *
675 * This is the inverse of the separation_order_map.
676 */
677 private void
build_comp_to_sep_map(tiffsep_device * pdev,short * map_comp_to_sep)678 build_comp_to_sep_map(tiffsep_device * pdev, short * map_comp_to_sep)
679 {
680 int num_sep = pdev->devn_params.separations.num_separations;
681 int num_std_colorants = pdev->devn_params.num_std_colorant_names;
682 int sep_num;
683
684 for (sep_num = 0; sep_num < num_std_colorants + num_sep; sep_num++) {
685 int comp_num = pdev->devn_params.separation_order_map[sep_num];
686
687 if (comp_num >= 0 && comp_num < GX_DEVICE_COLOR_MAX_COMPONENTS)
688 map_comp_to_sep[comp_num] = sep_num;
689 }
690 }
691
692 /* Open the tiffsep device */
693 int
tiffsep_prn_open(gx_device * pdev)694 tiffsep_prn_open(gx_device * pdev)
695 {
696 int code = gdev_prn_open(pdev);
697
698 set_linear_color_bits_mask_shift(pdev);
699 pdev->color_info.separable_and_linear = GX_CINFO_SEP_LIN;
700 return code;
701 }
702
703 /* Close the tiffsep device */
704 int
tiffsep_prn_close(gx_device * pdev)705 tiffsep_prn_close(gx_device * pdev)
706 {
707 tiffsep_device * const pdevn = (tiffsep_device *) pdev;
708 int num_dev_comp = pdevn->color_info.num_components;
709 int num_std_colorants = pdevn->devn_params.num_std_colorant_names;
710 int num_order = pdevn->devn_params.num_separation_order_names;
711 int num_spot = pdevn->devn_params.separations.num_separations;
712 char name[MAX_FILE_NAME_SIZE];
713 int code = gdev_prn_close(pdev);
714 short map_comp_to_sep[GX_DEVICE_COLOR_MAX_COMPONENTS];
715 int comp_num;
716 int num_comp = number_output_separations(num_dev_comp, num_std_colorants,
717 num_order, num_spot);
718
719 if (code < 0)
720 return code;
721 build_comp_to_sep_map(pdevn, map_comp_to_sep);
722 /* Close the separation files */
723 for (comp_num = 0; comp_num < num_comp; comp_num++ ) {
724 if (pdevn->sep_file[comp_num] != NULL) {
725 int sep_num = map_comp_to_sep[comp_num];
726
727 code = create_separation_file_name(pdevn, name,
728 MAX_FILE_NAME_SIZE, sep_num);
729 if (code < 0)
730 return code;
731 code = gx_device_close_output_file(pdev, name,
732 pdevn->sep_file[comp_num]);
733 if (code < 0)
734 return code;
735 pdevn->sep_file[comp_num] = NULL;
736 }
737 }
738 return 0;
739 }
740
741 /*
742 * Element for a map to convert colorants to a CMYK color.
743 */
744 typedef struct cmyk_composite_map_s {
745 frac c, m, y, k;
746 } cmyk_composite_map;
747
748 /*
749 * Build the map to be used to create a CMYK equivalent to the current
750 * device components.
751 */
752 private void
build_cmyk_map(tiffsep_device * pdev,int num_comp,short * map_comp_to_sep,cmyk_composite_map * cmyk_map)753 build_cmyk_map(tiffsep_device * pdev, int num_comp,
754 short *map_comp_to_sep, cmyk_composite_map * cmyk_map)
755 {
756 int comp_num;
757
758 for (comp_num = 0; comp_num < num_comp; comp_num++ ) {
759 int sep_num = map_comp_to_sep[comp_num];
760
761 cmyk_map[comp_num].c = cmyk_map[comp_num].m =
762 cmyk_map[comp_num].y = cmyk_map[comp_num].k = frac_0;
763 /* The tiffsep device has 4 standard colors: CMYK */
764 if (sep_num < pdev->devn_params.num_std_colorant_names) {
765 switch (sep_num) {
766 case 0: cmyk_map[comp_num].c = frac_1; break;
767 case 1: cmyk_map[comp_num].m = frac_1; break;
768 case 2: cmyk_map[comp_num].y = frac_1; break;
769 case 3: cmyk_map[comp_num].k = frac_1; break;
770 }
771 }
772 else {
773 sep_num -= pdev->devn_params.num_std_colorant_names;
774 if (pdev->equiv_cmyk_colors.color[sep_num].color_info_valid) {
775 cmyk_map[comp_num].c = pdev->equiv_cmyk_colors.color[sep_num].c;
776 cmyk_map[comp_num].m = pdev->equiv_cmyk_colors.color[sep_num].m;
777 cmyk_map[comp_num].y = pdev->equiv_cmyk_colors.color[sep_num].y;
778 cmyk_map[comp_num].k = pdev->equiv_cmyk_colors.color[sep_num].k;
779 }
780 }
781 }
782 }
783
784 /*
785 * Build a CMYK equivalent to a raster line.
786 */
787 private void
build_cmyk_raster_line(byte * src,byte * dest,int width,int num_comp,int pixel_size,cmyk_composite_map * cmyk_map)788 build_cmyk_raster_line(byte * src, byte * dest, int width,
789 int num_comp, int pixel_size, cmyk_composite_map * cmyk_map)
790 {
791 int pixel, comp_num;
792 uint temp, cyan, magenta, yellow, black;
793 cmyk_composite_map * cmyk_map_entry;
794
795 for (pixel = 0; pixel < width; pixel++) {
796 cmyk_map_entry = cmyk_map;
797 temp = *src++;
798 cyan = cmyk_map_entry->c * temp;
799 magenta = cmyk_map_entry->m * temp;
800 yellow = cmyk_map_entry->y * temp;
801 black = cmyk_map_entry->k * temp;
802 cmyk_map_entry++;
803 for (comp_num = 1; comp_num < num_comp; comp_num++) {
804 temp = *src++;
805 cyan += cmyk_map_entry->c * temp;
806 magenta += cmyk_map_entry->m * temp;
807 yellow += cmyk_map_entry->y * temp;
808 black += cmyk_map_entry->k * temp;
809 cmyk_map_entry++;
810 }
811 src += pixel_size - num_comp;
812 cyan /= frac_1;
813 magenta /= frac_1;
814 yellow /= frac_1;
815 black /= frac_1;
816 if (cyan > MAX_COLOR_VALUE)
817 cyan = MAX_COLOR_VALUE;
818 if (magenta > MAX_COLOR_VALUE)
819 magenta = MAX_COLOR_VALUE;
820 if (yellow > MAX_COLOR_VALUE)
821 yellow = MAX_COLOR_VALUE;
822 if (black > MAX_COLOR_VALUE)
823 black = MAX_COLOR_VALUE;
824 *dest++ = cyan;
825 *dest++ = magenta;
826 *dest++ = yellow;
827 *dest++ = black;
828 }
829 }
830
831 /*
832 * Output the image data for the tiff separation (tiffsep) device. The data
833 * for the tiffsep device is written in separate planes to separate files.
834 *
835 * The DeviceN parameters (SeparationOrder, SeparationColorNames, and
836 * MaxSeparations) are applied to the tiffsep device.
837 */
838 private int
tiffsep_print_page(gx_device_printer * pdev,FILE * file)839 tiffsep_print_page(gx_device_printer * pdev, FILE * file)
840 {
841 tiffsep_device * const tfdev = (tiffsep_device *)pdev;
842 int num_std_colorants = tfdev->devn_params.num_std_colorant_names;
843 int num_order = tfdev->devn_params.num_separation_order_names;
844 int num_spot = tfdev->devn_params.separations.num_separations;
845 int num_comp, comp_num, sep_num, code = 0;
846 short map_comp_to_sep[GX_DEVICE_COLOR_MAX_COMPONENTS];
847 cmyk_composite_map cmyk_map[GX_DEVICE_COLOR_MAX_COMPONENTS];
848 char name[MAX_FILE_NAME_SIZE];
849 int base_filename_length = strlen(pdev->fname);
850 int save_depth = pdev->color_info.depth;
851 const char *fmt;
852 gs_parsed_file_name_t parsed;
853
854 build_comp_to_sep_map(tfdev, map_comp_to_sep);
855
856 /* Print the names of the spot colors */
857 for (sep_num = 0; sep_num < num_spot; sep_num++) {
858 copy_separation_name(tfdev, name,
859 MAX_FILE_NAME_SIZE - base_filename_length - SUFFIX_SIZE, sep_num);
860 dlprintf1("%%%%SeparationName: %s\n", name);
861 }
862
863 /*
864 * Check if the file name has a numeric format. If so then we want to
865 * create individual separation files for each page of the input.
866 */
867 code = gx_parse_output_file_name(&parsed, &fmt,
868 tfdev->fname, strlen(tfdev->fname));
869
870 /* Write the page directory for the CMYK equivalent file. */
871 pdev->color_info.depth = 32; /* Create directory for 32 bit cmyk */
872 code = gdev_tiff_begin_page(pdev, &tfdev->tiff_comp, file,
873 (const TIFF_dir_entry *)&dir_cmyk_template,
874 sizeof(dir_cmyk_template) / sizeof(TIFF_dir_entry),
875 (const byte *)&val_cmyk_template,
876 sizeof(val_cmyk_template), 0);
877 pdev->color_info.depth = save_depth;
878 if (code < 0)
879 return code;
880
881 /* Set up the separation output files */
882 num_comp = number_output_separations( tfdev->color_info.num_components,
883 num_std_colorants, num_order, num_spot);
884 for (comp_num = 0; comp_num < num_comp; comp_num++ ) {
885 int sep_num = map_comp_to_sep[comp_num];
886
887 code = create_separation_file_name(tfdev, name,
888 MAX_FILE_NAME_SIZE, sep_num);
889 if (code < 0)
890 return code;
891 /*
892 * Close the old separation file if we are creating individual files
893 * for each page.
894 */
895 if (tfdev->sep_file[comp_num] != NULL && fmt != NULL) {
896 code = gx_device_close_output_file((const gx_device *)tfdev, name,
897 tfdev->sep_file[comp_num]);
898 if (code < 0)
899 return code;
900 tfdev->sep_file[comp_num] = NULL;
901 }
902 /* Open the separation file, if not already open */
903 if (tfdev->sep_file[comp_num] == NULL) {
904 code = gx_device_open_output_file((gx_device *)pdev, name,
905 true, false, &(tfdev->sep_file[comp_num]));
906 if (code < 0)
907 return code;
908 }
909
910 /* Write the page directory. */
911 pdev->color_info.depth = 8; /* Create files for 8 bit gray */
912 code = gdev_tiff_begin_page(pdev, &(tfdev->tiff[comp_num]),
913 tfdev->sep_file[comp_num],
914 (const TIFF_dir_entry *)&dir_gray_template,
915 sizeof(dir_gray_template) / sizeof(TIFF_dir_entry),
916 (const byte *)&val_gray_template,
917 sizeof(val_gray_template), 0);
918 pdev->color_info.depth = save_depth;
919 if (code < 0)
920 return code;
921 }
922
923 build_cmyk_map(tfdev, num_comp, map_comp_to_sep, cmyk_map);
924
925 {
926 int raster = gdev_prn_raster(pdev);
927 int width = tfdev->width;
928 int cmyk_raster = width * NUM_CMYK_COMPONENTS;
929 int bytes_pp = tfdev->color_info.num_components;
930 int pixel, y;
931 byte * line = gs_alloc_bytes(pdev->memory, raster, "tiffsep_print_page");
932 byte * sep_line;
933 byte * row;
934
935 if (line == NULL)
936 return_error(gs_error_VMerror);
937 sep_line =
938 gs_alloc_bytes(pdev->memory, cmyk_raster, "tiffsep_print_page");
939 if (sep_line == NULL) {
940 gs_free_object(pdev->memory, line, "tiffsep_print_page");
941 return_error(gs_error_VMerror);
942 }
943
944 /* Write the page data. */
945 for (y = 0; y < pdev->height; ++y) {
946 code = gdev_prn_get_bits(pdev, y, line, &row);
947 if (code < 0)
948 break;
949 /* Write separation data (tiffgray format) */
950 for (comp_num = 0; comp_num < num_comp; comp_num++ ) {
951 byte * src = row + comp_num;
952 byte * dest = sep_line;
953
954 for (pixel = 0; pixel < width; pixel++, dest++, src += bytes_pp)
955 *dest = MAX_COLOR_VALUE - *src; /* Gray is additive */
956 fwrite((char *)sep_line, width, 1, tfdev->sep_file[comp_num]);
957 }
958 /* Write CMYK equivalent data (tiff32nc format) */
959 build_cmyk_raster_line(row, sep_line, width,
960 num_comp, bytes_pp, cmyk_map);
961 fwrite((char *)sep_line, cmyk_raster, 1, file);
962 }
963 /* Update the strip data */
964 gdev_tiff_end_strip(&(tfdev->tiff_comp), file);
965 gdev_tiff_end_page(&(tfdev->tiff_comp), file);
966 for (comp_num = 0; comp_num < num_comp; comp_num++ ) {
967 gdev_tiff_end_strip(&(tfdev->tiff[comp_num]),
968 tfdev->sep_file[comp_num]);
969 gdev_tiff_end_page(&(tfdev->tiff[comp_num]),
970 tfdev->sep_file[comp_num]);
971 }
972 gs_free_object(pdev->memory, line, "tiffsep_print_page");
973 gs_free_object(pdev->memory, sep_line, "tiffsep_print_page");
974 }
975
976 return code;
977 }
978