diff options
Diffstat (limited to 'gs/base/gdevfax.c')
-rw-r--r-- | gs/base/gdevfax.c | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/gs/base/gdevfax.c b/gs/base/gdevfax.c new file mode 100644 index 000000000..fcaf2c68c --- /dev/null +++ b/gs/base/gdevfax.c @@ -0,0 +1,279 @@ +/* Copyright (C) 2001-2006 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, modified + or distributed except as expressly authorized under the terms of that + license. Refer to licensing information at http://www.artifex.com/ + or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, + San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. +*/ +/* $Id$ */ +/* Fax devices */ +#include "gdevprn.h" +#include "strimpl.h" +#include "scfx.h" +#include "gdevfax.h" + +/* The device descriptors */ +static dev_proc_print_page(faxg3_print_page); +static dev_proc_print_page(faxg32d_print_page); +static dev_proc_print_page(faxg4_print_page); + +/* Define procedures that adjust the paper size. */ +const gx_device_procs gdev_fax_std_procs = + prn_params_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close, + gdev_fax_get_params, gdev_fax_put_params); + +#define FAX_DEVICE(dname, print_page)\ +{\ + FAX_DEVICE_BODY(gx_device_fax, gdev_fax_std_procs, dname, print_page)\ +} + + +const gx_device_fax gs_faxg3_device = + FAX_DEVICE("faxg3", faxg3_print_page); + +const gx_device_fax gs_faxg32d_device = + FAX_DEVICE("faxg32d", faxg32d_print_page); + +const gx_device_fax gs_faxg4_device = + FAX_DEVICE("faxg4", faxg4_print_page); + +/* Open the device. */ +/* This is no longer needed: we retain it for client backward compatibility. */ +int +gdev_fax_open(gx_device * dev) +{ + return gdev_prn_open(dev); +} + +/* Get/put the AdjustWidth parameter. */ +int +gdev_fax_get_params(gx_device * dev, gs_param_list * plist) +{ + gx_device_fax *const fdev = (gx_device_fax *)dev; + int code = gdev_prn_get_params(dev, plist); + int ecode = code; + + if ((code = param_write_int(plist, "AdjustWidth", &fdev->AdjustWidth)) < 0) + ecode = code; + return ecode; +} +int +gdev_fax_put_params(gx_device * dev, gs_param_list * plist) +{ + gx_device_fax *const fdev = (gx_device_fax *)dev; + int ecode = 0; + int code; + int aw = fdev->AdjustWidth; + const char *param_name; + + switch (code = param_read_int(plist, (param_name = "AdjustWidth"), &aw)) { + case 0: + if (aw >= 0 && aw <= 1) + break; + code = gs_error_rangecheck; + default: + ecode = code; + param_signal_error(plist, param_name, ecode); + case 1: + break; + } + + if (ecode < 0) + return ecode; + code = gdev_prn_put_params(dev, plist); + if (code < 0) + return code; + + fdev->AdjustWidth = aw; + return code; +} + +/* Initialize the stream state with a set of default parameters. */ +/* These select the same defaults as the CCITTFaxEncode filter, */ +/* except we set BlackIs1 = true. */ +static void +gdev_fax_init_state_adjust(stream_CFE_state *ss, + const gx_device_fax *fdev, + int adjust_width) +{ + s_CFE_template.set_defaults((stream_state *)ss); + ss->Columns = fdev->width; + ss->Rows = fdev->height; + ss->BlackIs1 = true; + if (adjust_width > 0) { + /* Adjust the page width to a legal value for fax systems. */ + if (ss->Columns >= 1680 && ss->Columns <= 1736) { + /* Adjust width for A4 paper. */ + ss->Columns = 1728; + } else if (ss->Columns >= 2000 && ss->Columns <= 2056) { + /* Adjust width for B4 paper. */ + ss->Columns = 2048; + } + } +} +void +gdev_fax_init_state(stream_CFE_state *ss, const gx_device_fax *fdev) +{ + gdev_fax_init_state_adjust(ss, fdev, 1); +} +void +gdev_fax_init_fax_state(stream_CFE_state *ss, const gx_device_fax *fdev) +{ + gdev_fax_init_state_adjust(ss, fdev, fdev->AdjustWidth); +} + +/* + * Print one strip with fax compression. Fax devices call this once per + * page; TIFF devices call this once per strip. + */ +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 /* last + 1 */) +{ + gs_memory_t *mem = pdev->memory; + int code; + stream_cursor_read r; + stream_cursor_write w; + int in_size = gdev_mem_bytes_per_scan_line((gx_device *) pdev); + /* + * Because of the width adjustment for fax systems, width may + * be different from (either greater than or less than) pdev->width. + * Allocate a large enough buffer to account for this. + */ + int col_size = (width * pdev->color_info.depth + 7) >> 3; + int max_size = max(in_size, col_size); + int lnum; + byte *in; + byte *out; + /* If the file is 'nul', don't even do the writes. */ + bool nul = !strcmp(pdev->fname, "nul"); + + /* Initialize the common part of the encoder state. */ + ss->template = temp; + ss->memory = mem; + /* Now initialize the encoder. */ + code = temp->init(ss); + if (code < 0) + return_error(gs_error_limitcheck); /* bogus, but as good as any */ + + /* Allocate the buffers. */ + in = gs_alloc_bytes(mem, temp->min_in_size + max_size + 1, + "gdev_stream_print_page(in)"); +#define OUT_SIZE 1000 + out = gs_alloc_bytes(mem, OUT_SIZE, "gdev_stream_print_page(out)"); + if (in == 0 || out == 0) { + code = gs_note_error(gs_error_VMerror); + goto done; + } + /* Set up the processing loop. */ + lnum = 0; + r.ptr = r.limit = in - 1; + w.ptr = out - 1; + w.limit = w.ptr + OUT_SIZE; +#undef OUT_SIZE + + /* Process the image. */ + for (lnum = row_first; ;) { + int status; + + if_debug7('w', "[w]lnum=%d r=0x%lx,0x%lx,0x%lx w=0x%lx,0x%lx,0x%lx\n", lnum, + (ulong)in, (ulong)r.ptr, (ulong)r.limit, + (ulong)out, (ulong)w.ptr, (ulong)w.limit); + status = temp->process(ss, &r, &w, lnum == row_end); + if_debug7('w', "...%d, r=0x%lx,0x%lx,0x%lx w=0x%lx,0x%lx,0x%lx\n", status, + (ulong)in, (ulong)r.ptr, (ulong)r.limit, + (ulong)out, (ulong)w.ptr, (ulong)w.limit); + switch (status) { + case 0: /* need more input data */ + if (lnum == row_end) + goto ok; + { + uint left = r.limit - r.ptr; + + memcpy(in, r.ptr + 1, left); + code = gdev_prn_copy_scan_lines(pdev, lnum++, in + left, in_size); + if (code < 0) { + gs_note_error(code); + goto done; + } + /* Note: we use col_size here, not in_size. */ + if (col_size > in_size) { + memset(in + left + in_size, 0, col_size - in_size); + } + r.limit = in + left + col_size - 1; + r.ptr = in - 1; + } + break; + case 1: /* need to write output */ + if (!nul) + fwrite(out, 1, w.ptr + 1 - out, prn_stream); + w.ptr = out - 1; + break; + } + } + + ok: + /* Write out any remaining output. */ + if (!nul) + fwrite(out, 1, w.ptr + 1 - out, prn_stream); + + done: + gs_free_object(mem, out, "gdev_stream_print_page(out)"); + gs_free_object(mem, in, "gdev_stream_print_page(in)"); + if (temp->release) + temp->release(ss); + return code; +} + +/* Print a fax page. Other fax drivers use this. */ +int +gdev_fax_print_page(gx_device_printer * pdev, FILE * prn_stream, + stream_CFE_state * ss) +{ + return gdev_fax_print_strip(pdev, prn_stream, &s_CFE_template, + (stream_state *)ss, ss->Columns, + 0, pdev->height); +} + +/* Print a 1-D Group 3 page. */ +static int +faxg3_print_page(gx_device_printer * pdev, FILE * prn_stream) +{ + stream_CFE_state state; + + gdev_fax_init_fax_state(&state, (gx_device_fax *)pdev); + state.EndOfLine = true; + state.EndOfBlock = false; + return gdev_fax_print_page(pdev, prn_stream, &state); +} + +/* Print a 2-D Group 3 page. */ +static int +faxg32d_print_page(gx_device_printer * pdev, FILE * prn_stream) +{ + stream_CFE_state state; + + gdev_fax_init_fax_state(&state, (gx_device_fax *)pdev); + state.K = (pdev->y_pixels_per_inch < 100 ? 2 : 4); + state.EndOfLine = true; + state.EndOfBlock = false; + return gdev_fax_print_page(pdev, prn_stream, &state); +} + +/* Print a Group 4 page. */ +static int +faxg4_print_page(gx_device_printer * pdev, FILE * prn_stream) +{ + stream_CFE_state state; + + gdev_fax_init_fax_state(&state, (gx_device_fax *)pdev); + state.K = -1; + state.EndOfBlock = false; + return gdev_fax_print_page(pdev, prn_stream, &state); +} |