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