xref: /plan9/sys/src/cmd/gs/src/gdevcfax.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 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: gdevcfax.c,v 1.5 2002/02/21 22:24:51 giles Exp $ */
18 /* SFF format writer for CAPI fax devices */
19 #include "gdevprn.h"
20 #include "strimpl.h"
21 #include "scfx.h"
22 #include "gdevfax.h"
23 
24 /* The device descriptor */
25 private dev_proc_print_page(cfax_print_page);
26 private dev_proc_close_device(cfax_prn_close);
27 
28 /* Define procedures for cfax. For sff multipage documents  */
29 /* a special close procedure is required because sff needs  */
30 /* an additional "end of document" signature after the last */
31 /* "end page" signature */
32 private const gx_device_procs gdev_cfax_std_procs =
33     prn_params_procs(gdev_prn_open, gdev_prn_output_page, cfax_prn_close,
34 		     gdev_fax_get_params, gdev_fax_put_params);
35 
36 const gx_device_fax gs_cfax_device = {
37     FAX_DEVICE_BODY(gx_device_fax, gdev_cfax_std_procs, "cfax", cfax_print_page)
38 };
39 
40 /* ---------------- SFF output ----------------- */
41 
42 private void
cfax_byte(uint c,FILE * file)43 cfax_byte(uint c, FILE * file)
44 {
45     fputc(c & 0xff, file);
46 }
47 
48 private void
cfax_word(ushort c,FILE * file)49 cfax_word(ushort c, FILE * file)
50 {
51     cfax_byte(c & 0xff, file);
52     cfax_byte(c >> 8, file);
53 }
54 
55 private void
cfax_dword(ulong c,FILE * file)56 cfax_dword(ulong c, FILE * file)
57 {
58     cfax_byte(c & 0xff, file);
59     cfax_byte(c >> 8, file);
60     cfax_byte(c >> 16, file);
61     cfax_byte(c >> 24, file);
62 }
63 
64 private void
cfax_doc_hdr(FILE * file)65 cfax_doc_hdr(FILE * file)
66 {
67     cfax_byte('S', file);
68     cfax_byte('f', file);
69     cfax_byte('f', file);
70     cfax_byte('f', file);
71     cfax_byte(1, file);
72     cfax_byte(0, file);
73     cfax_word(0, file);
74     cfax_word(0, file);
75     cfax_word(20, file);
76     cfax_dword(0, file);
77     cfax_dword(0, file);
78 }
79 
80 private void
cfax_page_hdr(gx_device_printer * pdev,FILE * file)81 cfax_page_hdr(gx_device_printer * pdev, FILE * file)
82 {
83     cfax_byte(254, file);
84     cfax_byte(16, file);
85     cfax_byte((pdev->y_pixels_per_inch < 100 ? 0 : 1), file);
86     cfax_byte(0, file);
87     cfax_byte(0, file);
88     cfax_byte(0, file);
89     cfax_word(pdev->width, file);
90     cfax_word(pdev->height, file);
91     cfax_dword(0, file);
92     cfax_dword(0, file);
93 }
94 
95 private void
cfax_doc_end(FILE * file)96 cfax_doc_end(FILE * file)
97 {
98     cfax_byte(254, file);
99     cfax_byte(0, file);
100 }
101 
102 /* Send the page to the printer. */
103 private int
cfax_stream_print_page_width(gx_device_printer * pdev,FILE * prn_stream,const stream_template * temp,stream_state * ss,int width)104 cfax_stream_print_page_width(gx_device_printer * pdev, FILE * prn_stream,
105 			     const stream_template * temp, stream_state * ss,
106                		     int width)
107 {
108     gs_memory_t *mem = pdev->memory;
109     int code = 0;
110     stream_cursor_read r;
111     stream_cursor_write w;
112     int in_size = gdev_prn_raster((gx_device *) pdev);
113     /*
114      * Because of the width adjustment for fax systems, width may
115      * be different from (either greater than or less than) pdev->width.
116      * Allocate a large enough buffer to account for this.
117      */
118     int col_size = (width * pdev->color_info.depth + 7) >> 3;
119     int max_size = max(in_size, col_size);
120     int lnum, nbytes, i;
121     byte *in;
122     byte *out;
123     /* If the file is 'nul', don't even do the writes. */
124     bool nul = !strcmp(pdev->fname, "nul");
125 
126     /* Initialize the common part of the encoder state. */
127     ss->template = temp;
128     ss->memory = mem;
129 
130     /* Allocate the buffers. */
131     in = gs_alloc_bytes(mem, temp->min_in_size + max_size + 1,
132     	"cfax_stream_print_page(in)");
133 
134 #define OUT_SIZE 1000
135     out = gs_alloc_bytes(mem, OUT_SIZE, "cfax_stream_print_page(out)");
136     if (in == 0 || out == 0) {
137 	code = gs_note_error(gs_error_VMerror);
138 	goto done;
139     }
140 
141     /* Process the image */
142     for (lnum = 0; lnum < pdev->height; lnum++) {
143 	/* Initialize read and write pointer each time, because they're getting modified */
144 	r.ptr = in - 1;
145     	r.limit = in + col_size;
146     	w.ptr = out - 1;
147     	w.limit = w.ptr + OUT_SIZE;
148 	/* Decoder must encode line for line, so init it for each line */
149 	code = (*temp->init) (ss);
150 	if (code < 0)
151 	    return_error(gs_error_limitcheck);
152 	/* Now, get the bits and encode them */
153 	gdev_prn_copy_scan_lines(pdev, lnum, in, in_size);
154 	if (col_size > in_size) {
155 	    memset(in + in_size , 0, col_size - in_size);
156         }
157 	code = (*temp->process) (ss, &r, &w, 1 /* always last line */);
158 	nbytes = w.ptr - out + 1;
159 	if (!nul) {
160 	    if (nbytes > 0) {
161 		if (nbytes < 217) {
162 		    cfax_byte(nbytes, prn_stream);
163 		    for (i = 0; i < nbytes; i++)
164 			  cfax_byte(out[i], prn_stream);
165 		} else {
166 		    cfax_byte(0, prn_stream);
167 		    cfax_word(nbytes, prn_stream);
168 		    for (i = 0; i < nbytes; i++)
169 			  cfax_byte(out[i], prn_stream);
170 		}
171 	    } else {
172 		cfax_byte(218, prn_stream);
173 	    }
174 	}
175 	if (temp->release != 0)
176 	    (*temp->release) (ss);
177     }
178 #undef OUT_SIZE
179 
180   done:
181     gs_free_object(mem, out, "cfax_stream_print_page(out)");
182     gs_free_object(mem, in, "cfax_stream_print_page(in)");
183     return code;
184 }
185 
186 /* Begin a capi fax page. */
187 private int
cfax_begin_page(gx_device_printer * pdev,FILE * fp,int width)188 cfax_begin_page(gx_device_printer * pdev, FILE * fp, int width)
189 {
190     /* Patch the width to reflect fax page width adjustment. */
191     int save_width = pdev->width;
192 
193     pdev->width = width;
194     if (gdev_prn_file_is_new(pdev)) {
195 	cfax_doc_hdr(fp);
196     }
197     cfax_page_hdr(pdev, fp);
198 
199     pdev->width = save_width;
200     return 0;
201 }
202 
203 /* Print an capi fax (sff-encoded) page. */
204 private int
cfax_print_page(gx_device_printer * pdev,FILE * prn_stream)205 cfax_print_page(gx_device_printer * pdev, FILE * prn_stream)
206 {
207     stream_CFE_state state;
208     int code;
209 
210     gdev_fax_init_fax_state(&state, (gx_device_fax *)pdev);
211     state.EndOfLine = false;
212     state.EndOfBlock = false;
213     state.EncodedByteAlign = true;
214     state.FirstBitLowOrder = true;
215     state.K = 0;
216 
217     cfax_begin_page(pdev, prn_stream, state.Columns);
218     code = cfax_stream_print_page_width(pdev, prn_stream,
219       &s_CFE_template, (stream_state *) &state, state.Columns);
220     return code;
221 }
222 
223 /* Close an capi fax (sff-encoded) document. */
224 private int
cfax_prn_close(gx_device * pdev)225 cfax_prn_close(gx_device * pdev)
226 {
227     gx_device_printer * const ppdev = (gx_device_printer *)pdev;
228 
229     if (ppdev->file != NULL) {
230       cfax_doc_end(ppdev->file);
231     }
232     return gdev_prn_close(pdev);
233 }
234