1 /* Copyright (C) 1994, 2000 artofcode LLC.  All rights reserved.
2 
3   This program is free software; you can redistribute it and/or modify it
4   under the terms of the GNU General Public License as published by the
5   Free Software Foundation; either version 2 of the License, or (at your
6   option) any later version.
7 
8   This program is distributed in the hope that it will be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   General Public License for more details.
12 
13   You should have received a copy of the GNU General Public License along
14   with this program; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16 
17 */
18 
19 /*$Id: gdevpsim.c,v 1.6.2.1.2.1 2003/01/17 00:49:01 giles Exp $ */
20 /* PostScript image output device */
21 #include "gdevprn.h"
22 #include "gdevpsu.h"
23 #include "stream.h"
24 #include "strimpl.h"
25 #include "sa85x.h"
26 #include "srlx.h"
27 
28 /*
29  * There are two drivers in this file, both of which produce PostScript
30  * output consisting of a single bitmap per page.  The psmono/psgray
31  * driver produces monochrome Level 1 images using home-grown run length
32  * compression; the psrgb driver produces planar RGB Level 2 images
33  * using the RunLengthEncode filter.
34  */
35 
36 /* ---------------- Shared code ---------------- */
37 
38 /* Define the device parameters. */
39 #ifndef X_DPI
40 #  define X_DPI 300
41 #endif
42 #ifndef Y_DPI
43 #  define Y_DPI 300
44 #endif
45 
46 /* Write the file (if necessary) and page headers. */
47 private void
ps_image_write_headers(FILE * f,gx_device_printer * pdev,const char * const setup[],gx_device_pswrite_common_t * pdpc)48 ps_image_write_headers(FILE *f, gx_device_printer *pdev,
49 		       const char *const setup[],
50 		       gx_device_pswrite_common_t *pdpc)
51 {
52     if (gdev_prn_file_is_new(pdev)) {
53 	gs_rect bbox;
54 
55 	bbox.p.x = 0;
56 	bbox.p.y = 0;
57 	bbox.q.x = pdev->width / pdev->HWResolution[0] * 72.0;
58 	bbox.q.y = pdev->height / pdev->HWResolution[1] * 72.0;
59 	psw_begin_file_header(f, (gx_device *)pdev, &bbox, pdpc, false);
60 	psw_print_lines(f, setup);
61 	psw_end_file_header(f);
62     }
63     {
64 	byte buf[100];		/* arbitrary */
65 	stream s;
66 
67 	swrite_file(&s, f, buf, sizeof(buf));
68 	psw_write_page_header(&s, (gx_device *)pdev, pdpc, true, pdev->PageCount + 1);
69 	sflush(&s);
70     }
71 }
72 
73 /* ---------------- Level 1 monochrome driver ---------------- */
74 
75 /*
76  * This driver produces a bitmap in the form of a PostScript file that can
77  * be fed to any PostScript printer.  It uses a run-length compression
78  * method that executes quickly (unlike some produced by PostScript
79  * drivers!).
80  *
81  * There are two devices here, one for 1-bit black-and-white and one
82  * for 8-bit gray.  In fact, the same code could also handle 2- and
83  * 4-bit gray output.
84  */
85 
86 /* The device descriptor */
87 private dev_proc_print_page(psmono_print_page);
88 private dev_proc_close_device(psmono_close);
89 
90 const gx_device_printer gs_psmono_device =
91 prn_device(prn_std_procs, "psmono",
92 	   DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
93 	   X_DPI, Y_DPI,
94 	   0, 0, 0, 0,		/* margins */
95 	   1, psmono_print_page);
96 
97 private const gx_device_procs psgray_procs =
98 prn_color_procs(gdev_prn_open, gdev_prn_output_page, psmono_close,
99 	      gx_default_gray_map_rgb_color, gx_default_gray_map_color_rgb);
100 
101 const gx_device_printer gs_psgray_device = {
102     prn_device_body(gx_device_printer, psgray_procs, "psgray",
103 		    DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
104 		    X_DPI, Y_DPI,
105 		    0, 0, 0, 0,	/* margins */
106 		    1, 8, 255, 0, 256, 1, psmono_print_page)
107 };
108 
109 private const char *const psmono_setup[] = {
110 		/* Initialize the strings for filling runs. */
111     "/.ImageFills [ 0 1 255 {",
112     "  256 string dup 0 1 7 { 3 index put dup } for { 8 16 32 64 128 } {",
113     "    2 copy 0 exch getinterval putinterval dup",
114     "  } forall pop exch pop",
115     "} bind for ] def",
116 		/* Initialize the procedure table for input dispatching. */
117     "/.ImageProcs [",
118 		/* Stack: <buffer> <file> <xdigits> <previous> <byte> */
119     "  32 { { pop .ImageItem } } repeat",
120     "  16 { {",	/* 0x20-0x2f: (N-0x20) data bytes follow */
121     "    32 sub 3 -1 roll add 3 index exch 0 exch getinterval 2 index exch",
122     "    readhexstring pop exch pop 0 exch dup",
123     "  } bind } repeat",
124     "  16 { {",	/* 0x30-0x3f: prefix hex digit (N-0x30) to next count */
125     "    48 sub 3 -1 roll add 4 bitshift exch .ImageItem",
126     "  } bind } repeat",
127     "  32 { {",	/* 0x40-0x5f: repeat last data byte (N-0x40) times */
128     "    64 sub 3 -1 roll add .ImageFills 2 index dup length 1 sub get get",
129     "    exch 0 exch getinterval 0 3 1 roll",
130     "  } bind } repeat",
131     "  160 { { pop .ImageItem } } repeat",
132     "] readonly def",
133 		/* Read one item from a compressed image. */
134 		/* Stack contents: <buffer> <file> <xdigits> <previous> */
135     "/.ImageItem {",
136     "  2 index read pop dup .ImageProcs exch get exec",
137     "} bind def",
138 		/* Read and print an entire compressed image. */
139     "/.ImageRead {"	/* <xres> <yres> <width> <height> <bpc> .ImageRead - */
140     "  gsave [",
141 	/* Stack: xres yres width height bpc -mark- */
142     "    6 -2 roll exch 72 div 0 0 4 -1 roll -72 div 0 7 index",
143 	/* Stack: width height bpc -mark- xres/72 0 0 -yres/72 0 height */
144     "  ] { .ImageItem }",
145 	/* Stack: width height bpc <matrix> <proc> */
146     "  4 index 3 index mul 7 add 8 idiv string currentfile 0 ()",
147 	/* Stack: width height bpc <matrix> <proc> <buffer> <file> 0 () */
148     "  9 4 roll",
149 	/* Stack: <buffer> <file> 0 () width height bpc <matrix> <proc> */
150     "  image pop pop pop pop grestore",
151     "} def",
152     0
153 };
154 static const gx_device_pswrite_common_t psmono_values =
155     PSWRITE_COMMON_VALUES(1, 0 /*false*/, 1);
156 
157 #define data_run_code 0x20
158 #define xdigit_code 0x30
159 #define max_data_per_line 35
160 #define repeat_run_code 0x40
161 #define max_repeat_run_code 31
162 #define max_repeat_run 255
163 
164 /* Send the page to the printer. */
165 private void write_data_run(P4(const byte *, int, FILE *, byte));
166 private int
psmono_print_page(gx_device_printer * pdev,FILE * prn_stream)167 psmono_print_page(gx_device_printer * pdev, FILE * prn_stream)
168 {
169     int line_size = gdev_mem_bytes_per_scan_line((gx_device *) pdev);
170     int lnum;
171     byte *line = gs_alloc_bytes(pdev->memory, line_size, "psmono_print_page");
172     byte invert = (pdev->color_info.depth == 1 ? 0xff : 0);
173     gx_device_pswrite_common_t pswrite_common;
174 
175     if (line == 0)
176 	return_error(gs_error_VMerror);
177     pswrite_common = psmono_values;
178 
179     /* If this is the first page of the file, */
180     /* write the setup code. */
181     ps_image_write_headers(prn_stream, pdev, psmono_setup, &pswrite_common);
182 
183     /* Write the .ImageRead command. */
184     fprintf(prn_stream,
185 	    "%g %g %d %d %d .ImageRead\n",
186 	    pdev->HWResolution[0], pdev->HWResolution[1],
187 	    pdev->width, pdev->height, pdev->color_info.depth);
188 
189     /* Compress each scan line in turn. */
190     for (lnum = 0; lnum < pdev->height; lnum++) {
191 	const byte *p;
192 	int left = line_size;
193 	byte *data;
194 
195 	gdev_prn_get_bits(pdev, lnum, line, &data);
196 	p = data;
197 	/* Loop invariant: p + left = data + line_size. */
198 #define min_repeat_run 10
199 	while (left >= min_repeat_run) {	/* Detect a maximal run of non-repeated data. */
200 	    const byte *p1 = p;
201 	    int left1 = left;
202 	    byte b;
203 	    int count, count_left;
204 
205 	    while (left1 >= min_repeat_run &&
206 		   ((b = *p1) != p1[1] ||
207 		    b != p1[2] || b != p1[3] || b != p1[4] ||
208 		    b != p1[5] || b != p1[6] || b != p1[7] ||
209 		    b != p1[8] || b != p1[9])
210 		)
211 		++p1, --left1;
212 	    if (left1 < min_repeat_run)
213 		break;		/* no repeated data left */
214 	    write_data_run(p, (int)(p1 - p + 1), prn_stream,
215 			   invert);
216 	    /* Detect a maximal run of repeated data. */
217 	    p = ++p1 + (min_repeat_run - 1);
218 	    left = --left1 - (min_repeat_run - 1);
219 	    while (left > 0 && *p == b)
220 		++p, --left;
221 	    for (count = p - p1; count > 0;
222 		 count -= count_left
223 		) {
224 		count_left = min(count, max_repeat_run);
225 		if (count_left > max_repeat_run_code)
226 		    fputc(xdigit_code + (count_left >> 4),
227 			  prn_stream),
228 			fputc(repeat_run_code + (count_left & 0xf),
229 			      prn_stream);
230 		else
231 		    putc(repeat_run_code + count_left,
232 			 prn_stream);
233 	    }
234 	}
235 	/* Write the remaining data, if any. */
236 	write_data_run(p, left, prn_stream, invert);
237     }
238 
239     /* Clean up and return. */
240     fputs("\n", prn_stream);
241     psw_write_page_trailer(prn_stream, 1, true);
242     gs_free_object(pdev->memory, line, "psmono_print_page");
243     return 0;
244 }
245 
246 /* Close the file. */
247 private int
psmono_close(gx_device * dev)248 psmono_close(gx_device *dev)
249 {
250     psw_end_file(((gx_device_printer *)dev)->file, dev, &psmono_values, NULL,
251                  dev->PageCount);
252     return gdev_prn_close(dev);
253 }
254 
255 /* Write a run of data on the file. */
256 private void
write_data_run(const byte * data,int count,FILE * f,byte invert)257 write_data_run(const byte * data, int count, FILE * f, byte invert)
258 {
259     const byte *p = data;
260     const char *const hex_digits = "0123456789abcdef";
261     int left = count;
262     char line[sizeof(count) * 2 + max_data_per_line * 2 + 3];
263     char *q = line;
264 
265     /* Write the count. */
266 
267     if (!count)
268 	return;
269     {
270 	int shift = sizeof(count) * 8;
271 
272 	while ((shift -= 4) > 0 && (count >> shift) == 0);
273 	for (; shift > 0; shift -= 4)
274 	    *q++ = xdigit_code + ((count >> shift) & 0xf);
275 	*q++ = data_run_code + (count & 0xf);
276     }
277 
278     /* Write the data. */
279 
280     while (left > 0) {
281 	register int wcount = min(left, max_data_per_line);
282 
283 	left -= wcount;
284 	for (; wcount > 0; ++p, --wcount) {
285 	    byte b = *p ^ invert;
286 
287 	    *q++ = hex_digits[b >> 4];
288 	    *q++ = hex_digits[b & 0xf];
289 	}
290 	*q++ = '\n';
291 	fwrite(line, 1, q - line, f);
292 	q = line;
293     }
294 
295 }
296 
297 /* ---------------- Level 2 RGB driver ---------------- */
298 
299 /*
300  * This driver produces plane-separated, run-length-encoded, 24-bit RGB
301  * images suitable for a PostScript Level 2 printer.  LZW compression would
302  * be better, but Unisys' claim to own the compression algorithm and their
303  * demand for licensing and payment even for freely distributed software
304  * rule this out.
305  */
306 
307 /* The device descriptor */
308 private dev_proc_print_page(psrgb_print_page);
309 private dev_proc_close_device(psrgb_close);
310 
311 private const gx_device_procs psrgb_procs =
312 prn_color_procs(gdev_prn_open, gdev_prn_output_page, psrgb_close,
313 		gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb);
314 
315 const gx_device_printer gs_psrgb_device = {
316     prn_device_body(gx_device_printer, psrgb_procs, "psrgb",
317 		    DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
318 		    X_DPI, Y_DPI,
319 		    0, 0, 0, 0,	/* margins */
320 		    3, 24, 255, 255, 256, 256, psrgb_print_page)
321 };
322 
323 private const char *const psrgb_setup[] = {
324     "/rgbimage {",		/* <width> <height> rgbimage - */
325     "  gsave 2 copy scale /h exch def /w exch def",
326     "  /s1 w string def /s2 w string def /s3 w string def",
327     "  /f currentfile /ASCII85Decode filter /RunLengthDecode filter def",
328     "  w h 8 [w 0 0 h neg 0 h]",
329     "  {f s1 readstring pop} {f s2 readstring pop} {f s3 readstring pop}",
330     "  true 3 colorimage grestore",
331     "} bind def",
332     0
333 };
334 static const gx_device_pswrite_common_t psrgb_values =
335     PSWRITE_COMMON_VALUES(2, 0 /*false*/, 1);
336 
337 /* Send the page to the printer. */
338 private int
psrgb_print_page(gx_device_printer * pdev,FILE * prn_stream)339 psrgb_print_page(gx_device_printer * pdev, FILE * prn_stream)
340 {
341     gs_memory_t *mem = pdev->memory;
342     int width = pdev->width;
343     byte *lbuf = gs_alloc_bytes(mem, width * 3,
344 				"psrgb_print_page(lbuf)");
345     int lnum;
346     stream fs, a85s, rls;
347     stream_A85E_state a85state;
348     stream_RLE_state rlstate;
349     byte fsbuf[200];		/* arbitrary, must be >2 */
350     byte a85sbuf[100];		/* arbitrary, must be >=6 */
351     byte rlsbuf[200];		/* arbitrary, must be >128 */
352     gx_device_pswrite_common_t pswrite_common;
353     pswrite_common = psrgb_values;
354 
355     if (lbuf == 0)
356 	return_error(gs_error_VMerror);
357     ps_image_write_headers(prn_stream, pdev, psrgb_setup, &pswrite_common);
358     fprintf(prn_stream, "%d %d rgbimage\n", width, pdev->height);
359     swrite_file(&fs, prn_stream, fsbuf, sizeof(fsbuf));
360     fs.memory = 0;
361 
362     if (s_A85E_template.set_defaults)
363 	(*s_A85E_template.set_defaults) ((stream_state *) & a85state);
364     s_std_init(&a85s, a85sbuf, sizeof(a85sbuf), &s_filter_write_procs,
365 	       s_mode_write);
366     a85s.memory = 0;
367     a85state.memory = 0;
368     a85state.template = &s_A85E_template;
369     (*s_A85E_template.init) ((stream_state *) & a85state);
370     a85s.state = (stream_state *) & a85state;
371     a85s.procs.process = s_A85E_template.process;
372     a85s.strm = &fs;
373 
374     (*s_RLE_template.set_defaults) ((stream_state *) & rlstate);
375     s_std_init(&rls, rlsbuf, sizeof(rlsbuf), &s_filter_write_procs,
376 	       s_mode_write);
377     rls.memory = 0;
378     rlstate.memory = 0;
379     rlstate.template = &s_RLE_template;
380     (*s_RLE_template.init) ((stream_state *) & rlstate);
381     rls.state = (stream_state *) & rlstate;
382     rls.procs.process = s_RLE_template.process;
383     rls.strm = &a85s;
384 
385     for (lnum = 0; lnum < pdev->height; ++lnum) {
386 	byte *data;
387 	int i, c;
388 
389 	gdev_prn_get_bits(pdev, lnum, lbuf, &data);
390 	for (c = 0; c < 3; ++c) {
391 	    const byte *p;
392 
393 	    for (i = 0, p = data + c; i < width; ++i, p += 3)
394 		sputc(&rls, *p);
395 	}
396     }
397     sclose(&rls);
398     sclose(&a85s);
399     sflush(&fs);
400     fputs("\n", prn_stream);
401     psw_write_page_trailer(prn_stream, 1, true);
402     gs_free_object(mem, lbuf, "psrgb_print_page(lbuf)");
403     return 0;
404 }
405 
406 /* Close the file. */
407 private int
psrgb_close(gx_device * dev)408 psrgb_close(gx_device *dev)
409 {
410     psw_end_file(((gx_device_printer *)dev)->file, dev, &psrgb_values, NULL,
411                  dev->PageCount);
412     return gdev_prn_close(dev);
413 }
414