xref: /plan9/sys/src/cmd/gs/src/gdevtsep.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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