1
/* Copyright (C) 2001-2006 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, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
13
/* $Id: gdevfax.c 8655 2008-04-21 14:53:38Z leonardo $ */
20
/* The device descriptors */
21
static dev_proc_print_page(faxg3_print_page);
22
static dev_proc_print_page(faxg32d_print_page);
23
static dev_proc_print_page(faxg4_print_page);
25
/* Define procedures that adjust the paper size. */
26
const gx_device_procs gdev_fax_std_procs =
27
prn_params_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
28
gdev_fax_get_params, gdev_fax_put_params);
30
#define FAX_DEVICE(dname, print_page)\
32
FAX_DEVICE_BODY(gx_device_fax, gdev_fax_std_procs, dname, print_page)\
36
const gx_device_fax gs_faxg3_device =
37
FAX_DEVICE("faxg3", faxg3_print_page);
39
const gx_device_fax gs_faxg32d_device =
40
FAX_DEVICE("faxg32d", faxg32d_print_page);
42
const gx_device_fax gs_faxg4_device =
43
FAX_DEVICE("faxg4", faxg4_print_page);
45
/* Open the device. */
46
/* This is no longer needed: we retain it for client backward compatibility. */
48
gdev_fax_open(gx_device * dev)
50
return gdev_prn_open(dev);
53
/* Get/put the AdjustWidth parameter. */
55
gdev_fax_get_params(gx_device * dev, gs_param_list * plist)
57
gx_device_fax *const fdev = (gx_device_fax *)dev;
58
int code = gdev_prn_get_params(dev, plist);
61
if ((code = param_write_int(plist, "AdjustWidth", &fdev->AdjustWidth)) < 0)
66
gdev_fax_put_params(gx_device * dev, gs_param_list * plist)
68
gx_device_fax *const fdev = (gx_device_fax *)dev;
71
int aw = fdev->AdjustWidth;
72
const char *param_name;
74
switch (code = param_read_int(plist, (param_name = "AdjustWidth"), &aw)) {
76
if (aw >= 0 && aw <= 1)
78
code = gs_error_rangecheck;
81
param_signal_error(plist, param_name, ecode);
88
code = gdev_prn_put_params(dev, plist);
92
fdev->AdjustWidth = aw;
96
/* Initialize the stream state with a set of default parameters. */
97
/* These select the same defaults as the CCITTFaxEncode filter, */
98
/* except we set BlackIs1 = true. */
100
gdev_fax_init_state_adjust(stream_CFE_state *ss,
101
const gx_device_fax *fdev,
104
s_CFE_template.set_defaults((stream_state *)ss);
105
ss->Columns = fdev->width;
106
ss->Rows = fdev->height;
108
if (adjust_width > 0) {
109
/* Adjust the page width to a legal value for fax systems. */
110
if (ss->Columns >= 1680 && ss->Columns <= 1736) {
111
/* Adjust width for A4 paper. */
113
} else if (ss->Columns >= 2000 && ss->Columns <= 2056) {
114
/* Adjust width for B4 paper. */
120
gdev_fax_init_state(stream_CFE_state *ss, const gx_device_fax *fdev)
122
gdev_fax_init_state_adjust(ss, fdev, 1);
125
gdev_fax_init_fax_state(stream_CFE_state *ss, const gx_device_fax *fdev)
127
gdev_fax_init_state_adjust(ss, fdev, fdev->AdjustWidth);
131
* Print one strip with fax compression. Fax devices call this once per
132
* page; TIFF devices call this once per strip.
135
gdev_fax_print_strip(gx_device_printer * pdev, FILE * prn_stream,
136
const stream_template * temp, stream_state * ss,
137
int width, int row_first, int row_end /* last + 1 */)
139
gs_memory_t *mem = pdev->memory;
141
stream_cursor_read r;
142
stream_cursor_write w;
143
int in_size = gdev_mem_bytes_per_scan_line((gx_device *) pdev);
145
* Because of the width adjustment for fax systems, width may
146
* be different from (either greater than or less than) pdev->width.
147
* Allocate a large enough buffer to account for this.
149
int col_size = (width * pdev->color_info.depth + 7) >> 3;
150
int max_size = max(in_size, col_size);
154
/* If the file is 'nul', don't even do the writes. */
155
bool nul = !strcmp(pdev->fname, "nul");
157
/* Initialize the common part of the encoder state. */
160
/* Now initialize the encoder. */
161
code = temp->init(ss);
163
return_error(gs_error_limitcheck); /* bogus, but as good as any */
165
/* Allocate the buffers. */
166
in = gs_alloc_bytes(mem, temp->min_in_size + max_size + 1,
167
"gdev_stream_print_page(in)");
168
#define OUT_SIZE 1000
169
out = gs_alloc_bytes(mem, OUT_SIZE, "gdev_stream_print_page(out)");
170
if (in == 0 || out == 0) {
171
code = gs_note_error(gs_error_VMerror);
174
/* Set up the processing loop. */
176
r.ptr = r.limit = in - 1;
178
w.limit = w.ptr + OUT_SIZE;
181
/* Process the image. */
182
for (lnum = row_first; ;) {
185
if_debug7('w', "[w]lnum=%d r=0x%lx,0x%lx,0x%lx w=0x%lx,0x%lx,0x%lx\n", lnum,
186
(ulong)in, (ulong)r.ptr, (ulong)r.limit,
187
(ulong)out, (ulong)w.ptr, (ulong)w.limit);
188
status = temp->process(ss, &r, &w, lnum == row_end);
189
if_debug7('w', "...%d, r=0x%lx,0x%lx,0x%lx w=0x%lx,0x%lx,0x%lx\n", status,
190
(ulong)in, (ulong)r.ptr, (ulong)r.limit,
191
(ulong)out, (ulong)w.ptr, (ulong)w.limit);
193
case 0: /* need more input data */
197
uint left = r.limit - r.ptr;
199
memcpy(in, r.ptr + 1, left);
200
code = 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);
209
r.limit = in + left + col_size - 1;
213
case 1: /* need to write output */
215
fwrite(out, 1, w.ptr + 1 - out, prn_stream);
222
/* Write out any remaining output. */
224
fwrite(out, 1, w.ptr + 1 - out, prn_stream);
227
gs_free_object(mem, out, "gdev_stream_print_page(out)");
228
gs_free_object(mem, in, "gdev_stream_print_page(in)");
234
/* Print a fax page. Other fax drivers use this. */
236
gdev_fax_print_page(gx_device_printer * pdev, FILE * prn_stream,
237
stream_CFE_state * ss)
239
return gdev_fax_print_strip(pdev, prn_stream, &s_CFE_template,
240
(stream_state *)ss, ss->Columns,
244
/* Print a 1-D Group 3 page. */
246
faxg3_print_page(gx_device_printer * pdev, FILE * prn_stream)
248
stream_CFE_state state;
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);
256
/* Print a 2-D Group 3 page. */
258
faxg32d_print_page(gx_device_printer * pdev, FILE * prn_stream)
260
stream_CFE_state state;
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);
269
/* Print a Group 4 page. */
271
faxg4_print_page(gx_device_printer * pdev, FILE * prn_stream)
273
stream_CFE_state state;
275
gdev_fax_init_fax_state(&state, (gx_device_fax *)pdev);
277
state.EndOfBlock = false;
278
return gdev_fax_print_page(pdev, prn_stream, &state);