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: gdevfax.c,v 1.4 2002/02/21 22:24:51 giles Exp $ */
18 /* Fax devices */
19 #include "gdevprn.h"
20 #include "strimpl.h"
21 #include "scfx.h"
22 #include "gdevfax.h"
23
24 /* The device descriptors */
25 private dev_proc_print_page(faxg3_print_page);
26 private dev_proc_print_page(faxg32d_print_page);
27 private dev_proc_print_page(faxg4_print_page);
28
29 /* Define procedures that adjust the paper size. */
30 const gx_device_procs gdev_fax_std_procs =
31 prn_params_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
32 gdev_fax_get_params, gdev_fax_put_params);
33
34 #define FAX_DEVICE(dname, print_page)\
35 {\
36 FAX_DEVICE_BODY(gx_device_fax, gdev_fax_std_procs, dname, print_page)\
37 }
38
39
40 const gx_device_fax gs_faxg3_device =
41 FAX_DEVICE("faxg3", faxg3_print_page);
42
43 const gx_device_fax gs_faxg32d_device =
44 FAX_DEVICE("faxg32d", faxg32d_print_page);
45
46 const gx_device_fax gs_faxg4_device =
47 FAX_DEVICE("faxg4", faxg4_print_page);
48
49 /* Open the device. */
50 /* This is no longer needed: we retain it for client backward compatibility. */
51 int
gdev_fax_open(gx_device * dev)52 gdev_fax_open(gx_device * dev)
53 {
54 return gdev_prn_open(dev);
55 }
56
57 /* Get/put the AdjustWidth parameter. */
58 int
gdev_fax_get_params(gx_device * dev,gs_param_list * plist)59 gdev_fax_get_params(gx_device * dev, gs_param_list * plist)
60 {
61 gx_device_fax *const fdev = (gx_device_fax *)dev;
62 int code = gdev_prn_get_params(dev, plist);
63 int ecode = code;
64
65 if ((code = param_write_int(plist, "AdjustWidth", &fdev->AdjustWidth)) < 0)
66 ecode = code;
67 return ecode;
68 }
69 int
gdev_fax_put_params(gx_device * dev,gs_param_list * plist)70 gdev_fax_put_params(gx_device * dev, gs_param_list * plist)
71 {
72 gx_device_fax *const fdev = (gx_device_fax *)dev;
73 int ecode = 0;
74 int code;
75 int aw = fdev->AdjustWidth;
76 const char *param_name;
77
78 switch (code = param_read_int(plist, (param_name = "AdjustWidth"), &aw)) {
79 case 0:
80 if (aw >= 0 && aw <= 1)
81 break;
82 code = gs_error_rangecheck;
83 default:
84 ecode = code;
85 param_signal_error(plist, param_name, ecode);
86 case 1:
87 break;
88 }
89
90 if (ecode < 0)
91 return ecode;
92 code = gdev_prn_put_params(dev, plist);
93 if (code < 0)
94 return code;
95
96 fdev->AdjustWidth = aw;
97 return code;
98 }
99
100 /* Initialize the stream state with a set of default parameters. */
101 /* These select the same defaults as the CCITTFaxEncode filter, */
102 /* except we set BlackIs1 = true. */
103 private void
gdev_fax_init_state_adjust(stream_CFE_state * ss,const gx_device_fax * fdev,int adjust_width)104 gdev_fax_init_state_adjust(stream_CFE_state *ss,
105 const gx_device_fax *fdev,
106 int adjust_width)
107 {
108 s_CFE_template.set_defaults((stream_state *)ss);
109 ss->Columns = fdev->width;
110 ss->Rows = fdev->height;
111 ss->BlackIs1 = true;
112 if (adjust_width > 0) {
113 /* Adjust the page width to a legal value for fax systems. */
114 if (ss->Columns >= 1680 && ss->Columns <= 1736) {
115 /* Adjust width for A4 paper. */
116 ss->Columns = 1728;
117 } else if (ss->Columns >= 2000 && ss->Columns <= 2056) {
118 /* Adjust width for B4 paper. */
119 ss->Columns = 2048;
120 }
121 }
122 }
123 void
gdev_fax_init_state(stream_CFE_state * ss,const gx_device_fax * fdev)124 gdev_fax_init_state(stream_CFE_state *ss, const gx_device_fax *fdev)
125 {
126 gdev_fax_init_state_adjust(ss, fdev, 1);
127 }
128 void
gdev_fax_init_fax_state(stream_CFE_state * ss,const gx_device_fax * fdev)129 gdev_fax_init_fax_state(stream_CFE_state *ss, const gx_device_fax *fdev)
130 {
131 gdev_fax_init_state_adjust(ss, fdev, fdev->AdjustWidth);
132 }
133
134 /*
135 * Print one strip with fax compression. Fax devices call this once per
136 * page; TIFF devices call this once per strip.
137 */
138 int
gdev_fax_print_strip(gx_device_printer * pdev,FILE * prn_stream,const stream_template * temp,stream_state * ss,int width,int row_first,int row_end)139 gdev_fax_print_strip(gx_device_printer * pdev, FILE * prn_stream,
140 const stream_template * temp, stream_state * ss,
141 int width, int row_first, int row_end /* last + 1 */)
142 {
143 gs_memory_t *mem = pdev->memory;
144 int code;
145 stream_cursor_read r;
146 stream_cursor_write w;
147 int in_size = gdev_mem_bytes_per_scan_line((gx_device *) pdev);
148 /*
149 * Because of the width adjustment for fax systems, width may
150 * be different from (either greater than or less than) pdev->width.
151 * Allocate a large enough buffer to account for this.
152 */
153 int col_size = (width * pdev->color_info.depth + 7) >> 3;
154 int max_size = max(in_size, col_size);
155 int lnum;
156 byte *in;
157 byte *out;
158 /* If the file is 'nul', don't even do the writes. */
159 bool nul = !strcmp(pdev->fname, "nul");
160
161 /* Initialize the common part of the encoder state. */
162 ss->template = temp;
163 ss->memory = mem;
164 /* Now initialize the encoder. */
165 code = temp->init(ss);
166 if (code < 0)
167 return_error(gs_error_limitcheck); /* bogus, but as good as any */
168
169 /* Allocate the buffers. */
170 in = gs_alloc_bytes(mem, temp->min_in_size + max_size + 1,
171 "gdev_stream_print_page(in)");
172 #define OUT_SIZE 1000
173 out = gs_alloc_bytes(mem, OUT_SIZE, "gdev_stream_print_page(out)");
174 if (in == 0 || out == 0) {
175 code = gs_note_error(gs_error_VMerror);
176 goto done;
177 }
178 /* Set up the processing loop. */
179 lnum = 0;
180 r.ptr = r.limit = in - 1;
181 w.ptr = out - 1;
182 w.limit = w.ptr + OUT_SIZE;
183 #undef OUT_SIZE
184
185 /* Process the image. */
186 for (lnum = row_first; ;) {
187 int status;
188
189 if_debug7('w', "[w]lnum=%d r=0x%lx,0x%lx,0x%lx w=0x%lx,0x%lx,0x%lx\n", lnum,
190 (ulong)in, (ulong)r.ptr, (ulong)r.limit,
191 (ulong)out, (ulong)w.ptr, (ulong)w.limit);
192 status = temp->process(ss, &r, &w, lnum == row_end);
193 if_debug7('w', "...%d, r=0x%lx,0x%lx,0x%lx w=0x%lx,0x%lx,0x%lx\n", status,
194 (ulong)in, (ulong)r.ptr, (ulong)r.limit,
195 (ulong)out, (ulong)w.ptr, (ulong)w.limit);
196 switch (status) {
197 case 0: /* need more input data */
198 if (lnum == row_end)
199 goto ok;
200 {
201 uint left = r.limit - r.ptr;
202
203 memcpy(in, r.ptr + 1, left);
204 gdev_prn_copy_scan_lines(pdev, lnum++, in + left, in_size);
205 /* Note: we use col_size here, not in_size. */
206 if (col_size > in_size) {
207 memset(in + left + in_size, 0, col_size - in_size);
208 }
209 r.limit = in + left + col_size - 1;
210 r.ptr = in - 1;
211 }
212 break;
213 case 1: /* need to write output */
214 if (!nul)
215 fwrite(out, 1, w.ptr + 1 - out, prn_stream);
216 w.ptr = out - 1;
217 break;
218 }
219 }
220
221 ok:
222 /* Write out any remaining output. */
223 if (!nul)
224 fwrite(out, 1, w.ptr + 1 - out, prn_stream);
225
226 done:
227 gs_free_object(mem, out, "gdev_stream_print_page(out)");
228 gs_free_object(mem, in, "gdev_stream_print_page(in)");
229 if (temp->release)
230 temp->release(ss);
231 return code;
232 }
233
234 /* Print a fax page. Other fax drivers use this. */
235 int
gdev_fax_print_page(gx_device_printer * pdev,FILE * prn_stream,stream_CFE_state * ss)236 gdev_fax_print_page(gx_device_printer * pdev, FILE * prn_stream,
237 stream_CFE_state * ss)
238 {
239 return gdev_fax_print_strip(pdev, prn_stream, &s_CFE_template,
240 (stream_state *)ss, ss->Columns,
241 0, pdev->height);
242 }
243
244 /* Print a 1-D Group 3 page. */
245 private int
faxg3_print_page(gx_device_printer * pdev,FILE * prn_stream)246 faxg3_print_page(gx_device_printer * pdev, FILE * prn_stream)
247 {
248 stream_CFE_state state;
249
250 gdev_fax_init_fax_state(&state, (gx_device_fax *)pdev);
251 state.EndOfLine = true;
252 state.EndOfBlock = false;
253 return gdev_fax_print_page(pdev, prn_stream, &state);
254 }
255
256 /* Print a 2-D Group 3 page. */
257 private int
faxg32d_print_page(gx_device_printer * pdev,FILE * prn_stream)258 faxg32d_print_page(gx_device_printer * pdev, FILE * prn_stream)
259 {
260 stream_CFE_state state;
261
262 gdev_fax_init_fax_state(&state, (gx_device_fax *)pdev);
263 state.K = (pdev->y_pixels_per_inch < 100 ? 2 : 4);
264 state.EndOfLine = true;
265 state.EndOfBlock = false;
266 return gdev_fax_print_page(pdev, prn_stream, &state);
267 }
268
269 /* Print a Group 4 page. */
270 private int
faxg4_print_page(gx_device_printer * pdev,FILE * prn_stream)271 faxg4_print_page(gx_device_printer * pdev, FILE * prn_stream)
272 {
273 stream_CFE_state state;
274
275 gdev_fax_init_fax_state(&state, (gx_device_fax *)pdev);
276 state.K = -1;
277 state.EndOfBlock = false;
278 return gdev_fax_print_page(pdev, prn_stream, &state);
279 }
280