1
/* Copyright (C) 2001-2012 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied,
8
modified or distributed except as expressly authorized under the terms
9
of the license contained in the file LICENSE in this distribution.
11
Refer to licensing information at http://www.artifex.com or contact
12
Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13
CA 94903, U.S.A., +1(415)492-9861, for further information.
23
/* The device descriptors */
24
static dev_proc_print_page(faxg3_print_page);
25
static dev_proc_print_page(faxg32d_print_page);
26
static dev_proc_print_page(faxg4_print_page);
28
/* Define procedures that adjust the paper size. */
29
/* Since the print_page doesn't alter the device, this device can print in the background */
30
const gx_device_procs gdev_fax_std_procs =
31
prn_params_procs(gdev_prn_open, gdev_prn_bg_output_page, gdev_prn_close,
32
gdev_fax_get_params, gdev_fax_put_params);
34
#define FAX_DEVICE(dname, print_page)\
36
FAX_DEVICE_BODY(gx_device_fax, gdev_fax_std_procs, dname, print_page)\
39
const gx_device_fax gs_faxg3_device =
40
FAX_DEVICE("faxg3", faxg3_print_page);
42
const gx_device_fax gs_faxg32d_device =
43
FAX_DEVICE("faxg32d", faxg32d_print_page);
45
const gx_device_fax gs_faxg4_device =
46
FAX_DEVICE("faxg4", faxg4_print_page);
48
/* Open the device. */
49
/* This is no longer needed: we retain it for client backward compatibility. */
51
gdev_fax_open(gx_device * dev)
53
return gdev_prn_open(dev);
56
/* Get/put the fax parameters: AdjustWidth and MinFeatureSize */
58
gdev_fax_get_params(gx_device * dev, gs_param_list * plist)
60
gx_device_fax *const fdev = (gx_device_fax *)dev;
61
int code = gdev_prn_get_params(dev, plist);
64
if ((code = param_write_int(plist, "AdjustWidth", &fdev->AdjustWidth)) < 0)
66
if ((code = param_write_int(plist, "MinFeatureSize", &fdev->MinFeatureSize)) < 0)
71
gdev_fax_put_params(gx_device * dev, gs_param_list * plist)
73
gx_device_fax *const fdev = (gx_device_fax *)dev;
76
int aw = fdev->AdjustWidth;
77
int mfs = fdev->MinFeatureSize;
78
const char *param_name;
80
switch (code = param_read_int(plist, (param_name = "AdjustWidth"), &aw)) {
84
code = gs_error_rangecheck;
87
param_signal_error(plist, param_name, ecode);
92
switch (code = param_read_int(plist, (param_name = "MinFeatureSize"), &mfs)) {
94
if (mfs >= 0 && mfs <= 4)
96
code = gs_error_rangecheck;
99
param_signal_error(plist, param_name, ecode);
106
code = gdev_prn_put_params(dev, plist);
110
fdev->AdjustWidth = aw;
111
fdev->MinFeatureSize = mfs;
115
/* Initialize the stream state with a set of default parameters. */
116
/* These select the same defaults as the CCITTFaxEncode filter, */
117
/* except we set BlackIs1 = true. */
119
gdev_fax_init_state_adjust(stream_CFE_state *ss,
120
const gx_device_fax *fdev,
123
s_CFE_template.set_defaults((stream_state *)ss);
124
ss->Columns = fdev->width;
125
ss->Rows = fdev->height;
127
ss->Columns = fax_adjusted_width(ss->Columns, adjust_width);
131
gdev_fax_init_state(stream_CFE_state *ss, const gx_device_fax *fdev)
133
gdev_fax_init_state_adjust(ss, fdev, 1);
136
gdev_fax_init_fax_state(stream_CFE_state *ss, const gx_device_fax *fdev)
138
gdev_fax_init_state_adjust(ss, fdev, fdev->AdjustWidth);
142
* Print one strip with fax compression. Fax devices call this once per
143
* page; TIFF devices call this once per strip.
146
gdev_fax_print_strip(gx_device_printer * pdev, FILE * prn_stream,
147
const stream_template * temp, stream_state * ss,
148
int width, int row_first, int row_end /* last + 1 */)
150
gs_memory_t *mem = pdev->memory;
152
stream_cursor_read r;
153
stream_cursor_write w;
154
int in_size = gdev_mem_bytes_per_scan_line((gx_device *) pdev);
156
* Because of the width adjustment for fax systems, width may
157
* be different from (either greater than or less than) pdev->width.
158
* Allocate a large enough buffer to account for this.
160
int col_size = (width * pdev->color_info.depth + 7) >> 3;
161
int max_size = max(in_size, col_size);
163
int row_in = row_first;
166
void *min_feature_data = NULL;
167
/* If the file is 'nul', don't even do the writes. */
168
bool nul = !strcmp(pdev->fname, "nul");
169
int lnum_in = row_in;
170
int min_feature_size = ((gx_device_fax *const)pdev)->MinFeatureSize;
172
/* Initialize the common part of the encoder state. */
175
/* Now initialize the encoder. */
176
code = temp->init(ss);
178
return_error(gs_error_limitcheck); /* bogus, but as good as any */
180
/* Allocate the buffers. */
181
in = gs_alloc_bytes(mem, temp->min_in_size + max_size + 1,
182
"gdev_stream_print_page(in)");
183
#define OUT_SIZE 1000
184
out = gs_alloc_bytes(mem, OUT_SIZE, "gdev_stream_print_page(out)");
185
if (in == 0 || out == 0) {
186
code = gs_note_error(gs_error_VMerror);
189
/* Init the min_feature_size expansion for entire image (not strip) */
190
if ((min_feature_size > 1) && (row_first == 0))
191
code = min_feature_size_init(mem, min_feature_size,
192
width, pdev->height, &min_feature_data);
193
if (min_feature_size > 1)
194
row_in = max(0, row_first-min_feature_size); /* need some data before this row */
196
/* Set up the processing loop. */
197
r.ptr = r.limit = in - 1;
199
w.limit = w.ptr + OUT_SIZE;
202
/* Process the image. */
203
for (lnum = row_in; ;) {
207
"[w]lnum=%d r=0x%lx,0x%lx,0x%lx w=0x%lx,0x%lx,0x%lx\n", lnum,
208
(ulong)in, (ulong)r.ptr, (ulong)r.limit,
209
(ulong)out, (ulong)w.ptr, (ulong)w.limit);
210
status = temp->process(ss, &r, &w, lnum == row_end);
212
"...%d, r=0x%lx,0x%lx,0x%lx w=0x%lx,0x%lx,0x%lx\n", status,
213
(ulong)in, (ulong)r.ptr, (ulong)r.limit,
214
(ulong)out, (ulong)w.ptr, (ulong)w.limit);
216
case 0: /* need more input data */
220
uint left = r.limit - r.ptr;
221
int filtered_count = in_size;
223
memcpy(in, r.ptr + 1, left);
225
if (lnum_in < row_end)
227
code = gdev_prn_copy_scan_lines(pdev, lnum_in++, in + left, in_size);
229
code = gs_note_error(code);
233
if (min_feature_size > 1)
235
min_feature_size_process(in+left, min_feature_data);
236
} while (filtered_count == 0);
237
/* Note: we use col_size here, not in_size. */
239
if (col_size > in_size) {
240
memset(in + left + in_size, 0, col_size - in_size);
242
r.limit = in + left + col_size - 1;
246
case 1: /* need to write output */
248
fwrite(out, 1, w.ptr + 1 - out, prn_stream);
255
/* Write out any remaining output. */
257
fwrite(out, 1, w.ptr + 1 - out, prn_stream);
260
if ((min_feature_size > 1) && (lnum == pdev->height))
261
min_feature_size_dnit(min_feature_data);
262
gs_free_object(mem, out, "gdev_stream_print_page(out)");
263
gs_free_object(mem, in, "gdev_stream_print_page(in)");
269
/* Print a fax page. Other fax drivers use this. */
271
gdev_fax_print_page(gx_device_printer * pdev, FILE * prn_stream,
272
stream_CFE_state * ss)
274
return gdev_fax_print_strip(pdev, prn_stream, &s_CFE_template,
275
(stream_state *)ss, ss->Columns,
279
/* Print a 1-D Group 3 page. */
281
faxg3_print_page(gx_device_printer * pdev, FILE * prn_stream)
283
stream_CFE_state state;
285
gdev_fax_init_fax_state(&state, (gx_device_fax *)pdev);
286
state.EndOfLine = true;
287
state.EndOfBlock = false;
288
return gdev_fax_print_page(pdev, prn_stream, &state);
291
/* Print a 2-D Group 3 page. */
293
faxg32d_print_page(gx_device_printer * pdev, FILE * prn_stream)
295
stream_CFE_state state;
297
gdev_fax_init_fax_state(&state, (gx_device_fax *)pdev);
298
state.K = (pdev->y_pixels_per_inch < 100 ? 2 : 4);
299
state.EndOfLine = true;
300
state.EndOfBlock = false;
301
return gdev_fax_print_page(pdev, prn_stream, &state);
304
/* Print a Group 4 page. */
306
faxg4_print_page(gx_device_printer * pdev, FILE * prn_stream)
308
stream_CFE_state state;
310
gdev_fax_init_fax_state(&state, (gx_device_fax *)pdev);
312
state.EndOfBlock = false;
313
return gdev_fax_print_page(pdev, prn_stream, &state);