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