1 /* Copyright (C) 2001-2006 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, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 
14 /* $Id: gdevtsep.c 10710 2010-02-04 17:47:57Z larsu $ */
15 /* tiffgray device:  8-bit Gray uncompressed TIFF device */
16 /* tiff32nc device:  32-bit CMYK uncompressed TIFF device */
17 /* tiffsep device: Generate individual TIFF gray files for each separation */
18 /*                 as well as a 'composite' 32-bit CMYK for the page.      */
19 /* tiffsep1 device: Generate individual TIFF 1-bit files for each separation. */
20 
21 #include "gdevtifs.h"
22 #include "gdevprn.h"
23 #include "gdevdevn.h"
24 #include "gsequivc.h"
25 #include "gxdht.h"
26 #include "gxiodev.h"
27 #include "stdio_.h"
28 #include "ctype_.h"
29 
30 /*
31  * Some of the code in this module is based upon the gdevtfnx.c module.
32  * gdevtfnx.c has the following message:
33  * Thanks to Alan Barclay <alan@escribe.co.uk> for donating the original
34  * version of this code to Ghostscript.
35  */
36 
37 /* ------ The device descriptors ------ */
38 
39 /* Default X and Y resolution */
40 #define X_DPI 72
41 #define Y_DPI 72
42 
43 /* ------ The tiffgray device ------ */
44 
45 static dev_proc_print_page(tiffgray_print_page);
46 
47 static const gx_device_procs tiffgray_procs =
48 prn_color_params_procs(tiff_open, tiff_output_page, tiff_close,
49 		gx_default_gray_map_rgb_color, gx_default_gray_map_color_rgb,
50 		tiff_get_params, tiff_put_params);
51 
52 const gx_device_tiff gs_tiffgray_device = {
53     prn_device_body(gx_device_tiff, tiffgray_procs, "tiffgray",
54 		    DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
55 		    X_DPI, Y_DPI,
56 		    0, 0, 0, 0,	/* Margins */
57 		    1, 8, 255, 0, 256, 0, tiffgray_print_page),
58     arch_is_big_endian          /* default to native endian (i.e. use big endian iff the platform is so*/,
59     COMPRESSION_NONE,
60     TIFF_DEFAULT_STRIP_SIZE
61 };
62 
63 
64 /* ------ Private functions ------ */
65 
66 static void
tiff_set_gray_fields(gx_device_printer * pdev,TIFF * tif,unsigned short bits_per_sample,int compression,long max_strip_size)67 tiff_set_gray_fields(gx_device_printer *pdev, TIFF *tif,
68 		     unsigned short bits_per_sample,
69 		     int compression,
70 		     long max_strip_size)
71 {
72     TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bits_per_sample);
73     TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
74     TIFFSetField(tif, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
75     TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
76 
77     tiff_set_compression(pdev, tif, compression, max_strip_size);
78 }
79 
80 static int
tiffgray_print_page(gx_device_printer * pdev,FILE * file)81 tiffgray_print_page(gx_device_printer * pdev, FILE * file)
82 {
83     gx_device_tiff *const tfdev = (gx_device_tiff *)pdev;
84     int code;
85 
86     if (pdev->height > (max_long - ftell(file))/(pdev->width)) /* note width is never 0 in print_page */
87 	return_error(gs_error_rangecheck);  /* this will overflow max_long */
88 
89     code = gdev_tiff_begin_page(tfdev, file);
90     if (code < 0)
91 	return code;
92 
93     tiff_set_gray_fields(pdev, tfdev->tif, 8, tfdev->Compression, tfdev->MaxStripSize);
94 
95     return tiff_print_page(pdev, tfdev->tif);
96 }
97 
98 /* ------ The cmyk devices ------ */
99 
100 static dev_proc_print_page(tiffcmyk_print_page);
101 
102 #define cmyk_procs(p_map_color_rgb, p_map_cmyk_color)\
103     tiff_open, NULL, NULL, tiff_output_page, tiff_close,\
104     NULL, p_map_color_rgb, NULL, NULL, NULL, NULL, NULL, NULL,\
105     tiff_get_params, tiff_put_params,\
106     p_map_cmyk_color, NULL, NULL, NULL, gx_page_device_get_page_device
107 
108 /* 8-bit-per-plane separated CMYK color. */
109 
110 static const gx_device_procs tiffcmyk_procs = {
111     cmyk_procs(cmyk_8bit_map_color_cmyk, cmyk_8bit_map_cmyk_color)
112 };
113 
114 const gx_device_tiff gs_tiff32nc_device = {
115     prn_device_body(gx_device_tiff, tiffcmyk_procs, "tiff32nc",
116 		    DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
117 		    X_DPI, Y_DPI,
118 		    0, 0, 0, 0,	/* Margins */
119 		    4, 32, 255, 255, 256, 256, tiffcmyk_print_page),
120     arch_is_big_endian          /* default to native endian (i.e. use big endian iff the platform is so*/,
121     COMPRESSION_NONE,
122     TIFF_DEFAULT_STRIP_SIZE
123 };
124 
125 /* 16-bit-per-plane separated CMYK color. */
126 
127 static const gx_device_procs tiff64nc_procs = {
128     cmyk_procs(cmyk_16bit_map_color_cmyk, cmyk_16bit_map_cmyk_color)
129 };
130 
131 const gx_device_tiff gs_tiff64nc_device = {
132     prn_device_body(gx_device_tiff, tiff64nc_procs, "tiff64nc",
133 		    DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
134 		    X_DPI, Y_DPI,
135 		    0, 0, 0, 0,	/* Margins */
136 		    4, 64, 255, 255, 256, 256, tiffcmyk_print_page),
137     arch_is_big_endian          /* default to native endian (i.e. use big endian iff the platform is so*/,
138     COMPRESSION_NONE,
139     TIFF_DEFAULT_STRIP_SIZE
140 };
141 
142 /* ------ Private functions ------ */
143 
144 static void
tiff_set_cmyk_fields(gx_device_printer * pdev,TIFF * tif,short bits_per_sample,uint16 compression,long max_strip_size)145 tiff_set_cmyk_fields(gx_device_printer *pdev, TIFF *tif,
146 		     short bits_per_sample,
147 		     uint16 compression,
148 		     long max_strip_size)
149 {
150     TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bits_per_sample);
151     TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_SEPARATED);
152     TIFFSetField(tif, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
153     TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 4);
154 
155     tiff_set_compression(pdev, tif, compression, max_strip_size);
156 }
157 
158 static int
tiffcmyk_print_page(gx_device_printer * pdev,FILE * file)159 tiffcmyk_print_page(gx_device_printer * pdev, FILE * file)
160 {
161     gx_device_tiff *const tfdev = (gx_device_tiff *)pdev;
162     int code;
163 
164     if (pdev->height > (max_long - ftell(file))/(pdev->width)) /* note width is never 0 in print_page */
165 	return_error(gs_error_rangecheck);  /* this will overflow max_long */
166 
167     code = gdev_tiff_begin_page(tfdev, file);
168     if (code < 0)
169 	return code;
170 
171     tiff_set_cmyk_fields(pdev,
172 			 tfdev->tif,
173 			 pdev->color_info.depth / pdev->color_info.num_components,
174 			 tfdev->Compression,
175 			 tfdev->MaxStripSize);
176 
177     return tiff_print_page(pdev, tfdev->tif);
178 }
179 
180 /* ----------  The tiffsep device ------------ */
181 
182 #define NUM_CMYK_COMPONENTS 4
183 #define MAX_FILE_NAME_SIZE gp_file_name_sizeof
184 #define MAX_COLOR_VALUE	255		/* We are using 8 bits per colorant */
185 
186 /* The device descriptor */
187 static dev_proc_open_device(tiffsep_prn_open);
188 static dev_proc_close_device(tiffsep_prn_close);
189 static dev_proc_get_params(tiffsep_get_params);
190 static dev_proc_put_params(tiffsep_put_params);
191 static dev_proc_print_page(tiffsep_print_page);
192 static dev_proc_get_color_mapping_procs(tiffsep_get_color_mapping_procs);
193 static dev_proc_get_color_comp_index(tiffsep_get_color_comp_index);
194 static dev_proc_encode_color(tiffsep_encode_color);
195 static dev_proc_decode_color(tiffsep_decode_color);
196 static dev_proc_encode_color(tiffsep_encode_compressed_color);
197 static dev_proc_decode_color(tiffsep_decode_compressed_color);
198 static dev_proc_update_spot_equivalent_colors(tiffsep_update_spot_equivalent_colors);
199 static dev_proc_ret_devn_params(tiffsep_ret_devn_params);
200 static dev_proc_open_device(tiffsep1_prn_open);
201 static dev_proc_close_device(tiffsep1_prn_close);
202 static dev_proc_put_params(tiffsep1_put_params);
203 static dev_proc_print_page(tiffsep1_print_page);
204 static dev_proc_fill_path(sep1_fill_path);
205 
206 #define tiffsep_devices_common\
207     gx_device_common;\
208     gx_prn_device_common;\
209 	/* tiff state for separation files */\
210     FILE *sep_file[GX_DEVICE_COLOR_MAX_COMPONENTS];\
211     TIFF *tiff[GX_DEVICE_COLOR_MAX_COMPONENTS]; \
212     bool  BigEndian;            /* true = big endian; false = little endian */\
213     uint16 Compression;		/* for the separation files, same values as
214 				   TIFFTAG_COMPRESSION */\
215     long MaxStripSize;\
216     gs_devn_params devn_params;		/* DeviceN generated parameters */\
217     equivalent_cmyk_color_params equiv_cmyk_colors
218 
219 /*
220  * A structure definition for a DeviceN type device
221  */
222 typedef struct tiffsep_device_s {
223     tiffsep_devices_common;
224     TIFF *tiff_comp;		/* tiff file for comp file */
225 } tiffsep_device;
226 
227 /* threshold array structure */
228 typedef struct threshold_array_s {
229       int dheight, dwidth;
230       byte *dstart;
231 } threshold_array_t;
232 
233 typedef struct tiffsep1_device_s {
234     tiffsep_devices_common;
235     threshold_array_t thresholds[GX_DEVICE_COLOR_MAX_COMPONENTS + 1]; /* one extra for Default */
236     dev_t_proc_fill_path((*fill_path), gx_device); /* we forward to here */
237 } tiffsep1_device;
238 
239 /* GC procedures */
240 static
ENUM_PTRS_WITH(tiffsep_device_enum_ptrs,tiffsep_device * pdev)241 ENUM_PTRS_WITH(tiffsep_device_enum_ptrs, tiffsep_device *pdev)
242 {
243     if (index == 0)
244 	ENUM_RETURN(pdev->devn_params.compressed_color_list);
245     index--;
246     if (index < pdev->devn_params.separations.num_separations)
247 	ENUM_RETURN(pdev->devn_params.separations.names[index].data);
248     ENUM_PREFIX(st_device_printer,
249 		    pdev->devn_params.separations.num_separations);
250     return 0;
251 }
252 ENUM_PTRS_END
253 
RELOC_PTRS_WITH(tiffsep_device_reloc_ptrs,tiffsep_device * pdev)254 static RELOC_PTRS_WITH(tiffsep_device_reloc_ptrs, tiffsep_device *pdev)
255 {
256     RELOC_PREFIX(st_device_printer);
257     {
258 	int i;
259 
260 	for (i = 0; i < pdev->devn_params.separations.num_separations; ++i) {
261 	    RELOC_PTR(tiffsep_device, devn_params.separations.names[i].data);
262 	}
263     }
264     RELOC_PTR(tiffsep_device, devn_params.compressed_color_list);
265 }
266 RELOC_PTRS_END
267 
268 /* Even though tiffsep_device_finalize is the same as gx_device_finalize, */
269 /* we need to implement it separately because st_composite_final */
270 /* declares all 3 procedures as private. */
271 static void
tiffsep_device_finalize(void * vpdev)272 tiffsep_device_finalize(void *vpdev)
273 {
274     gx_device_finalize(vpdev);
275 }
276 
277 gs_private_st_composite_final(st_tiffsep_device, tiffsep_device,
278     "tiffsep_device", tiffsep_device_enum_ptrs, tiffsep_device_reloc_ptrs,
279     tiffsep_device_finalize);
280 
281 /*
282  * Macro definition for tiffsep device procedures
283  */
284 #define sep_device_procs(open, close, encode_color, decode_color, update_spot_colors,put_params, fill_path) \
285 {	open,\
286 	gx_default_get_initial_matrix,\
287 	NULL,				/* sync_output */\
288 	gdev_prn_output_page,		/* output_page */\
289 	close,				/* close */\
290 	NULL,				/* map_rgb_color - not used */\
291 	tiffsep_decode_color,		/* map_color_rgb */\
292 	NULL,				/* fill_rectangle */\
293 	NULL,				/* tile_rectangle */\
294 	NULL,				/* copy_mono */\
295 	NULL,				/* copy_color */\
296 	NULL,				/* draw_line */\
297 	NULL,				/* get_bits */\
298 	tiffsep_get_params,		/* get_params */\
299 	put_params,			/* put_params */\
300 	NULL,				/* map_cmyk_color - not used */\
301 	NULL,				/* get_xfont_procs */\
302 	NULL,				/* get_xfont_device */\
303 	NULL,				/* map_rgb_alpha_color */\
304 	gx_page_device_get_page_device,	/* get_page_device */\
305 	NULL,				/* get_alpha_bits */\
306 	NULL,				/* copy_alpha */\
307 	NULL,				/* get_band */\
308 	NULL,				/* copy_rop */\
309 	fill_path,			/* fill_path */\
310 	NULL,				/* stroke_path */\
311 	NULL,				/* fill_mask */\
312 	NULL,				/* fill_trapezoid */\
313 	NULL,				/* fill_parallelogram */\
314 	NULL,				/* fill_triangle */\
315 	NULL,				/* draw_thin_line */\
316 	NULL,				/* begin_image */\
317 	NULL,				/* image_data */\
318 	NULL,				/* end_image */\
319 	NULL,				/* strip_tile_rectangle */\
320 	NULL,				/* strip_copy_rop */\
321 	NULL,				/* get_clipping_box */\
322 	NULL,				/* begin_typed_image */\
323 	NULL,				/* get_bits_rectangle */\
324 	NULL,				/* map_color_rgb_alpha */\
325 	NULL,				/* create_compositor */\
326 	NULL,				/* get_hardware_params */\
327 	NULL,				/* text_begin */\
328 	NULL,				/* finish_copydevice */\
329 	NULL,				/* begin_transparency_group */\
330 	NULL,				/* end_transparency_group */\
331 	NULL,				/* begin_transparency_mask */\
332 	NULL,				/* end_transparency_mask */\
333 	NULL,				/* discard_transparency_layer */\
334 	tiffsep_get_color_mapping_procs,/* get_color_mapping_procs */\
335 	tiffsep_get_color_comp_index,	/* get_color_comp_index */\
336 	encode_color,			/* encode_color */\
337 	decode_color,			/* decode_color */\
338 	NULL,				/* pattern_manage */\
339 	NULL,				/* fill_rectangle_hl_color */\
340 	NULL,				/* include_color_space */\
341 	NULL,				/* fill_linear_color_scanline */\
342 	NULL,				/* fill_linear_color_trapezoid */\
343 	NULL,				/* fill_linear_color_triangle */\
344 	update_spot_colors,		/* update_spot_equivalent_colors */\
345 	tiffsep_ret_devn_params		/* ret_devn_params */\
346 }
347 
348 
349 #define tiffsep_devices_body(dtype, procs, dname, ncomp, pol, depth, mg, mc, sl, cn, print_page, compr)\
350     std_device_full_body_type_extended(dtype, &procs, dname,\
351 	  &st_tiffsep_device,\
352 	  (int)((long)(DEFAULT_WIDTH_10THS) * (X_DPI) / 10),\
353 	  (int)((long)(DEFAULT_HEIGHT_10THS) * (Y_DPI) / 10),\
354 	  X_DPI, Y_DPI,\
355     	  ncomp,		/* MaxComponents */\
356 	  ncomp,		/* NumComp */\
357 	  pol,			/* Polarity */\
358 	  depth, 0,		/* Depth, GrayIndex */\
359 	  mg, mc,		/* MaxGray, MaxColor */\
360 	  mg + 1, mc + 1,	/* DitherGray, DitherColor */\
361 	  sl,			/* Linear & Separable? */\
362 	  cn,			/* Process color model name */\
363 	  0, 0,			/* offsets */\
364 	  0, 0, 0, 0		/* margins */\
365 	),\
366 	prn_device_body_rest_(print_page),\
367 	{ 0 },			/* tiff state for separation files */\
368 	{ 0 },			/* separation files */\
369 	arch_is_big_endian      /* true = big endian; false = little endian */,\
370 	compr			/* COMPRESSION_* */,\
371 	TIFF_DEFAULT_STRIP_SIZE	/* MaxStripSize */
372 
373 /*
374  * Select the default number of components based upon the number of bits
375  * that we have in a gx_color_index.  If we have 64 bits then we can compress
376  * the colorant data.  This allows us to handle more colorants.  However the
377  * compressed encoding is not separable.  If we do not have 64 bits then we
378  * use a simple non-compressable encoding.
379  */
380 #if USE_COMPRESSED_ENCODING
381 #   define NC GX_DEVICE_COLOR_MAX_COMPONENTS
382 #   define SL GX_CINFO_SEP_LIN_NONE
383 #   define ENCODE_COLOR tiffsep_encode_compressed_color
384 #   define DECODE_COLOR tiffsep_decode_compressed_color
385 #else
386 #   define NC ARCH_SIZEOF_GX_COLOR_INDEX
387 #   define SL GX_CINFO_SEP_LIN
388 #   define ENCODE_COLOR tiffsep_encode_color
389 #   define DECODE_COLOR tiffsep_decode_color
390 #endif
391 #define GCIB (ARCH_SIZEOF_GX_COLOR_INDEX * 8)
392 
393 /*
394  * TIFF devices with CMYK process color model and spot color support.
395  */
396 static const gx_device_procs spot_cmyk_procs =
397 		sep_device_procs(tiffsep_prn_open, tiffsep_prn_close, ENCODE_COLOR, DECODE_COLOR,
398 				tiffsep_update_spot_equivalent_colors, tiffsep_put_params, NULL);
399 
400 static const gx_device_procs spot1_cmyk_procs =
401 		sep_device_procs(tiffsep1_prn_open, tiffsep1_prn_close, ENCODE_COLOR, DECODE_COLOR,
402 				tiffsep_update_spot_equivalent_colors, tiffsep1_put_params, sep1_fill_path);
403 
404 const tiffsep_device gs_tiffsep_device =
405 {
406     tiffsep_devices_body(tiffsep_device, spot_cmyk_procs, "tiffsep", NC, GX_CINFO_POLARITY_SUBTRACTIVE, GCIB, MAX_COLOR_VALUE, MAX_COLOR_VALUE, SL, "DeviceCMYK", tiffsep_print_page, COMPRESSION_LZW),
407     /* devn_params specific parameters */
408     { 8,			/* Not used - Bits per color */
409       DeviceCMYKComponents,	/* Names of color model colorants */
410       4,			/* Number colorants for CMYK */
411       0,			/* MaxSeparations has not been specified */
412       -1,			/* PageSpotColors has not been specified */
413       {0},			/* SeparationNames */
414       0,			/* SeparationOrder names */
415       {0, 1, 2, 3, 4, 5, 6, 7 }	/* Initial component SeparationOrder */
416     },
417     { true },			/* equivalent CMYK colors for spot colors */
418 };
419 
420 const tiffsep1_device gs_tiffsep1_device =
421 {
422     tiffsep_devices_body(tiffsep1_device, spot1_cmyk_procs, "tiffsep1", NC, GX_CINFO_POLARITY_SUBTRACTIVE, GCIB, MAX_COLOR_VALUE, MAX_COLOR_VALUE, SL, "DeviceCMYK", tiffsep1_print_page, COMPRESSION_CCITTFAX4),
423     /* devn_params specific parameters */
424     { 1,			/* Not used - Bits per color */
425       DeviceCMYKComponents,	/* Names of color model colorants */
426       4,			/* Number colorants for CMYK */
427       0,			/* MaxSeparations has not been specified */
428       -1,			/* PageSpotColors has not been specified */
429       {0},			/* SeparationNames */
430       0,			/* SeparationOrder names */
431       {0, 1, 2, 3, 4, 5, 6, 7 }	/* Initial component SeparationOrder */
432     },
433     { true },			/* equivalent CMYK colors for spot colors */
434     { {0} },			/* threshold arrays */
435     0, 				/* fill_path */
436 };
437 
438 #undef NC
439 #undef SL
440 #undef ENCODE_COLOR
441 #undef DECODE_COLOR
442 
443 static const uint32_t bit_order[32]={
444 #if arch_is_big_endian
445 	0x80000000, 0x40000000, 0x20000000, 0x10000000,	0x08000000, 0x04000000, 0x02000000, 0x01000000,
446 	0x00800000, 0x00400000, 0x00200000, 0x00100000,	0x00080000, 0x00040000, 0x00020000, 0x00010000,
447 	0x00008000, 0x00004000, 0x00002000, 0x00001000,	0x00000800, 0x00000400, 0x00000200, 0x00000100,
448 	0x00000080, 0x00000040, 0x00000020, 0x00000010,	0x00000008, 0x00000004, 0x00000002, 0x00000001
449 #else
450 	0x00000080, 0x00000040, 0x00000020, 0x00000010,	0x00000008, 0x00000004, 0x00000002, 0x00000001,
451 	0x00008000, 0x00004000, 0x00002000, 0x00001000,	0x00000800, 0x00000400, 0x00000200, 0x00000100,
452 	0x00800000, 0x00400000, 0x00200000, 0x00100000,	0x00080000, 0x00040000, 0x00020000, 0x00010000,
453 	0x80000000, 0x40000000, 0x20000000, 0x10000000,	0x08000000, 0x04000000, 0x02000000, 0x01000000
454 #endif
455     };
456 
457 /*
458  * The following procedures are used to map the standard color spaces into
459  * the color components for the tiffsep device.
460  */
461 static void
tiffsep_gray_cs_to_cm(gx_device * dev,frac gray,frac out[])462 tiffsep_gray_cs_to_cm(gx_device * dev, frac gray, frac out[])
463 {
464     int * map = ((tiffsep_device *) dev)->devn_params.separation_order_map;
465 
466     gray_cs_to_devn_cm(dev, map, gray, out);
467 }
468 
469 static void
tiffsep_rgb_cs_to_cm(gx_device * dev,const gs_imager_state * pis,frac r,frac g,frac b,frac out[])470 tiffsep_rgb_cs_to_cm(gx_device * dev, const gs_imager_state *pis,
471 				   frac r, frac g, frac b, frac out[])
472 {
473     int * map = ((tiffsep_device *) dev)->devn_params.separation_order_map;
474 
475     rgb_cs_to_devn_cm(dev, map, pis, r, g, b, out);
476 }
477 
478 static void
tiffsep_cmyk_cs_to_cm(gx_device * dev,frac c,frac m,frac y,frac k,frac out[])479 tiffsep_cmyk_cs_to_cm(gx_device * dev,
480 		frac c, frac m, frac y, frac k, frac out[])
481 {
482     int * map = ((tiffsep_device *) dev)->devn_params.separation_order_map;
483 
484     cmyk_cs_to_devn_cm(dev, map, c, m, y, k, out);
485 }
486 
487 static const gx_cm_color_map_procs tiffsep_cm_procs = {
488     tiffsep_gray_cs_to_cm,
489     tiffsep_rgb_cs_to_cm,
490     tiffsep_cmyk_cs_to_cm
491 };
492 
493 /*
494  * These are the handlers for returning the list of color space
495  * to color model conversion routines.
496  */
497 static const gx_cm_color_map_procs *
tiffsep_get_color_mapping_procs(const gx_device * dev)498 tiffsep_get_color_mapping_procs(const gx_device * dev)
499 {
500     return &tiffsep_cm_procs;
501 }
502 
503 /*
504  * Encode a list of colorant values into a gx_color_index_value.
505  * With 64 bit gx_color_index values, we compress the colorant values.  This
506  * allows us to handle more than 8 colorants.
507  */
508 static gx_color_index
tiffsep_encode_compressed_color(gx_device * dev,const gx_color_value colors[])509 tiffsep_encode_compressed_color(gx_device *dev, const gx_color_value colors[])
510 {
511     return devn_encode_compressed_color(dev, colors, &(((tiffsep_device *)dev)->devn_params));
512 }
513 
514 /*
515  * Decode a gx_color_index value back to a list of colorant values.
516  * With 64 bit gx_color_index values, we compress the colorant values.  This
517  * allows us to handle more than 8 colorants.
518  */
519 static int
tiffsep_decode_compressed_color(gx_device * dev,gx_color_index color,gx_color_value * out)520 tiffsep_decode_compressed_color(gx_device * dev, gx_color_index color, gx_color_value * out)
521 {
522     return devn_decode_compressed_color(dev, color, out,
523 		    &(((tiffsep_device *)dev)->devn_params));
524 }
525 
526 /*
527  * Encode a list of colorant values into a gx_color_index_value.
528  * With 32 bit gx_color_index values, we simply pack values.
529  */
530 static gx_color_index
tiffsep_encode_color(gx_device * dev,const gx_color_value colors[])531 tiffsep_encode_color(gx_device *dev, const gx_color_value colors[])
532 {
533     int bpc = ((tiffsep_device *)dev)->devn_params.bitspercomponent;
534     int drop = sizeof(gx_color_value) * 8 - bpc;
535     gx_color_index color = 0;
536     int i = 0;
537     int ncomp = dev->color_info.num_components;
538 
539     for (; i < ncomp; i++) {
540 	color <<= bpc;
541         color |= (colors[i] >> drop);
542     }
543     return (color == gx_no_color_index ? color ^ 1 : color);
544 }
545 
546 /*
547  * Decode a gx_color_index value back to a list of colorant values.
548  * With 32 bit gx_color_index values, we simply pack values.
549  */
550 static int
tiffsep_decode_color(gx_device * dev,gx_color_index color,gx_color_value * out)551 tiffsep_decode_color(gx_device * dev, gx_color_index color, gx_color_value * out)
552 {
553     int bpc = ((tiffsep_device *)dev)->devn_params.bitspercomponent;
554     int drop = sizeof(gx_color_value) * 8 - bpc;
555     int mask = (1 << bpc) - 1;
556     int i = 0;
557     int ncomp = dev->color_info.num_components;
558 
559     for (; i < ncomp; i++) {
560         out[ncomp - i - 1] = (gx_color_value) ((color & mask) << drop);
561 	color >>= bpc;
562     }
563     return 0;
564 }
565 
566 /*
567  *  Device proc for updating the equivalent CMYK color for spot colors.
568  */
569 static int
tiffsep_update_spot_equivalent_colors(gx_device * dev,const gs_state * pgs)570 tiffsep_update_spot_equivalent_colors(gx_device * dev, const gs_state * pgs)
571 {
572     tiffsep_device * pdev = (tiffsep_device *)dev;
573 
574     update_spot_equivalent_cmyk_colors(dev, pgs,
575 		    &pdev->devn_params, &pdev->equiv_cmyk_colors);
576     return 0;
577 }
578 
579 /*
580  *  Device proc for returning a pointer to DeviceN parameter structure
581  */
582 static gs_devn_params *
tiffsep_ret_devn_params(gx_device * dev)583 tiffsep_ret_devn_params(gx_device * dev)
584 {
585     tiffsep_device * pdev = (tiffsep_device *)dev;
586 
587     return &pdev->devn_params;
588 }
589 
590 /* Get parameters.  We provide a default CRD. */
591 static int
tiffsep_get_params(gx_device * pdev,gs_param_list * plist)592 tiffsep_get_params(gx_device * pdev, gs_param_list * plist)
593 {
594     tiffsep_device * const pdevn = (tiffsep_device *) pdev;
595     int code = gdev_prn_get_params(pdev, plist);
596     int ecode = code;
597     gs_param_string comprstr;
598 
599     if (code < 0)
600 	return code;
601 
602     code = devn_get_params(pdev, plist,
603 	    	&(((tiffsep_device *)pdev)->devn_params),
604     		&(((tiffsep_device *)pdev)->equiv_cmyk_colors));
605     if (code < 0)
606 	return code;
607 
608     if ((code = param_write_bool(plist, "BigEndian", &pdevn->BigEndian)) < 0)
609         ecode = code;
610     if ((code = tiff_compression_param_string(&comprstr, pdevn->Compression)) < 0 ||
611 	(code = param_write_string(plist, "Compression", &comprstr)) < 0)
612 	ecode = code;
613     if ((code = param_write_long(plist, "MaxStripSize", &pdevn->MaxStripSize)) < 0)
614         ecode = code;
615 
616     return ecode;
617 }
618 
619 /* Set parameters.  We allow setting the number of bits per component. */
620 static int
tiffsep_put_params(gx_device * pdev,gs_param_list * plist)621 tiffsep_put_params(gx_device * pdev, gs_param_list * plist)
622 {
623     tiffsep_device * const pdevn = (tiffsep_device *) pdev;
624     int code;
625     const char *param_name;
626     gs_param_string comprstr;
627 
628     /* Read BigEndian option as bool */
629     switch (code = param_read_bool(plist, (param_name = "BigEndian"), &pdevn->BigEndian)) {
630 	default:
631 	    param_signal_error(plist, param_name, code);
632 	    return code;
633         case 0:
634 	case 1:
635 	    break;
636     }
637     /* Read Compression */
638     switch (code = param_read_string(plist, (param_name = "Compression"), &comprstr)) {
639 	case 0:
640 	    if ((code = tiff_compression_id(&pdevn->Compression, &comprstr)) < 0 ||
641 		!tiff_compression_allowed(pdevn->Compression,
642 					  pdevn->devn_params.bitspercomponent))
643 	    {
644 		param_signal_error(plist, param_name, code);
645 		return code;
646 	    }
647 	    break;
648 	case 1:
649 	    break;
650 	default:
651 	    param_signal_error(plist, param_name, code);
652 	    return code;
653     }
654     switch (code = param_read_long(plist, (param_name = "MaxStripSize"), &pdevn->MaxStripSize)) {
655         case 0:
656 	    /*
657 	     * Strip must be large enough to accommodate a raster line.
658 	     * If the max strip size is too small, we still write a single
659 	     * line per strip rather than giving an error.
660 	     */
661 	    if (pdevn->MaxStripSize >= 0)
662 	        break;
663 	    code = gs_error_rangecheck;
664 	default:
665 	    param_signal_error(plist, param_name, code);
666 	    return code;
667 	case 1:
668 	    break;
669     }
670 
671     return devn_printer_put_params(pdev, plist,
672 		&(pdevn->devn_params), &(pdevn->equiv_cmyk_colors));
673 }
674 
675 static int
tiffsep1_put_params(gx_device * pdev,gs_param_list * plist)676 tiffsep1_put_params(gx_device * pdev, gs_param_list * plist)
677 {
678     tiffsep1_device * const tfdev = (tiffsep1_device *) pdev;
679     int code;
680 
681     if ((code = tiffsep_put_params(pdev, plist)) < 0)
682 	return code;
683 
684     /* put_params may have changed the fill_path proc -- we need it set to ours */
685     if (pdev->procs.fill_path != sep1_fill_path) {
686         tfdev->fill_path = pdev->procs.fill_path;
687 	pdev->procs.fill_path = sep1_fill_path;
688     }
689     return code;
690 
691 }
692 static void build_comp_to_sep_map(tiffsep_device *, short *);
693 static int number_output_separations(int, int, int, int);
694 static int create_separation_file_name(tiffsep_device *, char *, uint, int, bool);
695 static byte * threshold_from_order( gx_ht_order *, int *, int *, gs_memory_t *);
696 static int sep1_ht_order_to_thresholds(gx_device *pdev, const gs_imager_state *pis);
697 static void sep1_free_thresholds(tiffsep1_device *);
698 dev_proc_fill_path(clist_fill_path);
699 
700 /* Open the tiffsep device */
701 /* Save the fill_hl_color and fill_path procs around the gdev_prn_open */
702 int
tiffsep1_prn_open(gx_device * pdev)703 tiffsep1_prn_open(gx_device * pdev)
704 {
705     tiffsep1_device * const tfdev = (tiffsep1_device *)pdev;
706     int code = gdev_prn_open(pdev);
707 
708 #if !USE_COMPRESSED_ENCODING
709     /*
710      * If we are using the compressed encoding scheme, then set the separable
711      * and linear info.
712      */
713     set_linear_color_bits_mask_shift(pdev);
714     pdev->color_info.separable_and_linear = GX_CINFO_SEP_LIN;
715 #endif
716     /* gdev_prn_open may have changed the fill_path proc -- we need it set to ours */
717     if (pdev->procs.fill_path != sep1_fill_path) {
718         tfdev->fill_path = pdev->procs.fill_path;
719 	pdev->procs.fill_path = sep1_fill_path;
720     }
721     return code;
722 }
723 
724 /* Close the tiffsep device */
725 int
tiffsep1_prn_close(gx_device * pdev)726 tiffsep1_prn_close(gx_device * pdev)
727 {
728     tiffsep1_device * const tfdev = (tiffsep1_device *) pdev;
729     int num_dev_comp = tfdev->color_info.num_components;
730     int num_std_colorants = tfdev->devn_params.num_std_colorant_names;
731     int num_order = tfdev->devn_params.num_separation_order_names;
732     int num_spot = tfdev->devn_params.separations.num_separations;
733     char name[MAX_FILE_NAME_SIZE];
734     int code = gdev_prn_close(pdev);
735     short map_comp_to_sep[GX_DEVICE_COLOR_MAX_COMPONENTS];
736     int comp_num;
737     int num_comp = number_output_separations(num_dev_comp, num_std_colorants,
738 					num_order, num_spot);
739     const char *fmt;
740     gs_parsed_file_name_t parsed;
741 
742     if (code < 0)
743 	return code;
744     code = gx_parse_output_file_name(&parsed, &fmt,
745 		    			tfdev->fname, strlen(tfdev->fname));
746     if (code < 0)
747 	return code;
748 
749     /* If we are doing separate pages, delete the old default file */
750     if (parsed.iodev == iodev_default) {		/* filename includes "%nnd" */
751 	if (fmt) {
752 	    char compname[MAX_FILE_NAME_SIZE];
753 	    long count1 = pdev->PageCount;
754 
755 	    while (*fmt != 'l' && *fmt != '%')
756 		--fmt;
757 	    if (*fmt == 'l')
758 		sprintf(compname, parsed.fname, count1);
759 	    else
760 		sprintf(compname, parsed.fname, (int)count1);
761 	    parsed.iodev->procs.delete_file(parsed.iodev, compname);
762 	} else {
763 	    parsed.iodev->procs.delete_file(parsed.iodev, tfdev->fname);
764 	}
765 
766     }
767 
768     build_comp_to_sep_map((tiffsep_device *)tfdev, map_comp_to_sep);
769     /* Close the separation files */
770     for (comp_num = 0; comp_num < num_comp; comp_num++ ) {
771 	if (tfdev->sep_file[comp_num] != NULL) {
772 	    int sep_num = map_comp_to_sep[comp_num];
773 
774 	    code = create_separation_file_name((tiffsep_device *)tfdev, name,
775 						MAX_FILE_NAME_SIZE, sep_num, true);
776 	    if (code < 0)
777 		return code;
778 	    code = gx_device_close_output_file(pdev, name, tfdev->sep_file[comp_num]);
779 	    if (code < 0)
780 		return code;
781 	    tfdev->sep_file[comp_num] = NULL;
782 	}
783 	if (tfdev->tiff[comp_num]) {
784 	    TIFFCleanup(tfdev->tiff[comp_num]);
785 	    tfdev->tiff[comp_num] = NULL;
786 	}
787     }
788     /* If we have thresholds, free them and clear the pointers */
789     if( tfdev->thresholds[0].dstart != NULL) {
790 	sep1_free_thresholds(tfdev);
791     }
792     return 0;
793 }
794 
795 
796 static int
sep1_fill_path(gx_device * pdev,const gs_imager_state * pis,gx_path * ppath,const gx_fill_params * params,const gx_device_color * pdevc,const gx_clip_path * pcpath)797 sep1_fill_path(gx_device * pdev, const gs_imager_state * pis,
798 		 gx_path * ppath, const gx_fill_params * params,
799 		 const gx_device_color * pdevc, const gx_clip_path * pcpath)
800 {
801     tiffsep1_device * const tfdev = (tiffsep1_device *)pdev;
802 
803     /* If we haven't already converted the ht into thresholds, do it now */
804     if( tfdev->thresholds[0].dstart == NULL) {
805 	int code = sep1_ht_order_to_thresholds(pdev, pis);
806 
807 	if (code < 0)
808 	    return code;
809     }
810     return (tfdev->fill_path)( pdev, pis, ppath, params, pdevc, pcpath);
811 }
812 
813 /*
814  * This routine will check to see if the color component name  match those
815  * that are available amoung the current device's color components.
816  *
817  * Parameters:
818  *   dev - pointer to device data structure.
819  *   pname - pointer to name (zero termination not required)
820  *   nlength - length of the name
821  *
822  * This routine returns a positive value (0 to n) which is the device colorant
823  * number if the name is found.  It returns GX_DEVICE_COLOR_MAX_COMPONENTS if
824  * the colorant is not being used due to a SeparationOrder device parameter.
825  * It returns a negative value if not found.
826  */
827 static int
tiffsep_get_color_comp_index(gx_device * dev,const char * pname,int name_size,int component_type)828 tiffsep_get_color_comp_index(gx_device * dev, const char * pname,
829 				int name_size, int component_type)
830 {
831     tiffsep_device * pdev = (tiffsep_device *) dev;
832 
833     /*
834      * We allow more spot colors than we can image.  This allows the user
835      * to obtain separations for more than our max of 8 by doing multiple
836      * passes.
837      */
838     return devn_get_color_comp_index(dev,
839 		&(pdev->devn_params), &(pdev->equiv_cmyk_colors),
840 		pname, name_size, component_type, ALLOW_EXTRA_SPOT_COLORS);
841 }
842 
843 /*
844  * There can be a conflict if a separation name is used as part of the file
845  * name for a separation output file.  PostScript and PDF do not restrict
846  * the characters inside separation names.  However most operating systems
847  * have some sort of restrictions.  For instance: /, \, and : have special
848  * meaning under Windows.  This implies that there should be some sort of
849  * escape sequence for special characters.  This routine exists as a place
850  * to put the handling of that escaping.  However it is not actually
851  * implemented. Instead we just map them to '_'.
852  */
853 static void
copy_separation_name(tiffsep_device * pdev,char * buffer,int max_size,int sep_num)854 copy_separation_name(tiffsep_device * pdev,
855 		char * buffer, int max_size, int sep_num)
856 {
857     int sep_size = pdev->devn_params.separations.names[sep_num].size;
858     int i;
859     int restricted_chars[] = { '/', '\\', ':', 0 };
860 
861     /* If name is too long then clip it. */
862     if (sep_size > max_size - 1)
863         sep_size = max_size - 1;
864     memcpy(buffer, pdev->devn_params.separations.names[sep_num].data,
865 		sep_size);
866     /* Change some of the commonly known restricted characters to '_' */
867     for (i=0; restricted_chars[i] != 0; i++) {
868 	char *p = buffer;
869 
870 	while ((p=memchr(p, restricted_chars[i], sep_size - (p - buffer))) != NULL)
871 	    *p = '_';
872     }
873     buffer[sep_size] = 0;	/* Terminate string */
874 }
875 
876 /*
877  * Determine the length of the base file name.  If the file name includes
878  * the extension '.tif', then we remove it from the length of the file
879  * name.
880  */
881 static int
length_base_file_name(tiffsep_device * pdev)882 length_base_file_name(tiffsep_device * pdev)
883 {
884     int base_filename_length = strlen(pdev->fname);
885 
886 #define REMOVE_TIF_FROM_BASENAME 1
887 #if REMOVE_TIF_FROM_BASENAME
888     if (base_filename_length > 4 &&
889 	pdev->fname[base_filename_length - 4] == '.'  &&
890 	toupper(pdev->fname[base_filename_length - 3]) == 'T'  &&
891 	toupper(pdev->fname[base_filename_length - 2]) == 'I'  &&
892 	toupper(pdev->fname[base_filename_length - 1]) == 'F')
893 	base_filename_length -= 4;
894 #endif
895 #undef REMOVE_TIF_FROM_BASENAME
896 
897     return base_filename_length;
898 }
899 
900 /*
901  * Create a name for a separation file.
902  */
903 static int
create_separation_file_name(tiffsep_device * pdev,char * buffer,uint max_size,int sep_num,bool use_sep_name)904 create_separation_file_name(tiffsep_device * pdev, char * buffer,
905 				uint max_size, int sep_num, bool use_sep_name)
906 {
907     uint base_filename_length = length_base_file_name(pdev);
908 
909     /*
910      * In most cases it is more convenient if we append '.tif' to the end
911      * of the file name.
912      */
913 #define APPEND_TIF_TO_NAME 1
914 #define SUFFIX_SIZE (4 * APPEND_TIF_TO_NAME)
915 
916     memcpy(buffer, pdev->fname, base_filename_length);
917     buffer[base_filename_length++] = use_sep_name ? '(' : '.';
918     buffer[base_filename_length] = 0;  /* terminate the string */
919 
920     if (sep_num < pdev->devn_params.num_std_colorant_names) {
921 	if (max_size < strlen(pdev->devn_params.std_colorant_names[sep_num]))
922 	    return_error(gs_error_rangecheck);
923 	strcat(buffer, pdev->devn_params.std_colorant_names[sep_num]);
924     }
925     else {
926 	sep_num -= pdev->devn_params.num_std_colorant_names;
927         if (use_sep_name) {
928             copy_separation_name(pdev, buffer + base_filename_length,
929 	    			max_size - SUFFIX_SIZE - 2, sep_num);
930        	} else {
931 		/* Max of 10 chars in %d format */
932 	    if (max_size < base_filename_length + 11)
933 		return_error(gs_error_rangecheck);
934 	    sprintf(buffer + base_filename_length, "s%d", sep_num);
935 	}
936     }
937     if (use_sep_name)
938 	strcat(buffer, ")");
939 
940 #if APPEND_TIF_TO_NAME
941     if (max_size < strlen(buffer) + SUFFIX_SIZE)
942 	return_error(gs_error_rangecheck);
943     strcat(buffer, ".tif");
944 #endif
945     return 0;
946 }
947 
948 /*
949  * Determine the number of output separations for the tiffsep device.
950  *
951  * There are several factors which affect the number of output separations
952  * for the tiffsep device.
953  *
954  * Due to limitations on the size of a gx_color_index, we are limited to a
955  * maximum of 8 colors per pass.  Thus the tiffsep device is set to 8
956  * components.  However this is not usually the number of actual separation
957  * files to be created.
958  *
959  * If the SeparationOrder parameter has been specified, then we use it to
960  * select the number and which separation files are created.
961  *
962  * If the SeparationOrder parameter has not been specified, then we use the
963  * nuber of process colors (CMYK) and the number of spot colors unless we
964  * exceed the 8 component maximum for the device.
965  *
966  * Note:  Unlike most other devices, the tiffsep device will accept more than
967  * four spot colors.  However the extra spot colors will not be imaged
968  * unless they are selected by the SeparationOrder parameter.  (This does
969  * allow the user to create more than 8 separations by a making multiple
970  * passes and using the SeparationOrder parameter.)
971 */
972 static int
number_output_separations(int num_dev_comp,int num_std_colorants,int num_order,int num_spot)973 number_output_separations(int num_dev_comp, int num_std_colorants,
974 					int num_order, int num_spot)
975 {
976     int num_comp =  num_std_colorants + num_spot;
977 
978     if (num_comp > num_dev_comp)
979 	num_comp = num_dev_comp;
980     if (num_order)
981 	num_comp = num_order;
982     return num_comp;
983 }
984 
985 /*
986  * This routine creates a list to map the component number to a separation number.
987  * Values less than 4 refer to the CMYK colorants.  Higher values refer to a
988  * separation number.
989  *
990  * This is the inverse of the separation_order_map.
991  */
992 static void
build_comp_to_sep_map(tiffsep_device * pdev,short * map_comp_to_sep)993 build_comp_to_sep_map(tiffsep_device * pdev, short * map_comp_to_sep)
994 {
995     int num_sep = pdev->devn_params.separations.num_separations;
996     int num_std_colorants = pdev->devn_params.num_std_colorant_names;
997     int sep_num;
998     int num_channels;
999 
1000     /* since both proc colors and spot colors are packed in same encoded value we
1001        need to have this limit */
1002 
1003     num_channels =
1004         ( (num_std_colorants + num_sep) < (GX_DEVICE_COLOR_MAX_COMPONENTS) ? (num_std_colorants + num_sep) : (GX_DEVICE_COLOR_MAX_COMPONENTS) );
1005 
1006     for (sep_num = 0; sep_num < num_channels; sep_num++) {
1007 	int comp_num = pdev->devn_params.separation_order_map[sep_num];
1008 
1009 	if (comp_num >= 0 && comp_num < GX_DEVICE_COLOR_MAX_COMPONENTS)
1010 	    map_comp_to_sep[comp_num] = sep_num;
1011     }
1012 }
1013 
1014 /* Open the tiffsep device */
1015 int
tiffsep_prn_open(gx_device * pdev)1016 tiffsep_prn_open(gx_device * pdev)
1017 {
1018     int code = gdev_prn_open(pdev);
1019 
1020 #if !USE_COMPRESSED_ENCODING
1021     /*
1022      * If we are using the compressed encoding scheme, then set the separable
1023      * and linear info.
1024      */
1025     set_linear_color_bits_mask_shift(pdev);
1026     pdev->color_info.separable_and_linear = GX_CINFO_SEP_LIN;
1027 #endif
1028     return code;
1029 }
1030 
1031 static int
tiffsep_close_sep_file(tiffsep_device * tfdev,const char * fn,int comp_num)1032 tiffsep_close_sep_file(tiffsep_device *tfdev, const char *fn, int comp_num)
1033 {
1034     int code;
1035 
1036     if (tfdev->tiff[comp_num]) {
1037 	TIFFCleanup(tfdev->tiff[comp_num]);
1038 	tfdev->tiff[comp_num] = NULL;
1039     }
1040 
1041     code = gx_device_close_output_file((gx_device *)tfdev,
1042                                        fn,
1043                                        tfdev->sep_file[comp_num]);
1044     tfdev->sep_file[comp_num] = NULL;
1045     tfdev->tiff[comp_num] = NULL;
1046 
1047     return code;
1048 }
1049 
1050 /* Close the tiffsep device */
1051 int
tiffsep_prn_close(gx_device * pdev)1052 tiffsep_prn_close(gx_device * pdev)
1053 {
1054     tiffsep_device * const pdevn = (tiffsep_device *) pdev;
1055     int num_dev_comp = pdevn->color_info.num_components;
1056     int num_std_colorants = pdevn->devn_params.num_std_colorant_names;
1057     int num_order = pdevn->devn_params.num_separation_order_names;
1058     int num_spot = pdevn->devn_params.separations.num_separations;
1059     char name[MAX_FILE_NAME_SIZE];
1060     int code;
1061     short map_comp_to_sep[GX_DEVICE_COLOR_MAX_COMPONENTS];
1062     int comp_num;
1063     int num_comp = number_output_separations(num_dev_comp, num_std_colorants,
1064 					num_order, num_spot);
1065 
1066     if (pdevn->tiff_comp) {
1067 	TIFFCleanup(pdevn->tiff_comp);
1068 	pdevn->tiff_comp = NULL;
1069     }
1070     code = gdev_prn_close(pdev);
1071     if (code < 0)
1072 	return code;
1073 
1074     build_comp_to_sep_map(pdevn, map_comp_to_sep);
1075     /* Close the separation files */
1076     for (comp_num = 0; comp_num < num_comp; comp_num++ ) {
1077         if (pdevn->sep_file[comp_num] != NULL) {
1078 	    int sep_num = map_comp_to_sep[comp_num];
1079 
1080 	    code = create_separation_file_name(pdevn, name,
1081 	            MAX_FILE_NAME_SIZE, sep_num, false);
1082 	    if (code < 0)
1083 		return code;
1084             code = tiffsep_close_sep_file(pdevn, name, comp_num);
1085 	    if (code < 0)
1086 		return code;
1087 	}
1088     }
1089 
1090     return 0;
1091 }
1092 
1093 /*
1094  * Element for a map to convert colorants to a CMYK color.
1095  */
1096 typedef struct cmyk_composite_map_s {
1097     frac c, m, y, k;
1098 } cmyk_composite_map;
1099 
1100 /*
1101  * Build the map to be used to create a CMYK equivalent to the current
1102  * device components.
1103  */
1104 static void
build_cmyk_map(tiffsep_device * pdev,int num_comp,short * map_comp_to_sep,cmyk_composite_map * cmyk_map)1105 build_cmyk_map(tiffsep_device * pdev, int num_comp,
1106 	short *map_comp_to_sep, cmyk_composite_map * cmyk_map)
1107 {
1108     int comp_num;
1109 
1110     for (comp_num = 0; comp_num < num_comp; comp_num++ ) {
1111 	int sep_num = map_comp_to_sep[comp_num];
1112 
1113 	cmyk_map[comp_num].c = cmyk_map[comp_num].m =
1114 	    cmyk_map[comp_num].y = cmyk_map[comp_num].k = frac_0;
1115 	/* The tiffsep device has 4 standard colors:  CMYK */
1116         if (sep_num < pdev->devn_params.num_std_colorant_names) {
1117 	    switch (sep_num) {
1118 		case 0: cmyk_map[comp_num].c = frac_1; break;
1119 		case 1: cmyk_map[comp_num].m = frac_1; break;
1120 		case 2: cmyk_map[comp_num].y = frac_1; break;
1121 		case 3: cmyk_map[comp_num].k = frac_1; break;
1122 	    }
1123 	}
1124 	else {
1125             sep_num -= pdev->devn_params.num_std_colorant_names;
1126 	    if (pdev->equiv_cmyk_colors.color[sep_num].color_info_valid) {
1127 	        cmyk_map[comp_num].c = pdev->equiv_cmyk_colors.color[sep_num].c;
1128 	        cmyk_map[comp_num].m = pdev->equiv_cmyk_colors.color[sep_num].m;
1129 	        cmyk_map[comp_num].y = pdev->equiv_cmyk_colors.color[sep_num].y;
1130 	        cmyk_map[comp_num].k = pdev->equiv_cmyk_colors.color[sep_num].k;
1131 	    }
1132 	}
1133     }
1134 }
1135 
1136 /*
1137  * Build a CMYK equivalent to a raster line.
1138  */
1139 static void
build_cmyk_raster_line(byte * src,byte * dest,int width,int num_comp,cmyk_composite_map * cmyk_map)1140 build_cmyk_raster_line(byte * src, byte * dest, int width,
1141 	int num_comp, cmyk_composite_map * cmyk_map)
1142 {
1143     int pixel, comp_num;
1144     uint temp, cyan, magenta, yellow, black;
1145     cmyk_composite_map * cmyk_map_entry;
1146 
1147     for (pixel = 0; pixel < width; pixel++) {
1148 	cmyk_map_entry = cmyk_map;
1149 	temp = *src++;
1150 	cyan = cmyk_map_entry->c * temp;
1151 	magenta = cmyk_map_entry->m * temp;
1152 	yellow = cmyk_map_entry->y * temp;
1153 	black = cmyk_map_entry->k * temp;
1154 	cmyk_map_entry++;
1155 	for (comp_num = 1; comp_num < num_comp; comp_num++) {
1156 	    temp = *src++;
1157 	    cyan += cmyk_map_entry->c * temp;
1158 	    magenta += cmyk_map_entry->m * temp;
1159 	    yellow += cmyk_map_entry->y * temp;
1160 	    black += cmyk_map_entry->k * temp;
1161 	    cmyk_map_entry++;
1162 	}
1163 	cyan /= frac_1;
1164 	magenta /= frac_1;
1165 	yellow /= frac_1;
1166 	black /= frac_1;
1167 	if (cyan > MAX_COLOR_VALUE)
1168 	    cyan = MAX_COLOR_VALUE;
1169 	if (magenta > MAX_COLOR_VALUE)
1170 	    magenta = MAX_COLOR_VALUE;
1171 	if (yellow > MAX_COLOR_VALUE)
1172 	    yellow = MAX_COLOR_VALUE;
1173 	if (black > MAX_COLOR_VALUE)
1174 	    black = MAX_COLOR_VALUE;
1175 	*dest++ = cyan;
1176 	*dest++ = magenta;
1177 	*dest++ = yellow;
1178 	*dest++ = black;
1179     }
1180 }
1181 
1182 static int
sep1_ht_order_to_thresholds(gx_device * pdev,const gs_imager_state * pis)1183 sep1_ht_order_to_thresholds(gx_device *pdev, const gs_imager_state *pis)
1184 {
1185     tiffsep1_device * const tfdev = (tiffsep1_device *)pdev;
1186     gs_memory_t *mem = pdev->memory;
1187 
1188     /* If we have thresholds, free them and clear the pointers */
1189     if( tfdev->thresholds[0].dstart != NULL) {
1190 	sep1_free_thresholds(tfdev);
1191     } else {
1192 	int nc, j;
1193 	gx_ht_order *d_order;
1194         threshold_array_t *dptr;
1195 
1196 	if (pis->dev_ht == NULL) {
1197 	    eprintf("sep1_order_to_thresholds: no dev_ht available\n");
1198 	    return_error(gs_error_rangecheck);	/* error condition */
1199 	}
1200 	nc = pis->dev_ht->num_comp;
1201 	for( j=0; j<nc; j++ ) {
1202 	    d_order = &(pis->dev_ht->components[j].corder);
1203 	    dptr = &(tfdev->thresholds[j]);
1204 	    dptr->dstart = threshold_from_order( d_order, &(dptr->dwidth), &(dptr->dheight), mem);
1205 	    if( dptr->dstart == NULL ) {
1206 		eprintf("sep1_order_to_thresholds: conversion to thresholds failed.\n");
1207 		return_error(gs_error_rangecheck);	/* error condition */
1208 	    }
1209 	}
1210     }
1211     return 0;
1212 }
1213 
1214 static void
sep1_free_thresholds(tiffsep1_device * tfdev)1215 sep1_free_thresholds(tiffsep1_device *tfdev)
1216 {
1217     int i;
1218 
1219     for (i=0; i < GX_DEVICE_COLOR_MAX_COMPONENTS + 1; i++) {
1220 	threshold_array_t *dptr = &(tfdev->thresholds[i]);
1221 
1222 	if (dptr->dstart != NULL) {
1223 	    gs_free(tfdev->memory, dptr->dstart, dptr->dwidth * dptr->dheight, 1,
1224 		      "tiffsep1_threshold_array");
1225 	    dptr->dstart = NULL;
1226 	}
1227     }
1228 }
1229 
1230 /************************************************************************/
1231 /*	This routine generates a threshold matrix for use in		*/
1232 /*	the color dithering routine from the "order" info in		*/
1233 /*	the current graphics state.					*/
1234 /*									*/
1235 /************************************************************************/
1236 
1237 static byte*
threshold_from_order(gx_ht_order * d_order,int * Width,int * Height,gs_memory_t * memory)1238 threshold_from_order( gx_ht_order *d_order, int *Width, int *Height, gs_memory_t *memory)
1239 {
1240    int i, j, l, prev_l;
1241    unsigned char *thresh;
1242    gx_ht_bit *bits = (gx_ht_bit *)d_order->bit_data;
1243 
1244 #ifdef DEBUG
1245 if ( gs_debug_c('h') ) {
1246        dprintf2("   width=%d, height=%d,",
1247 	    d_order->width, d_order->height );
1248        dprintf2(" num_levels=%d, raster=%d\n",
1249 	    d_order->num_levels, d_order->raster );
1250 }
1251 #endif
1252 
1253    thresh = (byte *)gs_malloc(memory, d_order->num_bits, 1,
1254                                   "tiffsep1_threshold_array");
1255    if( thresh == NULL ) {
1256 #ifdef DEBUG
1257       eprintf("threshold_from_order, malloc failed\n");
1258       eprintf2("   width=%d, height=%d,",
1259 	      d_order->width, d_order->height );
1260       eprintf2(" num_levels=%d, raster=%d\n",
1261 	      d_order->num_levels, d_order->raster );
1262 #endif
1263  	return thresh ;		/* error if allocation failed	*/
1264    }
1265    for( i=0; i<d_order->num_bits; i++ )
1266       thresh[i] = 1;
1267 
1268    *Width  = d_order->width;
1269    *Height = d_order->height;
1270 
1271    prev_l = 0;
1272    l = 1;
1273    while( l < d_order->num_levels ) {
1274       if( d_order->levels[l] > d_order->levels[prev_l] ) {
1275 	 int t_level = (256*l)/d_order->num_levels;
1276 	 int row, col;
1277 #ifdef DEBUG
1278 	 if ( gs_debug_c('h') )
1279 	    dprintf2("	level[%3d]=%3d\n", l, d_order->levels[l]);
1280 #endif
1281 	 for( j=d_order->levels[prev_l]; j<d_order->levels[l]; j++) {
1282 #ifdef DEBUG
1283 	    if ( gs_debug_c('h') )
1284 	       dprintf2("	bits.offset=%3d, bits.mask=%8x	",
1285 		   bits[j].offset, bits[j].mask);
1286 #endif
1287 	    row = bits[j].offset / d_order->raster;
1288 	    for( col=0; col < (8*sizeof(ht_mask_t)); col++ ) {
1289 	       if( bits[j].mask & bit_order[col] )
1290 		  break;
1291 	    }
1292 	    col += 8 * ( bits[j].offset - (row * d_order->raster) );
1293 #ifdef DEBUG
1294 	    if ( gs_debug_c('h') )
1295 	       dprintf3("row=%2d, col=%2d, t_level=%3d\n",
1296 		  row, col, t_level);
1297 #endif
1298 	    if( col < (int)d_order->width )
1299 	       *(thresh+col+(row * d_order->width)) = t_level;
1300 	 }
1301 	 prev_l = l;
1302       }
1303       l++;
1304    }
1305 
1306 #ifdef DEBUG
1307    if ( gs_debug_c('h') ) {
1308       for( i=0; i<(int)d_order->height; i++ ) {
1309 	 dprintf1("threshold array row %3d= ", i);
1310 	 for( j=(int)d_order->width-1; j>=0; j-- )
1311 	    dprintf1("%3d ", *(thresh+j+(i*d_order->width)) );
1312 	 dprintf("\n");
1313       }
1314    }
1315 #endif
1316 
1317    return thresh;
1318 }
1319 
1320 /*
1321  * Output the image data for the tiff separation (tiffsep) device.  The data
1322  * for the tiffsep device is written in separate planes to separate files.
1323  *
1324  * The DeviceN parameters (SeparationOrder, SeparationColorNames, and
1325  * MaxSeparations) are applied to the tiffsep device.
1326  */
1327 static int
tiffsep_print_page(gx_device_printer * pdev,FILE * file)1328 tiffsep_print_page(gx_device_printer * pdev, FILE * file)
1329 {
1330     tiffsep_device * const tfdev = (tiffsep_device *)pdev;
1331     int num_std_colorants = tfdev->devn_params.num_std_colorant_names;
1332     int num_order = tfdev->devn_params.num_separation_order_names;
1333     int num_spot = tfdev->devn_params.separations.num_separations;
1334     int num_comp, comp_num, sep_num, code = 0;
1335     short map_comp_to_sep[GX_DEVICE_COLOR_MAX_COMPONENTS];
1336     cmyk_composite_map cmyk_map[GX_DEVICE_COLOR_MAX_COMPONENTS];
1337     char name[MAX_FILE_NAME_SIZE];
1338     int base_filename_length = length_base_file_name(tfdev);
1339     int save_depth = pdev->color_info.depth;
1340     const char *fmt;
1341     gs_parsed_file_name_t parsed;
1342     int non_encodable_count = 0;
1343 
1344     build_comp_to_sep_map(tfdev, map_comp_to_sep);
1345 
1346     /* Print the names of the spot colors */
1347     for (sep_num = 0; sep_num < num_spot; sep_num++) {
1348         copy_separation_name(tfdev, name,
1349 	    MAX_FILE_NAME_SIZE - base_filename_length - SUFFIX_SIZE, sep_num);
1350 	dlprintf1("%%%%SeparationName: %s\n", name);
1351     }
1352 
1353     /*
1354      * Check if the file name has a numeric format.  If so then we want to
1355      * create individual separation files for each page of the input.
1356     */
1357     code = gx_parse_output_file_name(&parsed, &fmt,
1358 		    			tfdev->fname, strlen(tfdev->fname));
1359 
1360     /* Write the page directory for the CMYK equivalent file. */
1361     pdev->color_info.depth = 32;	/* Create directory for 32 bit cmyk */
1362     if (pdev->height > (max_long - ftell(file))/(pdev->width*4)) /* note width is never 0 in print_page */
1363 	return_error(gs_error_rangecheck);  /* this will overflow max_long */
1364 
1365     if (gdev_prn_file_is_new(pdev)) {
1366 	tfdev->tiff_comp = tiff_from_filep(pdev->dname, file, tfdev->BigEndian);
1367 	if (!tfdev->tiff_comp)
1368 	    return_error(gs_error_invalidfileaccess);
1369     }
1370     code = tiff_set_fields_for_printer(pdev, tfdev->tiff_comp);
1371     tiff_set_cmyk_fields(pdev, tfdev->tiff_comp, 8, COMPRESSION_NONE, tfdev->MaxStripSize);
1372     pdev->color_info.depth = save_depth;
1373     if (code < 0)
1374 	return code;
1375 
1376     /* Set up the separation output files */
1377     num_comp = number_output_separations( tfdev->color_info.num_components,
1378 					num_std_colorants, num_order, num_spot);
1379     for (comp_num = 0; comp_num < num_comp; comp_num++ ) {
1380 	int sep_num = map_comp_to_sep[comp_num];
1381 
1382 	code = create_separation_file_name(tfdev, name, MAX_FILE_NAME_SIZE,
1383 					    sep_num, false);
1384 	if (code < 0)
1385 	    return code;
1386 	/*
1387 	 * Close the old separation file if we are creating individual files
1388 	 * for each page.
1389 	 */
1390 	if (tfdev->sep_file[comp_num] != NULL && fmt != NULL) {
1391             code = tiffsep_close_sep_file(tfdev, name, comp_num);
1392 	    if (code < 0)
1393 		return code;
1394 	}
1395 	/* Open the separation file, if not already open */
1396 	if (tfdev->sep_file[comp_num] == NULL) {
1397 	    code = gx_device_open_output_file((gx_device *)pdev, name,
1398 		    true, false, &(tfdev->sep_file[comp_num]));
1399 	    if (code < 0)
1400 	        return code;
1401             tfdev->tiff[comp_num] = tiff_from_filep(name,
1402 						    tfdev->sep_file[comp_num],
1403 						    tfdev->BigEndian);
1404 	    if (!tfdev->tiff[comp_num])
1405 		return_error(gs_error_ioerror);
1406 	}
1407 
1408 	pdev->color_info.depth = 8;	/* Create files for 8 bit gray */
1409 	if (pdev->height > (max_long - ftell(file))/(pdev->width)) /* note width is never 0 in print_page */
1410 	    return_error(gs_error_rangecheck);  /* this will overflow max_long */
1411 
1412 	code = tiff_set_fields_for_printer(pdev, tfdev->tiff[comp_num]);
1413 	tiff_set_gray_fields(pdev, tfdev->tiff[comp_num], 8, tfdev->Compression, tfdev->MaxStripSize);
1414 	pdev->color_info.depth = save_depth;
1415         if (code < 0)
1416 	    return code;
1417     }
1418 
1419     build_cmyk_map(tfdev, num_comp, map_comp_to_sep, cmyk_map);
1420 
1421     {
1422         int raster = gdev_prn_raster(pdev);
1423 	int width = tfdev->width;
1424 	int cmyk_raster = width * NUM_CMYK_COMPONENTS;
1425 	int pixel, y;
1426 	byte * line = gs_alloc_bytes(pdev->memory, raster, "tiffsep_print_page");
1427 	byte * unpacked = gs_alloc_bytes(pdev->memory, width * num_comp,
1428 							"tiffsep_print_page");
1429 	byte * sep_line;
1430 	byte * row;
1431 
1432 	if (line == NULL || unpacked == NULL)
1433 	    return_error(gs_error_VMerror);
1434 	sep_line =
1435 	    gs_alloc_bytes(pdev->memory, cmyk_raster, "tiffsep_print_page");
1436 	if (sep_line == NULL) {
1437 	    gs_free_object(pdev->memory, line, "tiffsep_print_page");
1438 	    return_error(gs_error_VMerror);
1439 	}
1440 
1441         /* Write the page data. */
1442 	for (y = 0; y < pdev->height; ++y) {
1443 	    code = gdev_prn_get_bits(pdev, y, line, &row);
1444 	    if (code < 0)
1445 		break;
1446 	    /* Unpack the encoded color info */
1447 	    non_encodable_count += devn_unpack_row((gx_device *)pdev, num_comp,
1448 			    &(tfdev->devn_params), width, row, unpacked);
1449 	    /* Write separation data (tiffgray format) */
1450             for (comp_num = 0; comp_num < num_comp; comp_num++ ) {
1451 		byte * src = unpacked + comp_num;
1452 		byte * dest = sep_line;
1453 
1454 		for (pixel = 0; pixel < width; pixel++, dest++, src += num_comp)
1455 		    *dest = MAX_COLOR_VALUE - *src;    /* Gray is additive */
1456 		TIFFWriteScanline(tfdev->tiff[comp_num], (tdata_t)sep_line, y, 0);
1457 	    }
1458 	    /* Write CMYK equivalent data (tiff32nc format) */
1459 	    build_cmyk_raster_line(unpacked, sep_line,
1460 			    		width, num_comp, cmyk_map);
1461 	    TIFFWriteScanline(tfdev->tiff_comp, (tdata_t)sep_line, y, 0);
1462 	}
1463 	for (comp_num = 0; comp_num < num_comp; comp_num++ )
1464 	    TIFFWriteDirectory(tfdev->tiff[comp_num]);
1465 	TIFFWriteDirectory(tfdev->tiff_comp);
1466 
1467 	gs_free_object(pdev->memory, line, "tiffsep_print_page");
1468 	gs_free_object(pdev->memory, sep_line, "tiffsep_print_page");
1469     }
1470 
1471 #if defined(DEBUG) && 0
1472     print_compressed_color_list(tfdev->devn_params.compressed_color_list,
1473 		    			max(16, num_comp));
1474 #endif
1475 
1476     /*
1477      * If we have any non encodable pixels then signal an error.
1478      */
1479     if (non_encodable_count) {
1480         dlprintf1("WARNING:  Non encodable pixels = %d\n", non_encodable_count);
1481 	return_error(gs_error_rangecheck);
1482     }
1483 
1484     return code;
1485 }
1486 
1487 /*
1488  * Output the image data for the tiff separation (tiffsep1) device.  The data
1489  * for the tiffsep1 device is written in separate planes to separate files.
1490  *
1491  * The DeviceN parameters (SeparationOrder, SeparationColorNames, and
1492  * MaxSeparations) are applied to the tiffsep device.
1493  */
1494 static int
tiffsep1_print_page(gx_device_printer * pdev,FILE * file)1495 tiffsep1_print_page(gx_device_printer * pdev, FILE * file)
1496 {
1497     tiffsep1_device * const tfdev = (tiffsep1_device *)pdev;
1498     int num_std_colorants = tfdev->devn_params.num_std_colorant_names;
1499     int num_order = tfdev->devn_params.num_separation_order_names;
1500     int num_spot = tfdev->devn_params.separations.num_separations;
1501     int num_comp, comp_num, code = 0;
1502     short map_comp_to_sep[GX_DEVICE_COLOR_MAX_COMPONENTS];
1503     char name[MAX_FILE_NAME_SIZE];
1504     int save_depth = pdev->color_info.depth;
1505     const char *fmt;
1506     gs_parsed_file_name_t parsed;
1507     int non_encodable_count = 0;
1508 
1509     if (tfdev->thresholds[0].dstart == NULL)
1510 	return_error(gs_error_rangecheck);
1511 
1512     build_comp_to_sep_map((tiffsep_device *)tfdev, map_comp_to_sep);
1513 
1514     /*
1515      * Check if the file name has a numeric format.  If so then we want to
1516      * create individual separation files for each page of the input.
1517     */
1518     code = gx_parse_output_file_name(&parsed, &fmt,
1519 		    			pdev->fname, strlen(pdev->fname));
1520 
1521     /* If the output file is on disk and the name contains a page #, */
1522     /* then delete the previous file. */
1523     if (pdev->file != NULL && parsed.iodev == iodev_default && fmt) {
1524         char compname[MAX_FILE_NAME_SIZE];
1525 	long count1 = pdev->PageCount;
1526 
1527 	gx_device_close_output_file((gx_device *)pdev, pdev->fname, pdev->file);
1528 	pdev->file = NULL;
1529 
1530 	while (*fmt != 'l' && *fmt != '%')
1531 	    --fmt;
1532 	if (*fmt == 'l')
1533 	    sprintf(compname, parsed.fname, count1);
1534 	else
1535 	    sprintf(compname, parsed.fname, (int)count1);
1536 	parsed.iodev->procs.delete_file(parsed.iodev, compname);
1537 	/* we always need an open printer (it will get deleted in tiffsep1_prn_close */
1538 	if ((code = gdev_prn_open_printer((gx_device *)pdev, 1)) < 0)
1539 	    return code;
1540     }
1541 
1542     /* Set up the separation output files */
1543     num_comp = number_output_separations( tfdev->color_info.num_components,
1544 					num_std_colorants, num_order, num_spot);
1545     for (comp_num = 0; comp_num < num_comp; comp_num++ ) {
1546 	int sep_num = map_comp_to_sep[comp_num];
1547 
1548 	code = create_separation_file_name((tiffsep_device *)tfdev, name,
1549 					MAX_FILE_NAME_SIZE, sep_num, true);
1550 	if (code < 0)
1551 	    return code;
1552 	/*
1553 	 * Close the old separation file if we are creating individual files
1554 	 * for each page.
1555 	 */
1556 	if (tfdev->sep_file[comp_num] != NULL && fmt != NULL) {
1557 	    code = gx_device_close_output_file((const gx_device *)tfdev, name,
1558 			    		tfdev->sep_file[comp_num]);
1559 	    if (code < 0)
1560 		return code;
1561 	    tfdev->sep_file[comp_num] = NULL;
1562 	    if (tfdev->tiff[comp_num]) {
1563 		TIFFCleanup(tfdev->tiff[comp_num]);
1564 		tfdev->tiff[comp_num] = NULL;
1565 	    }
1566 	}
1567 	/* Open the separation file, if not already open */
1568 	if (tfdev->sep_file[comp_num] == NULL) {
1569 	    code = gx_device_open_output_file((gx_device *)pdev, name,
1570 		    true, false, &(tfdev->sep_file[comp_num]));
1571 	    if (code < 0)
1572 	        return code;
1573 	    tfdev->tiff[comp_num] = tiff_from_filep(name,
1574 						    tfdev->sep_file[comp_num],
1575 						    tfdev->BigEndian);
1576 	    if (!tfdev->tiff[comp_num])
1577 		return_error(gs_error_ioerror);
1578 	}
1579 
1580 	pdev->color_info.depth = 8;	/* Create files for 8 bit gray */
1581 	code = tiff_set_fields_for_printer(pdev, tfdev->tiff[comp_num]);
1582 	tiff_set_gray_fields(pdev, tfdev->tiff[comp_num], 1, tfdev->Compression, tfdev->MaxStripSize);
1583 	pdev->color_info.depth = save_depth;
1584         if (code < 0)
1585 	    return code;
1586 
1587     }	/* end initialization of separation files */
1588 
1589 
1590     {	/* Get the expanded contone line, halftone and write out the dithered separations */
1591         int raster = gdev_prn_raster(pdev);
1592 	int width = tfdev->width;
1593 	int dithered_raster = ((7 + width) / 8) + ARCH_SIZEOF_LONG;
1594 	int pixel, y;
1595 	byte *line = gs_alloc_bytes(pdev->memory, raster, "tiffsep1_print_page");
1596 	byte *unpacked = gs_alloc_bytes(pdev->memory, width * num_comp,
1597 							"tiffsep1_print_page");
1598 	/* the dithered_line is assumed to be 32-bit aligned by the alloc */
1599 	uint32_t *dithered_line = (uint32_t *)gs_alloc_bytes(pdev->memory, dithered_raster,
1600 				"tiffsep1_print_page");
1601 	byte *row;
1602 
1603 	if (line == NULL || unpacked == NULL || dithered_line == NULL)
1604 	    return_error(gs_error_VMerror);
1605 
1606         /* Loop for the lines */
1607 	for (y = 0; y < pdev->height; ++y) {
1608 	    code = gdev_prn_get_bits(pdev, y, line, &row);
1609 	    if (code < 0)
1610 		break;
1611 	    /* Unpack the encoded color info */
1612 	    non_encodable_count += devn_unpack_row((gx_device *)pdev, num_comp,
1613 			    &(tfdev->devn_params), width, row, unpacked);
1614 	    /* Dither the separation and write it out (tiffpack format) */
1615             for (comp_num = 0; comp_num < num_comp; comp_num++ ) {
1616 
1617 /***** #define SKIP_HALFTONING_FOR_TIMING *****/ /* uncomment for timing test */
1618 #ifndef SKIP_HALFTONING_FOR_TIMING
1619 
1620 /*
1621  * Define 32-bit writes by default. Testing shows that while this is more
1622  * complex code, it runs measurably and consistently faster than the more
1623  * obvious 8-bit code. The 8-bit code is kept to help future optimization
1624  * efforts determine what affects tight loop optimization. Subtracting the
1625  * time when halftoning is skipped shows that the 32-bit halftoning is
1626  * 27% faster.
1627  *
1628  * The compressed color encoding has a much more significant impact on
1629  * the performance. On a 33 file test suite with spot colors, uncompressed
1630  * encoding (which is limited to CMYK + 4 spot colors) ran almost twice
1631  * the speed of compressed color encoding.
1632  */
1633 #define USE_32_BIT_WRITES
1634 		byte *thresh_line_base = tfdev->thresholds[comp_num].dstart +
1635 				    ((y % tfdev->thresholds[comp_num].dheight) *
1636 					tfdev->thresholds[comp_num].dwidth) ;
1637 		byte *thresh_ptr = thresh_line_base;
1638 		byte *thresh_limit = thresh_ptr + tfdev->thresholds[comp_num].dwidth;
1639 		byte *src = unpacked + comp_num;
1640 #ifdef USE_32_BIT_WRITES
1641 		uint32_t *dest = dithered_line;
1642 		uint32_t val = 0;
1643 		uint32_t *mask = &bit_order[0];
1644 #else	/* example 8-bit code */
1645 		byte *dest = dithered_line;
1646 		byte val = 0;
1647 		byte mask = 0x80;
1648 #endif /* USE_32_BIT_WRITES */
1649 
1650 		for (pixel = 0; pixel < width; pixel++, src += num_comp) {
1651 #ifdef USE_32_BIT_WRITES
1652 		    if (*src < *thresh_ptr++)
1653 		        val |= *mask;
1654 		    if (++mask == &(bit_order[32])) {
1655 			*dest++ = val;
1656 			val = 0;
1657 			mask = &bit_order[0];
1658 		    }
1659 #else	/* example 8-bit code */
1660 		    if (*src < *thresh_ptr++)
1661 		        val |= mask;
1662 		    mask >>= 1;
1663 		    if (mask == 0) {
1664 			*dest++ = val;
1665 			val = 0;
1666 			mask = 0x80;
1667 		    }
1668 #endif /* USE_32_BIT_WRITES */
1669 		    if (thresh_ptr >= thresh_limit)
1670 			thresh_ptr = thresh_line_base;
1671                 } /* end src pixel loop - collect last bits if any */
1672 		/* the following relies on their being enough 'pad' in dithered_line */
1673 #ifdef USE_32_BIT_WRITES
1674 		if (mask != &bit_order[0]) {
1675 		    *dest = val;
1676 		}
1677 #else	/* example 8-bit code */
1678 		if (mask != 0x80) {
1679 		    *dest = val;
1680 		}
1681 #endif /* USE_32_BIT_WRITES */
1682 #endif /* SKIP_HALFTONING_FOR_TIMING */
1683 		TIFFWriteScanline(tfdev->tiff[comp_num], (tdata_t)dithered_line, y, 0);
1684 	    } /* end component loop */
1685 	}
1686 	/* Update the strip data */
1687         for (comp_num = 0; comp_num < num_comp; comp_num++ )
1688 	    TIFFWriteDirectory(tfdev->tiff[comp_num]);
1689 	gs_free_object(pdev->memory, line, "tiffsep1_print_page");
1690 	gs_free_object(pdev->memory, dithered_line, "tiffsep1_print_page");
1691     }
1692 
1693     /*
1694      * If we have any non encodable pixels then signal an error.
1695      */
1696     if (non_encodable_count) {
1697         dlprintf1("WARNING:  Non encodable pixels = %d\n", non_encodable_count);
1698 	return_error(gs_error_rangecheck);
1699     }
1700 
1701     return code;
1702 }
1703