2 |
- |
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
|
|
|
52 |
gdev_fax_open(gx_device * dev)
|
|
|
53 |
{
|
|
|
54 |
return gdev_prn_open(dev);
|
|
|
55 |
}
|
|
|
56 |
|
|
|
57 |
/* Get/put the AdjustWidth parameter. */
|
|
|
58 |
int
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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
|
|
|
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 |
}
|