summaryrefslogtreecommitdiff
path: root/devices/gdevupd.c
diff options
context:
space:
mode:
Diffstat (limited to 'devices/gdevupd.c')
-rw-r--r--devices/gdevupd.c7620
1 files changed, 7620 insertions, 0 deletions
diff --git a/devices/gdevupd.c b/devices/gdevupd.c
new file mode 100644
index 000000000..efffd99d8
--- /dev/null
+++ b/devices/gdevupd.c
@@ -0,0 +1,7620 @@
+/* Copyright (C) 2001-2012 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 the license contained in the file LICENSE in this distribution.
+
+ 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.
+*/
+
+
+/* gdevupd.c Revision: 1.88 */
+/* "uniprint" -- Ugly Printer Driver by Gunther Hess (ghess@elmos.de) */
+
+/* Revision-History:
+ 23-Mar-1997 - 1.43: First published version
+ 24-Mar-1997 - 1.44: gs4.03 compatible version on the web
+ 31-Mar-1997 - 1.53: First Version inside gs-fileset (limited)
+ 28-Apr-1997 - 1.54: Version intended for public gs-release
+ 4-May-1997 - 1.55: Deactivated an accidentially active Debug-Option
+ 14-Jun-1997 - 1.56: Bug-Workaround for White on White Printing (gs5.0)
+ 17-Jun-1997 - 1.57: More reasonable Fix for the above Bug
+ ...
+ 7-Jul-1997 - 1.68: NULL-Param-BUG, HR's BJC, Pwidth/-height BUG, YFlip
+ 25-Jul-1997 - 1.69: Bug-Fix: incomplete Change of PHEIGHT-Treatment
+ 4-Aug-1997 - 1.70: Arrgh: still incomplete Change of PHEIGHT-Treatment
+ 17-AUG-1997 - 1.71: Fix of BSD-sprintf bug. (returns char * there)
+ ...
+ 28-Sep-1997 - 1.77: Fixed the byte<>char and casted-lvalue Problems
+ ...
+ 12-Mar-1998 - 1.80: Some PJL-Functions, Map-Bug-Fix (by Wonder-Wolfgang)
+ 21-Oct-1998 - 1.81: Added RGB2CMY[_]K Modi (Eric Domenjoud)
+ ...
+ 27-Feb-2000 - 1.84: CMYKgenerate with forced K-Control [distributed]
+ 2-Apr-2000 - Unofficial modifications for Epson Stylus Color 300. GR
+ 5-Apr-2000 - GR fixed last row not filled bug in wrtescnm
+ 7-May-2000 - 1.85: Always BOP/EOP-Massaging for RTL-Output (Dan Coby)
+ ...
+ 7-May-2000 - 1.87: integrated stc300-code by Glenn Ramsey
+ " - 1.88: reduced "cast discards `const'" warnings to 1
+
+*/
+
+/* Canon BJC 610 additions from (hr)
+ Helmut Riegler <helmut-riegler@net4you.co.at>
+
+ The BJC-4000 can be supported very easily, only by creating the right .upp
+ parameter file. If you have this printer and you are willing to do this,
+ contact me, I'll give you the technical details (ESC codes).
+*/
+
+/* Epson Stylus Color 300 (FMT_ESCNMY) additions 2-Apr-2000.
+ Glenn Ramsey <glennr@es.co.nz>
+*/
+
+/* ------------------------------------------------------------------- */
+/* Compile-Time-Options */
+/* ------------------------------------------------------------------- */
+
+/**
+There are two compile-time options for this driver:
+ 1. UPD_SIGNAL enables interrupt detection, that aborts printing and
+ 2. UPD_MESSAGES controls the amount of messages generated by the driver
+*/
+
+#ifndef UPD_SIGNAL
+#ifdef __unix__
+#define UPD_SIGNAL 1 /** Activated, if undefined, on UNIX-Systems */
+#else /* !__unix__ */
+#define UPD_SIGNAL 0 /** Inactive on others, by default */
+#endif /* ?__unix__ */
+#endif /* UPD_SIGNAL */
+
+#ifndef UPD_MESSAGES
+#define UPD_MESSAGES UPD_M_ERROR /** Error-messages only, if not defined */
+#endif /* UPD_MESSAGES */
+
+/* ------------------------------------------------------------------- */
+/* Required Header-Files */
+/* ------------------------------------------------------------------- */
+
+#include "stdint_.h"
+
+#ifndef hess_test_INCLUDED /* A private test-Option */
+
+#include "gdevprn.h" /** Printer-superclass header */
+#include "gsparam.h" /** For the Parameter-Handling (optional) */
+
+#include <stdlib.h> /** for rand */
+#include <limits.h> /** for INT_MIN */
+#include <ctype.h> /** for isupper */
+
+#endif /* hess_test_INCLUDED A private test-Option */
+
+#if UPD_SIGNAL
+#include <signal.h> /** Only included, if UPD_SIGNAL is active (true) */
+#endif /* UPD_SIGNAL */
+
+/* ------------------------------------------------------------------- */
+/* Device-Structure (including an additional Structure-Pointer-Type) */
+/* ------------------------------------------------------------------- */
+
+typedef struct upd_s upd_t,*upd_p; /** Type & Pointer of device-specifics */
+typedef const upd_t *upd_pc; /** Pointer to constant device-specfics */
+
+typedef struct upd_device_s { /** The driver must typedef ... */
+ gx_device_common; /** common fields for all devices */
+ gx_prn_device_common; /** common fields for printing-devices */
+ gs_param_string upd_version; /** Source-Code Version */
+ upd_p upd; /** uniprint-specific extension */
+} upd_device; /** some type usually <name>_device> */
+
+/* ------------------------------------------------------------------- */
+/* Major Driver-Functions */
+/* ------------------------------------------------------------------- */
+
+static dev_proc_print_page(upd_print_page); /** print a page (required) */
+
+static dev_proc_open_device(upd_open); /** device-initialization (opt) */
+static dev_proc_close_device(upd_close); /** device-release (opt) */
+
+static dev_proc_get_params(upd_get_params); /** export parameters (opt) */
+static dev_proc_put_params(upd_put_params); /** import parameters (opt) */
+
+/**
+A `normal' Device-Driver wil only implement one of the following pairs
+of functions for the colormapping. But "uniprint" is something special and
+it really provides all four reasonable pairs and in addition to that
+a fifth set of functions, that delivers better FS-Results with KCMY.
+
+The first pair is for the mapping into a single stored component, that
+usually represents a grayscale. But nevertheless GHOSTSCRIPT deals with
+RGB-Values, but promises to deal with R==G==B-Values when asking to map.
+
+The second pair deals with RGB-Values.
+*/
+
+static dev_proc_encode_color( upd_rgb_1color); /** Gray-Gray->Index */
+static dev_proc_decode_color( upd_1color_rgb); /** Gray-Index->Gray */
+
+static dev_proc_encode_color( upd_rgb_3color); /** RGB->RGB-Index */
+static dev_proc_decode_color( upd_3color_rgb); /** RGB-Index->RGB */
+
+/**
+The third pair maps RGB-Values into four components, which one might
+expect to be KCMY-Values, but they are not: "uniprint" considers this four
+Values as White+RGB Values!
+*/
+
+static dev_proc_encode_color( upd_rgb_4color); /** RGB->WRGB-Index */
+static dev_proc_decode_color(upd_4color_rgb); /** WRGB-Index->RGB */
+
+/**
+The fourth pair deals with KCMY-Values. The Mapping-Function
+is of a different type, due to the additional argument, but the
+inverse-Function is of the same type, and expects RGB-Values to be
+deliverd into the receiving 3-Component-Array!
+*/
+
+static dev_proc_encode_color(upd_cmyk_icolor); /** KCMY->KCMY-Index */
+static dev_proc_decode_color( upd_icolor_rgb); /** KCMY->RGB-Index */
+
+/**
+The difference between the icolor-pair and the kcolor-pair is the enforced
+black-generation in the forward-mapping. that is taken into account by the
+reverse-mapping too.
+*/
+
+static dev_proc_encode_color(upd_cmyk_kcolor); /** adds black generation */
+static dev_proc_decode_color( upd_kcolor_rgb); /** watches black-gen */
+
+/**
+"ovcolor" is CMYK with Black-Generation and Undercolor-Removal, which
+is suitable for overprinting:
+ CMY' = (CMY-K')/(1-K')
+with
+ K' = min(C,M,Y)
+*/
+
+static dev_proc_encode_color(upd_rgb_ovcolor); /** RGB->CMYK-Index */
+#define upd_ovcolor_rgb upd_icolor_rgb /** CMYK-Index->RGB */
+
+/**
+"novcolor" is CMYK with Black-Generation and Undercolor-Removal, which
+is suitable for CMY / K - Printing:
+ CMY' = CMY-K'
+with
+ K' = min(C,M,Y)
+*/
+
+static dev_proc_encode_color(upd_rgb_novcolor); /** RGB->CMYK-Index */
+#define upd_novcolor_rgb upd_icolor_rgb /** CMYK-Index->RGB */
+
+/**
+For the sake of efficiency there is that bunch of functions and they
+perform no validity checks, thus it has to be assured that they are
+only active, if there is a valid device-structure for then.
+upd_procs_map performs this task.
+*/
+
+static int upd_procs_map( upd_device *udev);
+
+/* ------------------------------------------------------------------- */
+/* Prototype of the Device-Structure (the only thing exported!) */
+/* ------------------------------------------------------------------- */
+
+/**
+"uniprint" needs a procedure-table of its own, since it provides several
+optional procedures. Simpler-Drivers (e.g. non-color-drivers) may use
+prn_std_procs instead of defining their own procedure-table.
+*/
+
+#define upd_set_dev_proc(dev, p, proc) \
+ ((dev)->std_procs.p = (dev)->orig_procs.p = (proc))
+
+static gx_device_procs upd_procs = { /** Table of procedures */
+ upd_open, /** open-function, upd-special */
+ gx_default_get_initial_matrix, /** retrieve matrix */
+ gx_default_sync_output, /** sync display */
+ gdev_prn_output_page, /** superclass-print (calls back) */
+ upd_close, /** close-function, upd-special */
+ gx_default_map_rgb_color, /** RGB-mapping */
+ gx_default_map_color_rgb, /** reverse mapping */
+ NULL, /** fill_rectangle */
+ NULL, /** tile_rectangle */
+ NULL, /** copy_mono */
+ NULL, /** copy_color */
+ NULL, /** draw_line */
+ gx_default_get_bits, /** reads scanlines, e.g. for the driver */
+ upd_get_params, /** Export parameters, upd-special */
+ upd_put_params, /** Import parameters, upd-special */
+ gx_default_map_cmyk_color /** KCMY-mapping */
+}; /** */
+
+/**
+The prototype-instance of the device-structure _must_ have the name
+"gs_uniprint_device", where "uniprint" is the external name of the driver.
+This notice is bluntly copied from drivers.txt, which a potential
+driver-author should carefully read.
+
+Just to mention: this prototype is quite similar to the one, that
+"prn_device" produces and it identifies "uniprint" as a monochrome 1Bit
+device to GHOSTSCRIPT. But during the lifetime of a driver-instance
+this might change.
+
+This is the end of the part of declarations, that are common for
+color-drivers. The next sections address "uniprint"-specific data-types
+and the reader might directly skip to the section titled
+
+ upd_print_page: The main workhorse
+*/
+
+upd_device far_data gs_uniprint_device = { /** */
+ prn_device_body(upd_device, upd_procs, /** The Type and Procedures */
+ "uniprint", /** External name of the Device */
+ DEFAULT_WIDTH_10THS, /** X-Size (1/10") */
+ DEFAULT_HEIGHT_10THS, /** Y-Size (1/10") */
+ 72, 72, /** X,Y-DpI */
+ 0.0, 0.0, 0.0, 0.0, /** L,B,R,T-Margin */
+ 1, /** color_info.num_components 1/3/4 */
+ 1, /** color_info.depth 1/2/4/8/16/24/32 */
+ 1, /** color_info.max_gray # of distinct gray levels -1 (255/1) */
+ 0, /** color_info.max_color # of distinct color levels -1 (255/1/0)*/
+ 2, /** color_info.dither_grays size of gray ramp for dithering (256/2) */
+ 0, /** color_info.dither_colors size of color cube ditto (256/2/0) */
+ upd_print_page), /** Print-procedure */
+ { NULL, 0, true }, /** Driver-Version */
+ NULL /** upd-field: Initially none */
+}; /** */
+
+/* ------------------------------------------------------------------- */
+/* UPD-Data- and Prototypes */
+/* ------------------------------------------------------------------- */
+
+/*@ gdevupd.h < */
+/* ------------------------------------------------------------------- */
+/* External names of the UPD-Parameters */
+/* ------------------------------------------------------------------- */
+
+/** UPD-Parameters
+
+"uniprint" supports a hole bunch of external parameters. This Parameters
+fall into the following categories:
+
+ 0. special-string the upd_version, readonly upd_version
+ 1. choice name-indices, stored in upd->choice
+ 2. boolean single bits, stored in upd->flags
+ 3. integers single numbers, stored in upd->ints
+ 4. integer-Arrays arrays of numbers, stored in upd->int_a
+ 5. string device-commands, stored in upd->strings
+ 6. string-Arrays arrayed device-commands, stored in upd->string_a
+ 7. float-Arrays arrays of floats, stored in upd->float_a
+
+Currently there is no need for single floats, but they may be introduced in
+future versions. Since "uniprint" somtimes manipulates the contents of the
+array-variables it dynamically allocates storage for all this parameters.
+
+The following sections defines the names for this parameters in the order,
+they are stored within the mentioned dynamic fields of the upd-structure.
+A NULL-name means that the corresponding parameter is not externally visible.
+Besides the name, there is always a symbolic index #defined, that MUST match
+the Index-Number of the name.
+Actually
+*/
+
+static const char *const upd_version = "upVersion"; /** Readonly Version */
+
+/** Names for the multiple-choice-Parameters
+
+Currently there are three Parameters, that are handled as named choices.
+For each of them, there is an array of constant strings that consists of
+
+1. the Parameter-Name
+2. - n-1 the available choices.
+n. A terminating NULL
+*/
+
+static const char *const upd_mapper[] = { "upColorModel",
+#define MAP_GRAY 1 /** Monochrome & Grayscale Devices */
+"DeviceGray", /** Monochrome & Grayscale Devices */
+#define MAP_RGBW 2 /** RGB with White-Generation */
+"DeviceRGBW", /** RGB with White-Generation */
+#define MAP_RGB 3 /** RGB-Mapping */
+"DeviceRGB", /** RGB-Mapping */
+#define MAP_CMYK 4 /** CMYK-Mapping */
+"DeviceCMYK", /** CMYK-Mapping */
+#define MAP_CMYKGEN 5 /** CMYK-Mapping with Black-Generation */
+"DeviceCMYKgenerate", /** CMYK-Mapping with Black-Generation */
+#define MAP_RGBOV 6 /** RGB->CMYK with BG and UCR for CMYK */
+"DeviceRGB2CMYK", /** RGB->CMYK with BG and UCR for CMYK */
+#define MAP_RGBNOV 7 /** RGB->CMYK with BG and UCR for CMY + K */
+"DeviceRGB2CMY_K", /** RGB->CMYK with BG and UCR for CMY + K */
+NULL
+};
+
+static const char *const upd_render[] = { "upRendering",
+#define RND_FSCOMP 1 /** Componentwise Floyd-Steinberg */
+"ErrorDiffusion", /** Componentwise Floyd-Steinberg */
+#define RND_FSCMYK 2 /** CMYK-specialized 32Bit Floyd-Steinberg */
+"FSCMYK32", /** CMYK-specialized 32Bit Floyd-Steinberg */
+#define RND_FSCMY_K 3 /** CMY_K Rendering */
+"FSCMY_K",
+NULL
+};
+
+static const char *const upd_format[] = { "upOutputFormat",
+#define FMT_RAS 1 /** Generates SUN-Rasterfiles */
+"SunRaster", /** Generates SUN-Rasterfiles */
+#define FMT_EPSON 2 /** Generates X+Y-Weaved ESC/P-Output */
+"Epson", /** Generates X+Y-Weaved ESC/P-Output */
+#define FMT_ESCP2Y 3 /** Generates Y-Weaved ESC/P2-Output */
+"EscP2", /** Generates Y-Weaved ESC/P2-Output */
+#define FMT_ESCP2XY 4 /** Generates X+Y-Weaved ESC/P2-Output */
+"EscP2XY", /** Generates X+Y-Weaved ESC/P2-Output */
+#define FMT_RTL 5 /** Generates HP-PCL/RTL-Output */
+"Pcl", /** Generates HP-PCL/RTL-Output */
+#define FMT_CANON 6 /** Generates Output for Canon extended mode (hr) */
+"Canon", /** Generates Output for Canon extended mode (hr) */
+#define FMT_ESCNMY 7 /** Generates Output for Epson Stylus Color 300 (GR) */
+"EscNozzleMap", /** Generates Output for Epson Stylus Color 300 (GR) */
+NULL
+};
+
+static const char *const *const upd_choice[] = {
+#define C_MAPPER 0 /** the selected Mapper */
+ upd_mapper,
+#define C_RENDER 1 /** the selected Rendering */
+ upd_render,
+#define C_FORMAT 2 /** the selected Choice */
+ upd_format
+};
+
+/** Names for the flags (bool)
+*/
+
+static const char *const upd_flags[] = { /** */
+#define B_REVDIR ((uint32_t) 1<<0) /** FS-Dir-Flag */
+"upFSReverseDirection", /** FS-Dir-Flag */
+#define B_FIXDIR ((uint32_t) 1<<1) /** Do not alter FS-direction */
+"upFSFixedDirection", /** Do not alter FS-direction */
+#define B_FSWHITE ((uint32_t) 1<<2) /** Process white in FS */
+"upFSProcessWhiteSpace", /** Process white in FS */
+#define B_FSZERO ((uint32_t) 1<<3) /** Zero FS-Initialization */
+"upFSZeroInit", /** Zero FS-Initialization */
+
+#define B_PAGEWIDTH ((uint32_t) 1<<4) /** Adjust Width in BOP */
+"upAdjustPageWidthCommand", /** Adjust Page-Width in BOP */
+#define B_PAGELENGTH ((uint32_t) 1<<5) /** Adjust Length in BOP */
+"upAdjustPageLengthCommand", /** Adjust Page-Length in BOP */
+#define B_TOPMARGIN ((uint32_t) 1<<6) /** Adjust Top-Margin in BOP */
+"upAdjustTopMarginCommand", /** Adjust Top-Margin in BOP */
+#define B_BOTTOMMARGIN ((uint32_t) 1<<7) /** Adjust Bottom-Margin in BOP */
+"upAdjustBottomMarginCommand", /** Adjust Bottom-Margin in BOP */
+#define B_RESOLUTION ((uint32_t) 1<<8) /** Adjust Resolution in BOP */
+"upAdjustResolutionCommand", /** Adjust Resolution in BOP */
+#define B_MEDIASIZE ((uint32_t) 1<<9) /** Adjust Mediasize in BOP */
+"upAdjustMediaSize", /** Adjust Mediasize in BOP */
+
+#define B_XABS ((uint32_t) 1<<10) /** Use Absolute X-Values */
+"upFormatXabsolute", /** Use Absolute X-Values */
+#define B_YABS ((uint32_t) 1<<11) /** Use Absolute Y-Values */
+"upFormatYabsolute", /** Use Absolute Y-Values */
+
+#define B_MAP ((uint32_t) 1<<12) /** Mapping Initialized */
+"upColorModelInitialized", /** Mapping Initialized */
+#define B_BUF ((uint32_t) 1<<13) /** Raster-Buffer Initialized */
+"upRasterBufferInitialized", /** Raster-Buffer Initialized */
+#define B_RENDER ((uint32_t) 1<<14) /** Rendering Initialized */
+"upRenderingInitialized", /** Rendering Initialized */
+#define B_FORMAT ((uint32_t) 1<<15) /** Formatter Initialized */
+"upOutputFormatInitialized", /** Formatter Initialized */
+#define B_ABORT ((uint32_t) 1<<16) /** Abort on Interrupt */
+"upOutputAborted", /** Abort on Interrupt */
+#define B_ERROR ((uint32_t) 1<<17) /** Severe Error detected */
+"upErrorDetected", /** Severe Error detected */
+
+#define B_OPEN ((uint32_t) 1<<18) /** Open-Command written */
+"upWroteData", /** Open-Command written */
+
+#define B_YFLIP ((uint32_t) 1<<19) /** Mirrored printing (hr) */
+"upYFlip", /** Mirrored printing (hr) */
+
+#define B_REDUCEK ((uint32_t) 1<<20) /** CMY->Black Reduction */
+"upFSReduceK"
+
+};
+
+/** B_OK4GO: Bits required to execute the print-loop */
+
+#define B_OK4GO (B_MAP | B_BUF | B_RENDER | B_FORMAT)
+
+/** Names for the ints
+*/
+
+static const char *const upd_ints[] = {
+#define I_PWIDTH 0 /** Output-Width */
+"upOutputWidth",
+#define I_PHEIGHT 1 /** Output-Height */
+"upOutputHeight",
+#define I_OCOMP 2 /** Output-Components */
+"upOutputComponents",
+#define I_NSCNBUF 3 /** Output-Buffers */
+"upOutputBuffers",
+#define I_XSTEP 4 /** Unit-Step */
+"upOutputXStep", /* > 0 -> divide Raster-X, < 0 muliply Raster-X */
+#define I_XOFS 5 /** abs. X-Offset */
+"upOutputXOffset",
+#define I_YSTEP 6 /** Unit-Step */
+"upOutputYStep", /* > 0 -> divide Raster-Y, < 0 muliply Raster-Y */
+#define I_YOFS 7 /** abs. Y-Offset */
+"upOutputYOffset",
+#define I_PINS2WRITE 8 /** Number of Pins */
+"upOutputPins",
+
+#define I_NXPASS 9 /** X-Passes */
+"upWeaveXPasses",
+#define I_NYPASS 10 /** Y-Passes */
+"upWeaveYPasses",
+#define I_NPASS 11 /** Total # Passes */
+"upWeavePasses",
+#define I_BEG_Y 12 /** Start of normal Weaving */
+"upWeaveInitialScan",
+#define I_END_Y 13 /** End of normal Weaving */
+"upWeaveFinalScan",
+#define I_BEGSKIP 14 /** A Scan-Offset */
+"upWeaveYOffset",
+#define I_ROWS 15 /** Output rows per pass */
+"upNozzleMapRowsPerPass",
+#define I_PATRPT 16 /** mask pattern repeat interval */
+"upNozzleMapPatternRepeat"
+};
+
+/** Names for the Integer-Arrays
+*/
+
+static const char *const upd_int_a[] = { /** */
+#define IA_COLOR_INFO 0 /** external color_info */
+"upColorInfo", /** external color_info */
+
+#define IA_COMPBITS 1 /** Bits stored per Component */
+"upComponentBits", /** Bits stored per Component */
+#define IA_COMPSHIFT 2 /** Shift for the stored Bits */
+"upComponentShift", /** Shift for the stored Bits */
+#define IA_COMPORDER 3 /** Order of Output-Components */
+"upOutputComponentOrder", /** Order of Output-Components */
+
+#define IA_STD_DY 4 /** Standard-Weave Feeds */
+"upWeaveYFeeds", /** Standard-Weave Feeds */
+#define IA_STD_IX 5 /** Standard-Weave X-Passes */
+"upWeaveXStarts", /** Standard-Weave X-Start */
+#define IA_BEG_DY 6 /** Initial-Weave Feeds */
+"upWeaveInitialYFeeds", /** Initial-Weave Feeds */
+#define IA_BEG_IX 7 /** Initial-Weave X-Start */
+"upWeaveInitialXStarts", /** Initial-Weave X-Start */
+#define IA_BEGBOT 8 /** Initial-Weave #Pins */
+"upWeaveInitialPins", /** Initial-Weave #Pins */
+#define IA_END_DY 9 /** Final-Weave Feeds */
+"upWeaveFinalYFeeds", /** Final-Weave Feeds */
+#define IA_END_IX 10 /** Final-Weave X-Start */
+"upWeaveFinalXStarts", /** Final-Weave X-Start */
+#define IA_ENDTOP 11 /** Final-Weave #Pins */
+"upWeaveFinalPins", /** Final-Weave #Pins */
+#define IA_ROWMASK 12 /** The nozzle to row map */
+"upNozzleMapRowMask",
+#define IA_SCNOFS 13 /** Mask to scan map */
+"upNozzleMapMaskScanOffset"
+};
+
+/** Names of the String-Parameters
+*/
+
+static const char *const upd_strings[] = { /** */
+#define S_MODEL 0 /** Name of the Printer-Model */
+"upModel", /** Name of the Printer-Model */
+#define S_OPEN 1 /** Printer-Begin-Job */
+"upBeginJobCommand", /** Printer-Begin-Job */
+#define S_CLOSE 2 /** Printer-End-Job */
+"upEndJobCommand", /** Printer-End-Job */
+#define S_BEGIN 3 /** Printer-Begin-Page */
+"upBeginPageCommand", /** Printer-Begin-Page */
+#define S_END 4 /** Printer-End-Page */
+"upEndPageCommand", /** Printer-End-Page */
+#define S_ABORT 5 /** Printer-Abort-Command */
+"upAbortCommand", /** Printer-Abort-Command */
+
+#define S_XMOVE 6 /** X-Positioning-Command */
+"upXMoveCommand", /** X-Positioning-Command */
+#define S_XSTEP 7 /** X-Step Command (1<I_XSTEP) */
+"upXStepCommand", /** X-Step Command (1<I_XSTEP) */
+#define S_SETLF 8 /** Set-Linefeed-Command */
+"upSetLineFeedCommand", /** Set-Linefeed-Command */
+#define S_YMOVE 9 /** Y-Positioning-Command */
+"upYMoveCommand", /** Y-Positioning-Command */
+#define S_YSTEP 10 /** Y-Step Command (1<I_YSTEP) */
+"upYStepCommand" /** Y-Step Command (1<I_YSTEP) */
+}; /** */
+
+/** Names for the String-Arrays
+*/
+
+static const char *const upd_string_a[] = { /** */
+#define SA_SETCOMP 0 /** Select Components */
+"upSelectComponentCommands", /** Select Components */
+#define SA_WRITECOMP 1 /** Write Component Comands */
+"upWriteComponentCommands" /** Write Component Commands */
+}; /** */
+
+/** Names for the float-Arrays
+*/
+static const char *const upd_float_a[] = { /** */
+#define FA_WXFER 0 /** White-Transfer */
+"upWhiteTransfer", /** White-Transfer */
+#define FA_RXFER 1 /** Red-Transfer */
+"upRedTransfer", /** Red-Transfer */
+#define FA_GXFER 2 /** Green-Transfer */
+"upGreenTransfer", /** Green-Transfer */
+#define FA_BXFER 3 /** Blue-Transfer */
+"upBlueTransfer", /** Blue-Transfer */
+#define FA_KXFER 4 /** Black-Transfer */
+"upBlackTransfer", /** Black-Transfer */
+#define FA_CXFER 5 /** Cyan-Transfer */
+"upCyanTransfer", /** Cyan-Transfer */
+#define FA_MXFER 6 /** Magenta-Transfer */
+"upMagentaTransfer", /** Magenta-Transfer */
+#define FA_YXFER 7 /** Yellow-Transfer */
+"upYellowTransfer", /** Yellow-Transfer */
+#define FA_MARGINS 8 /** private Margins */
+"upMargins", /** private Margins */
+#define FA_MAP 9 /** Color-Map */
+"upColorMap" /** Color-Map */
+}; /** */
+
+/* ------------------------------------------------------------------- */
+/* UPD-specific datatypes */
+/* ------------------------------------------------------------------- */
+
+/**
+int32_t and uint32_t are 32Bit-Integer-Types used in the
+Floyd-Steinberg Algorithm and instead of gx_color_index. The
+8-Byte long's on some 64Bit-Machines are apparently useless,
+since gdevprn.c does (currently) support only 32-Bit Rasterdata.
+*/
+
+#undef INT32_MIN
+#undef INT32_MAX
+#undef UINT32_MAX
+
+#if arch_log2_sizeof_int < 2 /* int is too small */
+#define INT32_MIN LONG_MIN
+#define INT32_MAX LONG_MAX
+#define UINT32_MAX ULONG_MAX
+#else /* int is sufficient */
+#define INT32_MIN INT_MIN
+#define INT32_MAX INT_MAX
+#define UINT32_MAX UINT_MAX
+#endif /* use int or long ? */
+
+/**
+"updcmap" is used by the color-mapping functions of the driver.
+there are four cmaps in the "uniprint"-structure, one for each component.
+To be exact, it's not "4" but rather "UPD_CMAP_MAX", which is a synonym.
+*/
+
+typedef struct updcmap_s { /** */
+ gx_color_value *code; /** Values related to codes */
+ uint32_t bitmsk; /** Mask, right justified */
+ int bitshf; /** Shift to right-justify */
+ int xfer; /** Index to the Xfer-Array */
+ int bits; /** # of Bits */
+ int comp; /** Output-Number */
+ bool rise; /* Rising/Falling Curve */
+} updcmap_t, *updcmap_p; /** */
+typedef const updcmap_t *updcmap_pc;
+
+/**
+"updcomp" holds similar informations, but is used for the rendering
+*/
+
+typedef struct updcomp_s { /* Parameters for Floyd-Steinberg */
+ int32_t offset; /* Offset added to scaled values */
+ int32_t scale; /* Scale for the raw values */
+ int32_t threshold; /* Val must be larger than this to fire */
+ int32_t spotsize; /* subtracted from Val when fired */
+ uint32_t bitmsk; /* Mask */
+ int bitshf; /* shift */
+ int bits; /* # of Bits */
+ int cmap; /* Index for the Parameter-name */
+} updcomp_t, *updcomp_p; /* Parameters for Floyd-Steinberg */
+
+/** updscan is the Element of the scan-buffer. */
+
+typedef struct updscan_s { /* Single Scanline (1 Bit/Pixel) */
+ byte *bytes; /* Buffer used w. 32-Bit Words */
+ int *xbegin; /* 1st Pixel set (or nbytes<<3 if none) */
+ int *xend; /* last Pixel set (or -1, if none) */
+} updscan_t, *updscan_p; /* Single Scanline (1 Bit/Pixel) */
+
+/** Main upd-Structure ***/
+
+#define UPD_CMAP_MAX 4 /** Number of Colormaps provided */
+#define UPD_VALPTR_MAX 32 /** Number of valbuf-Pointers */
+
+#define upd_proc_pxlget(name) uint32_t name(upd_p upd)
+#define upd_proc_render(name) int name(upd_p upd)
+#define upd_proc_writer(name) int name(upd_p upd,FILE *out)
+
+struct upd_s { /* All upd-specific data */
+
+ int *choice; /** Named-Choices */
+ int *ints; /** Integers */
+ gs_param_int_array *int_a; /** Integer-Arrays */
+ gs_param_string *strings; /** Strings */
+ gs_param_string_array *string_a; /** String-Arrays */
+ gs_param_float_array *float_a; /** Float-Arrays */
+
+ updcmap_t cmap[UPD_CMAP_MAX]; /** Mapping-Data */
+
+ byte *gsbuf; /* Storage for GS-Rasterdata */
+ byte *gsscan; /* Begin of GS-Rasterdata */
+
+ byte *pxlptr; /* Source for pxlget */
+ upd_proc_pxlget( (*pxlget)); /* The Pixel-Reader */
+ upd_proc_render( (*render)); /* Actual Rendering */
+ upd_proc_writer( (*writer));
+
+ updscan_p *scnbuf; /* Output-Values */
+ int32_t *valbuf; /* Floyd-Steinberg-Buffer */
+ void *valptr[UPD_VALPTR_MAX];
+
+ byte *outbuf; /* Output-Buffer */
+ upd_proc_render( (*start_render)); /* Setup for rendering */
+ upd_proc_writer( (*start_writer)); /* Setup for writilg */
+
+ uint32_t flags; /** Some flags */
+ int pdwidth; /** pdev-width upon open */
+ int pdheight; /** pdev-height upon open */
+
+ uint ngsbuf; /* Size of gsbuf */
+ int gswidth; /* Width in GS-Pixels */
+ int gsheight; /* Height in GS-Pixels */
+
+ int rwidth; /* Rendering-Width */
+
+ int pwidth; /* Printing-Width */
+ int pheight; /* # scanlines printed */
+
+ int ncomp; /* # Components in gsbuf */
+ int nmap; /* # Entries in color-map */
+
+ uint nvalbuf; /* Size of valbuf */
+ int nscnbuf; /* Number of entries in scnbuf. */
+
+ int ocomp; /* # Components written */
+ int nbytes; /* Size of scnbuf[][].words */
+ int nlimits; /* Size of scnbuf[][].xbegin/end */
+ int scnmsk; /* Size of scanbuf - 1 */
+ uint noutbuf; /* Size of the Output-Buffer */
+
+ int ixpass; /* Current X-pass (0 ... nxpass-1) */
+ int ipass; /* Current pass (0 ... npass-1) */
+ int icomp; /* Selected Component */
+ int lf; /* Selected Line-Space */
+
+ int xprinter; /* Actual X-Position */
+
+ int yscan; /* Top-Scan (page-vari) */
+ int yprinter; /* Actual Y-Position (page-vari) */
+ int yscnbuf; /* Y not yet buffered */
+ const gs_memory_t *memory; /* Memory pointer - for errprintf */
+}; /* All upd-specific data */
+
+/* ------------------------------------------------------------------- */
+/* Various Message-Levels */
+/* ------------------------------------------------------------------- */
+
+/**
+UPD_MESSAGES, Is collection of Bits, that controls Messages
+*/
+
+#define UPD_M_NONE 0x0000 /** No Messages at all */
+#define UPD_M_ERROR 0x0001 /** Errors */
+#define UPD_M_WARNING 0x0002 /** Warnings */
+#define UPD_M_TOPCALLS 0x0004 /** Log Calls to main Functions */
+#define UPD_M_MAPCALLS 0x0008 /** Log Color-Mapping-Calls */
+#define UPD_M_SETUP 0x0010 /** Log Setup-Activity */
+#define UPD_M_FSBUF 0x0020 /** Error-Summary for valbuf */
+#define UPD_M_FMTVARS 0x0040 /** (GR) Formatting variables */
+
+/* ------------------------------------------------------------------- */
+/* The UPD-Routines */
+/* ------------------------------------------------------------------- */
+
+/**
+Besides the main routines required for the color-mapping, that were
+declared near the beginning, there are some auxillary functions.
+Most prominent are "upd_open_map" and "upd_close_map", which
+do the proper actions when opening and closing the device.
+*/
+
+static int upd_open_map( upd_device *udev);
+static int upd_close_map(upd_device *udev);
+
+/**
+But "upd_truncate" and "upd_expand" are also mentionable. They are
+the actual workhorses for the component-oriented mapping. When mapping
+the 16Bit Component-Values to the indices, some truncation takes place
+and this is what "upd_truncate" does, in the most general manner i can
+think of and with O(log(n)) in time. "upd_expand" is required for the
+reverse mapping-functions and is a constant-time `algorithm'.
+*/
+static inline uint32_t upd_truncate(upd_pc,int,gx_color_value);
+
+/* ------------------------------------------------------------------- */
+/* Return the gx_color_value for a given component */
+/* ------------------------------------------------------------------- */
+static inline gx_color_value
+upd_expand(upd_pc upd,int i,gx_color_index ci0)
+{
+ const updcmap_pc cmap = upd->cmap + i; /* Writing-Shortcut */
+ uint32_t ci = (uint32_t)((ci0 >> cmap->bitshf) & cmap->bitmsk); /* Extract the component */
+
+ if(!cmap->rise) ci = cmap->bitmsk - ci; /* Invert, if necessary */
+/* no Truncation/Expansion on full range */
+ if(gx_color_value_bits > cmap->bits) return cmap->code[ci];
+ else return (gx_color_value) ci;
+}
+/* That's simple, isn't it? */
+
+/**
+The next group of internal functions adresses the rendering. Besides
+the main-functions "upd_open_render" and "upd_close_render", there
+are groups of up to 3 Functions, for each algorithm available with
+UPD. Two routines are invoked during open and close and the third
+is called for each scanline. Actually a fourth function is provided,
+that is invoked at the beginning of each page to be printed, but the
+current algorithms do not need it.
+*/
+static void upd_open_render( upd_device *udev);
+static void upd_close_render( upd_device *udev);
+
+static void upd_open_fscomp( upd_device *udev);
+static int upd_fscomp( upd_p upd);
+static void upd_close_fscomp( upd_device *udev);
+
+static void upd_open_fscmyk( upd_device *udev);
+static int upd_fscmyk( upd_p upd);
+
+static void upd_open_fscmy_k( upd_device *udev);
+static int upd_fscmy_k( upd_p upd);
+
+/**
+I hope that the formatting stuff can be kept simple and thus most
+of the work is done inside the general open and close-functions.
+During open, there is a call to a format-specific open-function, but
+this is only for checking and determining the amount of of bytes required
+for the output-buffer (and limit-values in the scan-buffer).
+*/
+static int upd_open_writer( upd_device *udev);
+static void upd_close_writer( upd_device *udev);
+#if UPD_SIGNAL
+static void upd_signal_handler(int sig);
+#endif
+
+/**
+The first format are the uncompressed! SUN-Rasterfiles. The primary intention
+of this format is testing, but it might turn out to be useful for other
+purposes, even if the amount of generated data is huge. On the other hand
+it is a violation of UPD's rules: the start-routine computes the Begin-Page
+sequence (the Rasterfile header) since it would be a nuisance to provide
+this code within each (test-)personalization in PostScript.
+*/
+static int upd_open_rascomp( upd_device *udev);
+static int upd_start_rascomp( upd_p upd, FILE *out);
+static int upd_rascomp( upd_p upd, FILE *out);
+
+/**
+The second format is ESC/P, the format introduced with the first Epson
+impact printers. This format is used by a lot of other printers too.
+It is also uncompressed. This formatter supports X- and Y-Weaving,
+which makes it the most sophisticated one inside this driver.
+*/
+
+static void upd_limits( upd_p upd, bool check);
+static int upd_open_wrtescp( upd_device *udev);
+static int upd_wrtescp( upd_p upd, FILE *out);
+
+/**
+The third format is ESC/P2, the format use by the newer Epson-Printers.
+It allows runlength-Compression similar to the RTL/PCL-Family of Printers.
+This formatter does not allow for X-Weaving.
+
+The fourth writer is a ESC/P2-Writer, that supports X-Weaving
+*/
+static int upd_rle(byte *out,const byte *in,int nbytes);
+static int upd_open_wrtescp2( upd_device *udev);
+static int upd_wrtescp2( upd_p upd, FILE *out);
+static int upd_wrtescp2x( upd_p upd, FILE *out);
+
+/**
+The fifth writer is a HP-RTL/PCL-Writer
+*/
+
+static int upd_open_wrtrtl( upd_device *udev);
+static int upd_wrtrtl( upd_p upd, FILE *out);
+
+/**
+The sixth writer is for Canon Extended Mode (currently BJC610) (hr)
+*/
+
+static int upd_open_wrtcanon( upd_device *udev);
+static int upd_wrtcanon( upd_p upd, FILE *out);
+
+/**
+The seventh writer is for ESC P/2 Nozzle Map Mode (currently Stylus Color 300) (GR)
+*/
+
+static int upd_wrtescnm( upd_p upd, FILE *out);
+
+/**
+Generalized Pixel Get & Read
+*/
+static uint32_t upd_pxlfwd(upd_p upd);
+static uint32_t upd_pxlrev(upd_p upd);
+#define upd_pxlget(UPD) (*UPD->pxlget)(UPD)
+
+static void *upd_cast(const void *);
+
+/* ------------------------------------------------------------------- */
+/* Macros to deal with the Parameter-Memory */
+/* ------------------------------------------------------------------- */
+
+/**
+Usually the creation of copies of external parameters is not necessary,
+at least with gs-versions > 4.03. But uniprint writes to the parameters
+in some cases or creates some by itself, thus to get a unified interface
+all parameter-data are copied and thus it is legal to manipulate them.
+
+Here are several Macros, named "UPD_MM_*" to deal with that.
+*/
+
+/** UPD_MM_GET_ARRAY allocates & initializes an array of values */
+#define UPD_MM_GET_ARRAY(mem, Which,Nelts) \
+ Which = NULL; \
+ if(0 < (Nelts)) { \
+ byte *tmp = gs_malloc(mem, Nelts,sizeof(Which[0]),"uniprint/params");\
+ if(tmp) { \
+ memset(tmp,0,(Nelts)*sizeof(Which[0])); \
+ Which = (void *) tmp; \
+ } else { \
+ return_error(gs_error_VMerror); \
+ } \
+ }
+
+/** UPD_MM_DEL_ARRAY frees an array of values */
+#define UPD_MM_DEL_ARRAY(mem, Which,Nelts,Delete) \
+ if(Which && 0 < (Nelts)) { \
+ uint ii; \
+ for(ii = 0; (Nelts) > ii; ++ii) Delete(mem, Which[ii]); \
+ gs_free(mem, upd_cast(Which),Nelts,sizeof(Which[0]),"uniprint/params");\
+ } \
+ Which = 0
+
+/** UPD_MM_DEL_VALUE deletes a value, does nothing */
+#define UPD_MM_DEL_VALUE(mem, Which) /* */
+
+/** UPD_MM_DEL_PARAM deletes a single gs-array-parameter */
+#define UPD_MM_DEL_PARAM(mem, Which) { \
+ if(Which.data && Which.size) \
+ gs_free(mem, upd_cast(Which.data),Which.size,sizeof(Which.data[0]),\
+ "uniprint/params"); \
+}
+
+/** UPD_MM_DEL_APARAM deletes a nested gs-array-parameter */
+#define UPD_MM_DEL_APARAM(mem, Which) { \
+ if(Which.data && Which.size) { \
+ uint iii; \
+ for(iii = 0; iii < Which.size; ++iii) \
+ UPD_MM_DEL_PARAM(mem, Which.data[iii]); \
+ gs_free(mem, upd_cast(Which.data),Which.size,sizeof(Which.data[0]),\
+ "uniprint/params"); \
+ } \
+}
+
+/** UPD_MM_CPY_ARRAY creates a new copy of an array of values */
+#define UPD_MM_CPY_ARRAY(mem, To,From,Nelts,Copy) \
+ UPD_MM_GET_ARRAY(mem, To,Nelts); \
+ if(To && From) { \
+ uint ii; \
+ for(ii = 0; (Nelts) > ii; ++ii) Copy(mem, To[ii],From[ii]);\
+ }
+
+/** UPD_MM_CPY_VALUE Copies a simple Value */
+#define UPD_MM_CPY_VALUE(mem,To,From) To = From
+
+#define UPD_MM_CPY_VALUE_3(mem,To,From) To = From
+
+/** UPD_MM_CPY_PARAM Creates a copy of a gs-parameter */
+#define UPD_MM_CPY_PARAM(mem, To, From) \
+ if(From.data && From.size) { \
+ UPD_MM_GET_ARRAY(mem, To.data,From.size); \
+ if(To.data) { \
+ To.size = From.size; \
+ memcpy(upd_cast(To.data),From.data,To.size*sizeof(To.data[0]));\
+ } \
+ }
+
+/** UPD_MM_CPY_APARAM Creates a copy of a nested gs-parameter */
+#define UPD_MM_CPY_APARAM(mem, To,From) \
+ if(From.data && From.size) { \
+ UPD_MM_GET_ARRAY(mem, To.data,From.size); \
+ if(To.data) { \
+ gs_param_string *tmp2 = (gs_param_string *) upd_cast(To.data);\
+ uint iii; \
+ To.size = From.size; \
+ for(iii = 0; To.size > iii; ++iii) \
+ UPD_MM_CPY_PARAM(mem, tmp2[iii],From.data[iii]); \
+ } \
+ }
+
+/* ------------------------------------------------------------------- */
+/* UPD-Initialized-Data */
+/* ------------------------------------------------------------------- */
+
+/** Version-String */
+
+static const char rcsid[] = "$Revision: 5215 $";
+
+/** Default-Transfer-curve */
+
+static const float upd_data_xfer[2] = { 0.0, 1.0 };
+
+/*@ > */
+
+/* ------------------------------------------------------------------- */
+/* upd_cast: keeps some compilers more happy [dangerous] */
+/* ------------------------------------------------------------------- */
+
+static void *
+upd_cast(const void *data)
+{
+ return (void *) data;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_signal_handler: Catch interrupts */
+/* ------------------------------------------------------------------- */
+
+#if UPD_SIGNAL
+static upd_p sigupd = NULL;
+static void
+upd_signal_handler(int sig)
+{
+ if(sigupd) sigupd->flags |= B_ABORT;
+}
+#endif
+
+/* ------------------------------------------------------------------- */
+/* upd_print_page: The main workhorse */
+/* ------------------------------------------------------------------- */
+
+/**
+Function: upd_print_page
+
+This is the top-level printing routine. It works through this
+steps:
+
+ 1. Once for each generated file, the "device-open-sequence" is written.
+ 2. The "page-begin-sequence" is written.
+
+ 3. The data are generated and written:
+ 3.1: Data are converted into a "printer-family"-specific format.
+ This step includes the halftoning, if selected.
+ 3.2: Data are written with a printer-specific function.
+ There is not much code-compression inside theese functions,
+ since i observed to improvments in print-speed. Other
+ drivers do a better job in this.
+
+ 4. The "page-end-sequence" is written.
+ 5. If a one-page-per-file mode is selected, the "device-close-sequence"
+ is added to the output. For multi-page files, this writing is
+ performed in "upd_close", the drivers close-function.
+
+The routine is quite short, since all the allocation and checking
+occur in upd_open and upd_putparams. The only test, that upd_print_page
+does, is the verification wether the device is in a sane state. This
+must be done here, since during the initialisation, the device is
+usually opened several times, before obtaining a valid state.
+*/
+
+static int
+upd_print_page(gx_device_printer *pdev, FILE *out)
+{
+ upd_device *const udev = (upd_device *) pdev;
+ const upd_p upd = udev->upd;
+ const int *const ints = upd ? upd->ints : NULL;
+ int error,need,yfill;
+
+#if UPD_SIGNAL /* variables required for signal-handling only */
+ void (*oldint )(int) = NULL;
+ void (*oldterm)(int) = NULL;
+ upd_p oldupd = sigupd;
+#endif /* variables required for signal-handling only */
+
+/*
+ * Refuse to work, if not explicitly enabled during open
+ * (some/lot of allocated memory is required)
+ */
+ if(!upd || B_OK4GO != (upd->flags & (B_OK4GO | B_ERROR))) {
+#if UPD_MESSAGES & (UPD_M_ERROR | UPD_M_TOPCALLS)
+ errprintf(pdev->memory, "CALL-REJECTED upd_print_page(0x%05lx,0x%05lx)\n",
+ (long) udev,(long) out);
+#endif
+ return gs_error_undefined;
+ }
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+ errprintf(pdev->memory, "CALL: upd_print_page(0x%05lx,0x%05lx)\n",
+ (long) udev,(long) out);
+#endif
+
+#if UPD_SIGNAL /* Setup of signal-handling */
+ sigupd = upd;
+ oldint = signal(SIGINT, upd_signal_handler);
+ oldterm = signal(SIGTERM,upd_signal_handler);
+#endif /* Setup of signal-handling */
+
+/*
+ * If the OutputFile was just opened, transfer the Open-Sequence to it.
+ */
+ if(!(upd->flags & B_OPEN)) {
+
+ if(0 < upd->strings[S_OPEN].size)
+ fwrite(upd->strings[S_OPEN].data,1,upd->strings[S_OPEN].size,out);
+ upd->flags |= B_OPEN;
+ }
+/*
+ * Always write the the Page-begin-sequence
+ */
+ if(0 < upd->strings[S_BEGIN].size)
+ fwrite(upd->strings[S_BEGIN].data,1,upd->strings[S_BEGIN].size,out);
+/*
+ * Establish page-variables
+ */
+
+/* Positions */
+ upd->xprinter = 0;
+ upd->yscan = 0; /* Position we are processing */
+ upd->yprinter = 0; /* Actual Printer-Positions */
+ upd->yscnbuf = 0; /* Next free scnbuf-Line */
+
+/* Rendering & Writing Setup, if available */
+ if(upd->start_render) (*upd->start_render)(upd);
+ if(upd->start_writer) (*upd->start_writer)(upd,out);
+
+/* How many scanlines do we need ? */
+ need = ints[I_NYPASS] * ints[I_PINS2WRITE];
+ if(0 >= need) need = 1;
+
+/* The Weave-counters */
+ upd->ipass = 0;
+ upd->ixpass = 0;
+ upd->icomp = -1; /* Enforces initial selection */
+ upd->lf = -1; /* Enforces initial selection */
+/*
+ * Main Loop
+ */
+ while(upd->pheight > upd->yscan) { /* Main-Loop */
+
+/*
+ * Load as much data into the scan-buffer as possible
+ * (this is done in scan-sequence, the printing not necessarily.)
+ */
+ if(ints[I_BEGSKIP] > upd->yscan) yfill = 0;
+ else yfill = upd->yscan - ints[I_BEGSKIP];
+
+ for(yfill += upd->nscnbuf; upd->yscnbuf < yfill; upd->yscnbuf++) {
+
+ if(upd->gsheight > upd->yscnbuf) {
+
+ if(0 > (*dev_proc(udev,get_bits))((gx_device *) udev,
+ upd->yscnbuf,upd->gsbuf,&upd->gsscan)) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory, "get_bits aborted with error, yscnbuf = %4d\n",
+ upd->yscnbuf);
+#endif
+ break;
+ }
+ } else {
+
+ memset(upd->gsscan = upd->gsbuf,0,upd->ngsbuf);
+
+ }
+
+ if(0 > (*upd->render)(upd)) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory, "Rendering aborted with error, yscnbuf = %4d\n",
+ upd->yscnbuf);
+#endif
+ break;
+ }
+
+ }
+/*
+ * Did the buffering loop take an error exit ?
+ */
+ if((upd->yscnbuf ^ yfill) & upd->scnmsk) break;
+/*
+ * Print as much as possible
+ */
+ while((upd->yscan - ints[I_BEGSKIP] + need) < upd->yscnbuf) {
+
+/* first write the scan(s) */
+ (*upd->writer)(upd,out);
+
+/* Check for termination */
+ if(upd->yscan >= upd->pheight) break;
+ if(upd->flags & B_ABORT ) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory, "Printing aborted upon interrupt, yscan = %4d\n",
+ upd->yscan);
+#endif
+ break;
+ }
+ }
+/*
+ * Did the print-Loop take an error exit ?
+ */
+ if((upd->yscan - ints[I_BEGSKIP] + need) < upd->yscnbuf) break;
+ } /* Main-Loop */
+
+/*
+ * If we aborted for some reason, use the dedicated sequence
+ */
+
+ if((upd->pheight > upd->yscan) &&
+ (0 < upd->strings[S_ABORT].size)) { /* Only This! */
+ fwrite(upd->strings[S_ABORT].data,1,upd->strings[S_ABORT].size,out);
+
+ upd->flags &= ~B_OPEN; /* Inhibit Close-Sequence ! */
+/*
+ * If there is no special sequence, or we came to normal end,
+ * write the normal sequence, if any
+ */
+
+ } else if(0 < upd->strings[S_END].size) {
+ fwrite(upd->strings[S_END].data,1,upd->strings[S_END].size,out);
+ }
+/*
+ * If necessary, write the close-sequence
+ */
+ {
+ gs_parsed_file_name_t parsed;
+ const char *fmt;
+
+ if (NULL != udev->fname &&
+ 0 <= gx_parse_output_file_name(&parsed, &fmt, udev->fname,
+ strlen(udev->fname), udev->memory) &&
+ fmt
+ ) {
+ if (0 < upd->strings[S_CLOSE].size)
+ fwrite(upd->strings[S_CLOSE].data,1,upd->strings[S_CLOSE].size,out);
+ upd->flags &= ~B_OPEN;
+ }
+ }
+
+/*
+ * clean up, and return status
+ */
+
+ fflush(out); /* just to prepare for ferror */
+
+ if(upd->pheight > upd->yscan) error = gs_error_interrupt;
+ else if(ferror(out)) error = gs_error_ioerror;
+ else error = 0;
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+ errprintf(udev->memory, "RETURN: %d = upd_print_page(0x%05lx,0x%05lx)\n",
+ error,(long) udev,(long)out);
+#endif
+
+#if UPD_SIGNAL /* Restore Interrupt-state */
+ sigupd = oldupd;
+ (void) signal(SIGINT ,oldint);
+ (void) signal(SIGTERM,oldterm);
+#endif /* Restore Interrupt-state */
+
+ return error;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_open: Initialize everything for printing */
+/* ------------------------------------------------------------------- */
+/**
+"upd_open" is -through the specified table of procedures- called instead
+of the normal open-procedures for printer-devices, that performs quite
+a complex job. Thus it is necessary to call this `superclass-open´
+here.
+
+Besides that, this routine does quite a complex job too, in initializes
+everything required to print a page. This might be time-consuming, the
+alternative would be "upd_print_page", but i often print 100 pages or
+more, but i never experienced more than 5-6 open-calls.
+*/
+
+static int
+upd_open(gx_device *pdev)
+{
+ upd_device *udev = (upd_device *) pdev;
+ upd_p upd = udev->upd;
+ int error;
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+ errprintf(udev->memory, "CALL: upd_open(0x%05lx)\n",(long) pdev);
+#endif
+
+/** enforce the UPD-Margins */
+
+ if((NULL != upd) &&
+ (NULL != upd->float_a[FA_MARGINS].data) &&
+ (4 == upd->float_a[FA_MARGINS].size) ) {
+ float m[4];
+ m[1] = upd->float_a[FA_MARGINS].data[1] / 72.0;
+ m[3] = upd->float_a[FA_MARGINS].data[3] / 72.0;
+ if(B_YFLIP & upd->flags) {
+ m[0] = upd->float_a[FA_MARGINS].data[2] / 72.0;
+ m[2] = upd->float_a[FA_MARGINS].data[0] / 72.0;
+ } else {
+ m[0] = upd->float_a[FA_MARGINS].data[0] / 72.0;
+ m[2] = upd->float_a[FA_MARGINS].data[2] / 72.0;
+ }
+ gx_device_set_margins((gx_device *) udev, m, true);
+ }
+
+/** call the super-class open **/
+ error = gdev_prn_open(pdev);
+ while (pdev->child)
+ pdev = pdev->child;
+
+ udev = (upd_device *) pdev;
+ upd = udev->upd;
+
+/** invoke the subroutines, if an upd is present. */
+
+ if(upd) {
+
+ upd->flags &= ~B_OK4GO;
+
+/**
+The following initializations are run, even in case of an error in
+the super-class open, just to bring our upd into a sane state.
+*/
+ if(0 > error) upd->flags |= B_ERROR;
+
+ if(gs_error_VMerror == upd_open_map(udev)) error = gs_error_VMerror;
+
+/**
+The following piece of code is here for demonstration-purposes:
+It determines the size of the printed image and allocates the
+buffer for the raw raster-data
+*/
+ upd->gswidth = udev->width -
+ (int)((dev_l_margin(udev)+dev_r_margin(udev))*udev->x_pixels_per_inch);
+
+ upd->gsheight = udev->height -
+ (int)((dev_t_margin(udev)+dev_b_margin(udev))*udev->y_pixels_per_inch);
+
+ upd->ngsbuf = 0; /* Ensure sane values */
+ upd->gsbuf = NULL; /* Ensure sane values */
+
+ if(B_MAP & upd->flags) { /* Only if prerequisites were met */
+ uint want = gx_device_raster(pdev,true);
+ upd->gsbuf = gs_malloc(pdev->memory, want,1,"upd/gsbuf");
+
+ if(upd->gsbuf) {
+ upd->ngsbuf = want;
+ upd->flags |= B_BUF; /* Signal Success */
+ } else {
+ error = gs_error_VMerror; /* Signal Error */
+ upd->flags |= B_ERROR;
+ }
+
+ } /* Only if prerequisites were met */
+
+ upd_open_render(udev); /* First subloop in printing */
+
+ if(gs_error_VMerror == upd_open_writer(udev)) error = gs_error_VMerror;
+
+ udev->upd->pdwidth = udev->width;
+ udev->upd->pdheight = udev->height;
+
+#if UPD_MESSAGES & UPD_M_SETUP
+ if((upd->flags & (B_OK4GO | B_ERROR)) == B_OK4GO) {
+ int i,j,l,ln,lv;
+ errprintf(udev->memory,"\nupd->flags = 0x%05lx\n",(unsigned long)upd->flags);
+ errprintf(udev->memory, "upd->pdwidth = %5d\n",upd->pdwidth);
+ errprintf(udev->memory, "upd->pdheight = %5d\n",upd->pdheight);
+ errprintf(udev->memory, "upd->ngsbuf = %5u\n",upd->ngsbuf);
+ errprintf(udev->memory, "upd->gswidth = %5d\n",upd->gswidth);
+ errprintf(udev->memory, "upd->gsheight = %5d\n",upd->gsheight);
+ errprintf(udev->memory, "upd->rwidth = %5d\n",upd->rwidth);
+ errprintf(udev->memory, "upd->pwidth = %5d\n",upd->pwidth);
+ errprintf(udev->memory, "upd->pheight = %5d\n",upd->pheight);
+ errprintf(udev->memory, "upd->nvalbuf = %5u\n",upd->nvalbuf);
+ errprintf(udev->memory, "upd->nscnbuf = %5d\n",upd->nscnbuf);
+ errprintf(udev->memory, "upd->ncomp = %5d\n",upd->ncomp);
+ errprintf(udev->memory, "upd->ocomp = %5d\n",upd->ocomp);
+ errprintf(udev->memory, "upd->nbytes = %5d\n",upd->nbytes);
+ errprintf(udev->memory, "upd->nlimits = %5d\n",upd->nlimits);
+ errprintf(udev->memory, "upd->scnmsk = %5d\n",upd->scnmsk);
+ errprintf(udev->memory, "upd->noutbuf = %5u\n",upd->noutbuf);
+ errprintf(udev->memory, "upd->ixpass = %5d\n",upd->ixpass);
+ errprintf(udev->memory, "upd->ipass = %5d\n",upd->ipass);
+ errprintf(udev->memory, "upd->icomp = %5d\n",upd->icomp);
+ errprintf(udev->memory, "upd->lf = %5d\n",upd->lf);
+ errprintf(udev->memory, "upd->xprinter = %5d\n",upd->xprinter);
+ errprintf(udev->memory, "upd->yscan = %5d\n",upd->yscan);
+ errprintf(udev->memory, "upd->yprinter = %5d\n",upd->yprinter);
+ errprintf(udev->memory, "upd->yscnbuf = %5d\n",upd->yscnbuf);
+
+ ln = 13;
+ lv = 5;
+ for(i = 0; countof(upd_choice) > i; ++i) {
+ if(!upd_choice[i]) continue;
+ l = strlen(upd_choice[i][0]);
+ if(ln < l) ln = l;
+ for(j = 1; upd_choice[i][j]; ++j) {
+ l = strlen(upd_choice[i][j]);
+ if(lv < l) lv = l;
+ }
+ }
+
+ for(i = 0; countof(upd_flags) > i; ++i) {
+ if(upd_flags[i]) {
+ l = strlen(upd_flags[i]);
+ if(ln < l) ln = l;
+ }
+ }
+
+ for(i = 0; countof(upd_ints) > i; ++i) {
+ if(upd_ints[i]) {
+ l = strlen(upd_ints[i]);
+ if(ln < l) ln = l;
+ }
+ }
+
+ for(i = 0; countof(upd_int_a) > i; ++i) {
+ if(upd_int_a[i]) {
+ l = strlen(upd_int_a[i]);
+ if(ln < l) ln = l;
+ }
+ }
+
+ for(i = 0; countof(upd_strings) > i; ++i) {
+ if(upd_strings[i]) {
+ l = strlen(upd_strings[i]);
+ if(ln < l) ln = l;
+ }
+ }
+
+ for(i = 0; countof(upd_string_a) > i; ++i) {
+ if(upd_string_a[i]) {
+ l = strlen(upd_string_a[i]);
+ if(ln < l) ln = l;
+ }
+ }
+
+ for(i = 0; countof(upd_float_a) > i; ++i) {
+ if(upd_float_a[i]) {
+ l = strlen(upd_float_a[i]);
+ if(ln < l) ln = l;
+ }
+ }
+
+ for(i = 0; countof(upd_choice) > i; ++i) {
+ if(upd_choice[i]) {
+ errprintf(udev->memory,"%*s = %-*s (%2d)\n",ln,upd_choice[i][0],
+ lv,upd_choice[i][upd->choice[i]],upd->choice[i]);
+ } else {
+ errprintf(udev->memory,"%*s[%2d] = %2d\n",ln-4,"upd_choice",i,
+ upd->choice[i]);
+ }
+ }
+
+ for(i = 0; countof(upd_flags) > i; ++i) {
+ if(upd_flags[i]) {
+ errprintf(udev->memory,"%*s = %s\n",ln,upd_flags[i],
+ ((uint32_t) 1 << i) & upd->flags ? "true" : "false");
+ } else {
+ errprintf(udev->memory,"%*s[%2d] = %s\n",ln-4,"upd_flags",i,
+ ((uint32_t) 1 << i) & upd->flags ? "true" : "false");
+
+ }
+ }
+
+ for(i = 0; countof(upd_ints) > i; ++i) {
+ if(upd_ints[i]) {
+ errprintf(udev->memory,"%*s = %5d\n",ln,upd_ints[i],upd->ints[i]);
+ } else {
+ errprintf(udev->memory,"%*s[%2d] = %5d\n",ln-4,"upd_ints",i,upd->ints[i]);
+ }
+ }
+
+ }
+
+ errprintf(udev->memory,"\n%sready to print\n\n",
+ B_OK4GO != (upd->flags & (B_OK4GO | B_ERROR)) ?
+ "NOT " : "");
+#endif
+
+ }
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+ errprintf(udev->memory,"RETURN: %d = upd_open(0x%05lx)\n",
+ error,(long) pdev);
+#endif
+
+ return error;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_close: Release everything allocated in upd_open */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_close(gx_device *pdev)
+{
+ upd_device *const udev = (upd_device *) pdev;
+ const upd_p upd = udev->upd;
+ int error = 0;
+ int code;
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+ errprintf(udev->memory,"CALL: upd_close(0x%05lx)\n",(long)pdev);
+#endif
+
+/** If necessary, write the close-sequence **/
+
+ if( upd && (( B_OPEN | B_OK4GO) ==
+ ((B_OPEN | B_OK4GO | B_ERROR) & upd->flags))) {
+
+ if(udev->file && upd->strings && 0 < upd->strings[S_CLOSE].size)
+ fwrite(upd->strings[S_CLOSE].data,1,
+ upd->strings[S_CLOSE].size,udev->file);
+
+ upd->flags &= ~B_OPEN;
+ }
+
+/** Then release the open-allocated memory */
+ if(upd) {
+
+ upd_close_writer(udev);
+
+ if(upd->gsbuf)
+ gs_free(pdev->memory, upd->gsbuf,upd->ngsbuf,1,"uniprint/gsbuf");
+ upd->gsbuf = NULL;
+ upd->ngsbuf = 0;
+ upd->flags &= ~B_BUF;
+
+ upd_close_render(udev);
+ upd_close_map(udev);
+
+ UPD_MM_DEL_ARRAY(pdev->memory, upd->choice, countof(upd_choice), UPD_MM_DEL_VALUE);
+ UPD_MM_DEL_ARRAY(pdev->memory, upd->ints, countof(upd_ints), UPD_MM_DEL_VALUE);
+ UPD_MM_DEL_ARRAY(pdev->memory, upd->int_a, countof(upd_int_a), UPD_MM_DEL_PARAM);
+ UPD_MM_DEL_ARRAY(pdev->memory, upd->strings, countof(upd_strings), UPD_MM_DEL_PARAM);
+ UPD_MM_DEL_ARRAY(pdev->memory, upd->string_a,countof(upd_string_a),UPD_MM_DEL_APARAM);
+ UPD_MM_DEL_ARRAY(pdev->memory, upd->float_a, countof(upd_float_a), UPD_MM_DEL_PARAM);
+
+ gs_free(pdev->memory, upd,sizeof(upd[0]),1,"uniprint");
+
+ udev->upd = NULL;
+ }
+
+/** Then call the superclass close **/
+ code = gdev_prn_close(pdev);
+ error = error > code ? code : error;
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+ errprintf(pdev->memory,"RETURN: %d = upd_close(0x%05lx)\n",
+ error,(long) pdev);
+#endif
+
+ return error;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_get_params: Export Parameters to the Interpreter */
+/* ------------------------------------------------------------------- */
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+#define UPD_EXIT_GET(Err,Dev,List) \
+ if(0 > Err) { \
+ errprintf(Dev->memory,"RETURN-%d: %d upd_get_params(0x%05lx,0x%05lx)\n", \
+ __LINE__,Err,(long) Dev,(long) List); \
+ return_error(Err); \
+ }
+#else
+#define UPD_EXIT_GET(Err,Dev,List) if(0 > Err) return_error(Err);
+#endif
+
+static int
+upd_get_params(gx_device *pdev, gs_param_list *plist)
+{
+ upd_device *const udev = (upd_device *) pdev;
+ const upd_p upd = udev->upd;
+ int error,i;
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+ errprintf(udev->memory,"CALL: upd_get_params(0x%05lx,0x%05lx)\n",
+ (long) udev,(long) plist);
+#endif
+
+/** Call the SuperClass-get_params at the beginning */
+ error = gdev_prn_get_params((gx_device *)udev,plist);
+ UPD_EXIT_GET(error,udev,plist);
+
+/** Export the version */
+ if(upd_version) { /* Version-Export enabled */
+ udev->upd_version.data = (const byte *) rcsid;
+ udev->upd_version.size = strlen(rcsid);
+ udev->upd_version.persistent = true;
+ error = param_write_string(plist,upd_version,&udev->upd_version);
+ UPD_EXIT_GET(error,udev,plist);
+ } /* Version-Export enabled */
+
+/** Export the Named choices */
+ for(i = 0; i < countof(upd_choice); ++i) {
+ if(!upd_choice[i]) continue; /* Choice-Export disabled */
+ if(upd && upd->choice && upd->choice[i]) {
+ gs_param_string name;
+ name.data = (const byte *) upd_choice[i][upd->choice[i]];
+ name.size = strlen((const char *) name.data);
+ name.persistent = true;
+ error = param_write_name(plist,upd_choice[i][0],&name);
+ } else {
+ error = param_write_null(plist,upd_choice[i][0]);
+ }
+ UPD_EXIT_GET(error,udev,plist);
+ }
+
+/** Export the flags (bool) */
+ for(i = 0; i < countof(upd_flags); ++i) {
+ if(!upd_flags[i]) continue; /* Flag-Export disabled */
+ if(upd) {
+ bool value = upd->flags & ((uint32_t) 1 << i);
+ error = param_write_bool(plist,upd_flags[i],&value);
+ } else {
+ error = param_write_null(plist,upd_flags[i]);
+ }
+ UPD_EXIT_GET(error,udev,plist);
+ }
+
+/** Export the ints */
+ for(i = 0; i < countof(upd_ints); ++i) {
+ if(!upd_ints[i]) continue; /* int-Export disabled */
+ if(upd && upd->ints && upd->ints[i]) {
+ int value = upd->ints[i];
+ error = param_write_int( plist,upd_ints[i],&value);
+ } else {
+ error = param_write_null(plist,upd_ints[i]);
+ }
+ UPD_EXIT_GET(error,udev,plist);
+ }
+
+/** Export the int-arrays */
+ for(i = 0; i < countof(upd_int_a); ++i) {
+ if(!upd_int_a[i]) continue; /* int-Array-Export disabled */
+ if(upd && upd->int_a && upd->int_a[i].size) {
+ error = param_write_int_array( plist,upd_int_a[i],(upd->int_a+i));
+ } else {
+ error = param_write_null(plist,upd_int_a[i]);
+ }
+ UPD_EXIT_GET(error,udev,plist);
+ }
+
+/** Export the strings */
+ for(i = 0; i < countof(upd_strings); ++i) {
+ if(!upd_strings[i]) continue; /* String-Export disabled */
+ if(upd && upd->strings && upd->strings[i].size) {
+ error = param_write_string( plist,upd_strings[i],(upd->strings+i));
+ } else {
+ error = param_write_null(plist,upd_strings[i]);
+ }
+ UPD_EXIT_GET(error,udev,plist);
+ }
+
+/** Export the string-Arrays */
+ for(i = 0; i < countof(upd_string_a); ++i) {
+ if(!upd_string_a[i]) continue; /* String-Array-Export disabled */
+ if(upd && upd->string_a && upd->string_a[i].size) {
+ error =
+ param_write_string_array( plist,upd_string_a[i],(upd->string_a+i));
+ } else {
+ error = param_write_null(plist,upd_string_a[i]);
+ }
+ UPD_EXIT_GET(error,udev,plist);
+ }
+
+/** Export the float-Arrays */
+ for(i = 0; i < countof(upd_float_a); ++i) {
+ if(!upd_float_a[i]) continue; /* Float-Array-Export disabled */
+ if(upd && upd->float_a && upd->float_a[i].size) {
+ error =
+ param_write_float_array( plist,upd_float_a[i],(upd->float_a+i));
+ } else {
+ error = param_write_null(plist,upd_float_a[i]);
+ }
+ UPD_EXIT_GET(error,udev,plist);
+ }
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+ errprintf(udev->memory,"RETURN: %d = upd_get_params(0x%05lx,0x%05lx)\n",
+ error,(long) udev,(long) plist);
+#endif
+
+ return error;
+}
+
+#undef UPD_EXIT_GET
+
+/* ------------------------------------------------------------------- */
+/* upd_put_params: Load Parameters into the device-structure */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_put_params(gx_device *pdev, gs_param_list *plist)
+{
+ upd_device *const udev = (upd_device *) pdev;
+ upd_p upd = udev->upd;
+ int error = 0, code,i;
+
+ float MarginsHWResolution[2],Margins[2];
+ gx_device_color_info color_info;
+ uint32_t flags = 0;
+ int *choice = NULL;
+ int *ints = NULL;
+ gs_param_int_array *int_a = NULL;
+ gs_param_string *strings = NULL;
+ gs_param_string_array *string_a = NULL;
+ gs_param_float_array *float_a = NULL, mfa;
+
+/**
+Error is used for two purposes: either it holds a negative error
+code or it is used as a bitfield, that tells, which parameters
+were actually loaded. If any of the important parameters changed
+upd_put_params closes the device, since the real parameter-evaluation
+is carried out by upd_open.
+*/
+
+#define UPD_PUT_FLAGS 0x0002
+#define UPD_PUT_CHOICE 0x0004
+#define UPD_PUT_INTS 0x0008
+#define UPD_PUT_INT_A 0x0010
+#define UPD_PUT_STRINGS 0x0020
+#define UPD_PUT_STRING_A 0x0040
+#define UPD_PUT_FLOAT_A 0x0080
+#define UPD_PUT_CHANGEDSIZE 0x0100
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+ errprintf(udev->memory,"CALL: upd_put_params(0x%05lx,0x%05lx)\n",
+ (long)udev,(long)plist);
+#endif
+
+/**
+I consider the following part of upd_put_params a bad-nasty-hack-hack
+and i am uncertain, wether it really works in the intended way. I provide it
+just for the case someone is performing nasty-parameter-changes on the
+active device, especially switching the OutputFile. If this happens in
+a situation, where data were written to the file, but the termination
+sequence is required, the driver does it now. (If you want to know, why
+i am writing bad-nasty-hack-hack, visit http://www.zark.com )
+*/
+ if(upd && (B_OPEN & udev->upd->flags) && (NULL != udev->file)) {
+
+ gs_param_string fname = { NULL, 0, false };
+
+ code = param_read_string(plist,"OutputFile",&fname);
+ if((1 != code) && (0 != code)) {
+ code = param_read_null(plist,"OutputFile");
+ if(0 == code) {
+ fname.data = (const byte *) "";
+ fname.size = 0;
+ }
+ }
+
+ if((0 == code) &&
+ strncmp((const char *)fname.data,udev->fname,fname.size)) {
+ if(upd->strings && 0 < udev->upd->strings[S_CLOSE].size)
+ fwrite(upd->strings[S_CLOSE].data,1,
+ upd->strings[S_CLOSE].size,udev->file);
+
+ upd->flags &= ~B_OPEN;
+ }
+ }
+/* Done with the bad-nasty-hack-hack */
+
+/**
+The next thing "upd_put_params" does, is a little strange too. It imports
+a readonly-parameter, the version-string. I do not know wether it is still
+required, but some versions of GHOSTSCRIPT disliked it very much, if an
+existing parameter was not touched by the put-operation.
+
+On the other hand it is the right time to show the basic-outline of the
+parameter-importing flow. Basically the proper "param_read"-procedure
+is called. If it indicated, that the parameter was present, but of the
+wrong type, a read for the null-type is attempted, which is by convention
+somehow an reset to default. This sequence is applied to all the parameters
+and in case of the array-parameters, a succesful null-read is marked by
+setting data and size to 0.
+*/
+#if UPD_MESSAGES & UPD_M_SETUP
+#define UPD_PARAM_READ(Param_read,Name,Object,Mem) \
+ code = Param_read(plist,Name,&Object); \
+ if(0 > code) { \
+ code = param_read_null(plist,Name); \
+ if(0 == code) memset(&Object,0,sizeof(Object));\
+ } \
+ if(!code) errprintf(Mem, \
+ "upd_put_params: retrieved parameter \"%s\"\n",\
+ Name); \
+ if(0 > code) { \
+ param_signal_error(plist,Name,code); \
+ if(error > code) error = code; \
+ }
+#else
+#define UPD_PARAM_READ(Param_read,Name,Object,Mem) \
+ code = Param_read(plist,Name,&Object); \
+ if(0 > code) { \
+ code = param_read_null(plist,Name); \
+ if(0 == code) memset(&Object,0,sizeof(Object));\
+ } \
+ if(0 > code) { \
+ param_signal_error(plist,Name,code); \
+ if(error > code) error = code; \
+ }
+#endif
+
+ UPD_PARAM_READ(param_read_string,upd_version,udev->upd_version,udev->memory)
+
+/**
+upd_put_params begins it's normal work by creating a copy, of
+the data, that it might change, except for color_info that might
+be changed in the device-structure, all manipulations are carried
+out on this copies.
+*/
+ MarginsHWResolution[0] = udev->MarginsHWResolution[0];
+ MarginsHWResolution[1] = udev->MarginsHWResolution[1];
+ Margins[0] = udev->Margins[0];
+ Margins[1] = udev->Margins[1];
+
+ color_info = udev->color_info;
+ if(upd) {
+ flags = upd->flags;
+ UPD_MM_CPY_ARRAY(udev->memory, choice, upd->choice, countof(upd_choice),
+ UPD_MM_CPY_VALUE);
+ UPD_MM_CPY_ARRAY(udev->memory, ints, upd->ints, countof(upd_ints),
+ UPD_MM_CPY_VALUE);
+ UPD_MM_CPY_ARRAY(udev->memory, int_a, upd->int_a, countof(upd_int_a),
+ UPD_MM_CPY_PARAM);
+ UPD_MM_CPY_ARRAY(udev->memory, strings, upd->strings, countof(upd_strings),
+ UPD_MM_CPY_PARAM);
+ UPD_MM_CPY_ARRAY(udev->memory, string_a,upd->string_a,countof(upd_string_a),
+ UPD_MM_CPY_APARAM);
+ UPD_MM_CPY_ARRAY(udev->memory, float_a, upd->float_a, countof(upd_float_a),
+ UPD_MM_CPY_PARAM);
+ } else {
+ flags = 0;
+ UPD_MM_GET_ARRAY(udev->memory, choice, countof(upd_choice));
+ UPD_MM_GET_ARRAY(udev->memory, ints, countof(upd_ints));
+ UPD_MM_GET_ARRAY(udev->memory, int_a, countof(upd_int_a));
+ UPD_MM_GET_ARRAY(udev->memory, strings, countof(upd_strings));
+ UPD_MM_GET_ARRAY(udev->memory, string_a,countof(upd_string_a));
+ UPD_MM_GET_ARRAY(udev->memory, float_a, countof(upd_float_a));
+ }
+
+/** Import the Multiple-Choices */
+ for(i = 0; countof(upd_choice) > i; ++i) {
+ gs_param_string value = { NULL, 0, false};
+ if(!upd_choice[i][0]) continue;
+ UPD_PARAM_READ(param_read_name,upd_choice[i][0],value,udev->memory);
+ if(0 == code) {
+ if(0 <= error) error |= UPD_PUT_CHOICE;
+ choice[i] = 0;
+ if(0 < value.size) {
+ int j;
+ for(j = 1; upd_choice[i][j]; ++j) {
+ if((strlen(upd_choice[i][j]) == value.size) &&
+ (0 == strncmp(upd_choice[i][j],
+ (const char *) value.data,value.size))) {
+ choice[i] = j;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+/** Import the Boolean Values */
+ for(i = 0; countof(upd_flags) > i; ++i) {
+ uint32_t bit = (uint32_t) 1 << i;
+ bool flag = flags & bit ? true : false;
+ if(!upd_flags[i]) continue;
+ UPD_PARAM_READ(param_read_bool,upd_flags[i],flag,udev->memory);
+ if(0 == code) {
+ if(0 <= error) error |= UPD_PUT_FLAGS;
+ if(flag) flags |= bit;
+ else flags &= ~bit;
+ }
+ }
+
+/** Import the Integer Values */
+ for(i = 0; countof(upd_ints) > i; ++i) {
+ int value = ints[i];
+ if(!upd_ints[i]) continue;
+ UPD_PARAM_READ(param_read_int,upd_ints[i],value,udev->memory);
+ if(0 == code) {
+ if(0 <= error) error |= UPD_PUT_INTS;
+ ints[i] = value;
+ }
+ }
+
+/** Import the Integer Arrays */
+ for(i = 0; countof(upd_int_a) > i; ++i) {
+ gs_param_int_array value = int_a[i];
+ if(!upd_int_a[i]) continue;
+ UPD_PARAM_READ(param_read_int_array,upd_int_a[i],value,udev->memory);
+ if(0 == code) {
+ if(0 <= error) error |= UPD_PUT_INT_A;
+ UPD_MM_DEL_PARAM(udev->memory, int_a[i]);
+ if(!value.size) {
+ value.data = NULL;
+ int_a[i] = value;
+ } else {
+ UPD_MM_CPY_PARAM(udev->memory, int_a[i],value);
+ }
+ }
+ }
+
+/** Import the Strings */
+ for(i = 0; countof(upd_strings) > i; ++i) {
+ gs_param_string value = strings[i];
+ if(!upd_strings[i]) continue;
+ UPD_PARAM_READ(param_read_string,upd_strings[i],value,udev->memory);
+ if(0 == code) {
+ if(0 <= error) error |= UPD_PUT_STRINGS;
+ UPD_MM_DEL_PARAM(udev->memory, strings[i]);
+ if(!value.size) {
+ value.data = NULL;
+ strings[i] = value;
+ } else {
+ UPD_MM_CPY_PARAM(udev->memory, strings[i],value);
+ }
+ }
+ }
+
+/** Import the String Arrays */
+ for(i = 0; countof(upd_string_a) > i; ++i) {
+ gs_param_string_array value = string_a[i];
+ if(!upd_string_a[i]) continue;
+ UPD_PARAM_READ(param_read_string_array,upd_string_a[i],value,udev->memory);
+ if(0 == code) {
+ if(0 <= error) error |= UPD_PUT_STRING_A;
+ UPD_MM_DEL_APARAM(udev->memory, string_a[i]);
+ if(!value.size) {
+ value.data = NULL;
+ string_a[i] = value;
+ } else {
+ UPD_MM_CPY_APARAM(udev->memory, string_a[i],value);
+ }
+ }
+ }
+
+/** Import the Float Arrays */
+ for(i = 0; countof(upd_float_a) > i; ++i) {
+ gs_param_float_array value = float_a[i];
+ if(!upd_float_a[i]) continue;
+ UPD_PARAM_READ(param_read_float_array,upd_float_a[i],value,udev->memory);
+ if(0 == code) {
+ if(0 <= error) error |= UPD_PUT_FLOAT_A;
+ UPD_MM_DEL_PARAM(udev->memory, float_a[i]);
+ if(!value.size) {
+ value.data = NULL;
+ float_a[i] = value;
+ } else {
+ UPD_MM_CPY_PARAM(udev->memory, float_a[i],value);
+ }
+ }
+ }
+
+/**
+Prior to the call to the superclass-put_params, the memory-layout and
+the color-model needs adjustment. This is performed here, if any parameters
+were set.
+In addition to that, Resolution & Margin-Parameters are tested & adjusted.
+*/
+ if(0 < error) {
+
+ int *ip,*ip2,ncomp,nbits;
+
+ if(6 > int_a[IA_COLOR_INFO].size) {
+ UPD_MM_DEL_PARAM(udev->memory, int_a[IA_COLOR_INFO]);
+ UPD_MM_GET_ARRAY(udev->memory, int_a[IA_COLOR_INFO].data,6);
+ int_a[IA_COLOR_INFO].size = 6;
+ }
+ ip = (int *) upd_cast(int_a[IA_COLOR_INFO].data);
+
+ if(0 == ip[0]) { /* Try to obtain num_components */
+ switch(choice[C_MAPPER]) {
+ case MAP_GRAY: ip[0] = 1; break;
+ case MAP_RGBW: ip[0] = 3; break;
+ case MAP_RGB: ip[0] = 3; break;
+ case MAP_CMYK: ip[0] = 4; break;
+ case MAP_CMYKGEN: ip[0] = 4; break;
+ case MAP_RGBOV: ip[0] = 3; break;
+ case MAP_RGBNOV: ip[0] = 3; break;
+ default: ip[0] = color_info.num_components; break;
+ }
+ } /* Try to obtain num_components */
+
+ switch(choice[C_MAPPER]) {
+ case MAP_GRAY: ncomp = 1; break;
+ case MAP_RGBW: ncomp = 4; break;
+ case MAP_RGB: ncomp = 3; break;
+ case MAP_CMYK: ncomp = 4; break;
+ case MAP_CMYKGEN: ncomp = 4; break;
+ case MAP_RGBOV: ncomp = 4; break;
+ case MAP_RGBNOV: ncomp = 4; break;
+ default: ncomp = ip[0]; break;
+ }
+ if(UPD_CMAP_MAX < ncomp) ncomp = UPD_CMAP_MAX;
+
+ if(ncomp > int_a[IA_COMPBITS].size) { /* Default ComponentBits */
+ UPD_MM_GET_ARRAY(udev->memory, ip2,ncomp);
+ nbits = 32 / ncomp;
+ if(8 < nbits) nbits = 8;
+ for(i = 0; i < ncomp; ++i) ip2[i] = nbits;
+ UPD_MM_DEL_PARAM(udev->memory, int_a[IA_COMPBITS]);
+ int_a[IA_COMPBITS].data = ip2;
+ int_a[IA_COMPBITS].size = ncomp;
+ } /* Default ComponentBits */
+
+ if(ncomp > int_a[IA_COMPSHIFT].size) { /* Default ComponentShift */
+ nbits = 0;
+ for(i = 0; i < ncomp; ++i) nbits += int_a[IA_COMPBITS].data[i];
+ UPD_MM_GET_ARRAY(udev->memory, ip2,ncomp);
+ for(i = 0; i < ncomp; ++i) {
+ ip2[i] = nbits - int_a[IA_COMPBITS].data[i];
+ nbits -= int_a[IA_COMPBITS].data[i];
+ }
+ UPD_MM_DEL_PARAM(udev->memory, int_a[IA_COMPSHIFT]);
+ int_a[IA_COMPSHIFT].data = ip2;
+ int_a[IA_COMPSHIFT].size = ncomp;
+ } /* Default ComponentShift */
+
+ if(0 == ip[1]) { /* Try to compute the depth */
+ nbits = 0;
+ for(i = 0; i < ncomp; ++i) {
+ if(nbits < (int_a[IA_COMPBITS].data[i] +
+ int_a[IA_COMPSHIFT].data[i]))
+ nbits = int_a[IA_COMPBITS].data[i] +
+ int_a[IA_COMPSHIFT].data[i];
+ }
+ if( 1 >= nbits) nbits = 1;
+ else if( 2 >= nbits) nbits = 2;
+ else if( 4 >= nbits) nbits = 4;
+ else if( 8 >= nbits) nbits = 8;
+ else if(16 >= nbits) nbits = 16;
+ else if(24 >= nbits) nbits = 24;
+ else nbits = 32;
+
+ ip[1] = nbits;
+
+ } /* Try to compute the depth */
+
+ if(0 == ip[2]) { /* Number of Gray-Levels */
+ nbits = 0;
+ for(i = 0; i < ncomp; ++i) if(nbits < int_a[IA_COMPBITS].data[i])
+ nbits = int_a[IA_COMPBITS].data[i];
+ if(nbits > 8) nbits = 8;
+ ip[2] = (1 << nbits) - 1;
+ } /* Number of Gray-Levels */
+
+ if(0 == ip[3] && 1 < ip[0]) { /* Number of Colors */
+ nbits = 0;
+ for(i = 0; i < ip[0]; ++i) nbits += int_a[IA_COMPBITS].data[i];
+ if(nbits > 8) nbits = 8;
+ ip[3] = (1 << nbits) - 1;
+ } /* Number of Colors */
+
+ if(0 == ip[4]) { /* Gray-Ramp */
+ nbits = 0;
+ for(i = 0; i < ncomp; ++i) if(nbits < int_a[IA_COMPBITS].data[i])
+ nbits = int_a[IA_COMPBITS].data[i];
+ if(2 < nbits) ip[4] = 256;
+ else ip[4] = 2;
+ } /* Gray-Ramp */
+
+ if(0 == ip[5] && 1 < ip[0]) { /* Color-Ramp */
+ nbits = 0;
+ for(i = 0; i < ncomp; ++i) if(nbits < int_a[IA_COMPBITS].data[i])
+ nbits = int_a[IA_COMPBITS].data[i];
+ if(2 < nbits) ip[5] = 256;
+ else ip[5] = 2;
+ } /* Color-Ramp */
+
+ udev->color_info.num_components = ip[0];
+ udev->color_info.depth = ip[1];
+ udev->color_info.max_gray = (gx_color_value) ip[2];
+ udev->color_info.max_color = (gx_color_value) ip[3];
+ udev->color_info.dither_grays = (gx_color_value) ip[4];
+ udev->color_info.dither_colors = (gx_color_value) ip[5];
+
+/*
+ * Now we're dealing with the Resolution- & Margin-Stuff
+ * (This is close to be a bad-nasty-hack-hack)
+ */
+ if((0 == param_read_float_array(plist,"HWResolution",&mfa)) &&
+ (2 == mfa.size) && (0 != mfa.data)) {
+ udev->MarginsHWResolution[0] = mfa.data[0];
+ udev->MarginsHWResolution[1] = mfa.data[1];
+ } else {
+ udev->MarginsHWResolution[0] = udev->HWResolution[0];
+ udev->MarginsHWResolution[1] = udev->HWResolution[1];
+ }
+
+ if((0 == param_read_float_array(plist,".HWMargins",&mfa)) &&
+ (4 == mfa.size) && (0 != mfa.data)) {
+ udev->Margins[0] = -mfa.data[0] * udev->MarginsHWResolution[0] / 72.0;
+ udev->Margins[1] = -mfa.data[3] * udev->MarginsHWResolution[1] / 72.0;
+ }
+ } /* Change the color-Info */
+
+/* Call the superclass-put_params now */
+ code = gdev_prn_put_params((gx_device *)udev,plist);
+ if(0 > code) error = code;
+
+/**
+If the superclass-"put_params" went o.k. too, then the new parameters are
+transferred into the device-structure. In the case of "uniprint", this may
+
+ 1. Close the device, which might fail.
+ 2. Allocate new memory for the upd-specific structure, that might fail too.
+
+*/
+/* *HGS* recognize a changed device geometry */
+ if( udev->upd && /* HGS */
+ ((udev->width != udev->upd->pdwidth) || /* HGS */
+ (udev->height != udev->upd->pdheight) )) /* HGS */
+ error |= UPD_PUT_CHANGEDSIZE; /* HGS */
+
+ if(0 < error && udev->is_open) {
+ code = gs_closedevice((gx_device *)udev);
+ if(0 > code) error = code;
+ }
+
+ if(0 < error) { /* Actually something loaded without error */
+
+ if(!(upd = udev->upd)) {
+ UPD_MM_GET_ARRAY(udev->memory, udev->upd,1);
+ upd = udev->upd;
+ } else {
+ UPD_MM_DEL_ARRAY(udev->memory, upd->choice, countof(upd_choice), UPD_MM_DEL_VALUE);
+ UPD_MM_DEL_ARRAY(udev->memory, upd->ints, countof(upd_ints), UPD_MM_DEL_VALUE);
+ UPD_MM_DEL_ARRAY(udev->memory, upd->int_a, countof(upd_int_a), UPD_MM_DEL_PARAM);
+ UPD_MM_DEL_ARRAY(udev->memory, upd->strings, countof(upd_strings), UPD_MM_DEL_PARAM);
+ UPD_MM_DEL_ARRAY(udev->memory, upd->string_a,countof(upd_string_a),UPD_MM_DEL_APARAM);
+ UPD_MM_DEL_ARRAY(udev->memory, upd->float_a, countof(upd_float_a), UPD_MM_DEL_PARAM);
+ }
+
+ upd->choice = choice;
+ upd->flags = flags;
+ upd->ints = ints;
+ upd->int_a = int_a;
+ upd->strings = strings;
+ upd->string_a = string_a;
+ upd->float_a = float_a;
+ upd->memory = udev->memory;
+
+ if(0 < error) error = 0;
+
+ } else {
+
+ udev->Margins[0] = Margins[0];
+ udev->Margins[1] = Margins[1];
+ udev->MarginsHWResolution[0] = MarginsHWResolution[0];
+ udev->MarginsHWResolution[1] = MarginsHWResolution[1];
+
+ udev->color_info = color_info;
+ UPD_MM_DEL_ARRAY(udev->memory, choice, countof(upd_choice), UPD_MM_DEL_VALUE);
+ UPD_MM_DEL_ARRAY(udev->memory, ints, countof(upd_ints), UPD_MM_DEL_VALUE);
+ UPD_MM_DEL_ARRAY(udev->memory, int_a, countof(upd_int_a), UPD_MM_DEL_PARAM);
+ UPD_MM_DEL_ARRAY(udev->memory, strings, countof(upd_strings), UPD_MM_DEL_PARAM);
+ UPD_MM_DEL_ARRAY(udev->memory, string_a,countof(upd_string_a),UPD_MM_DEL_APARAM);
+ UPD_MM_DEL_ARRAY(udev->memory, float_a, countof(upd_float_a), UPD_MM_DEL_PARAM);
+
+ }
+
+/*
+ * upd_put_params keeps the Procedures upd to date
+ */
+
+ upd_procs_map(udev);
+
+#if UPD_MESSAGES & UPD_M_TOPCALLS
+ errprintf(udev->memory,"RETURN: %d = upd_put_params(0x%05lx,0x%05lx)\n",
+ error,(long) udev, (long) plist);
+#endif
+
+ return error;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_cmyk_icolor: KCMY->KCMY-Index Mapping */
+/* ------------------------------------------------------------------- */
+/**
+The next Routines, that follow, are the color-mapping routines.
+GHOSTSCRIPT talks about "gx_color_values" and the driver has
+to merge the 1, 3 or four values into up to 32 Bits, that means
+it is necessary to do some truncation and shifting. For the truncation
+"uniprint" uses the internal function "upd_truncate" and "upd_expand"
+reverses this in the reverse-mapping procedures.
+*/
+
+static gx_color_index
+upd_cmyk_icolor(gx_device *pdev, const gx_color_value cv[])
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+ gx_color_index rv;
+ gx_color_value c, m, y, k;
+ c = cv[0]; m = cv[1]; y = cv[2]; k = cv[3];
+
+/**
+All 4-Component-Modi have to deal with the Problem, that a value
+with all bits set can be produced, which is treated as an error-return
+from the mapping-functions. But with RGBW or KCMY, there is a neat
+trick: Grayscale are transferred as RGB/CMY=0 and holding Data only
+in the W- or K-Component.
+*/
+
+ if((c == m) && (m == y)) {
+
+ rv = upd_truncate(upd,0,(gx_color_value)(c > k ? c : k));
+
+ } else {
+
+ rv = upd_truncate(upd,0,k) | upd_truncate(upd,1,c)
+ | upd_truncate(upd,2,m) | upd_truncate(upd,3,y);
+
+/* It might still become a "gx_no_color_value" due to truncation, thus: */
+
+ if(rv == gx_no_color_index) rv ^= 1;
+ }
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ errprintf(pdev->memory,
+"cmyk_icolor: (%5.1f,%5.1f,%5.1f,%5.1f) : (%5.1f,%5.1f,%5.1f,%5.1f) : 0x%0*lx\n",
+ 255.0 * (double) c / (double) gx_max_color_value,
+ 255.0 * (double) m / (double) gx_max_color_value,
+ 255.0 * (double) y / (double) gx_max_color_value,
+ 255.0 * (double) k / (double) gx_max_color_value,
+ 255.0 * (double) ((rv >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
+ / (double) upd->cmap[1].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
+ / (double) upd->cmap[2].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
+ / (double) upd->cmap[3].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ (pdev->color_info.depth + 3)>>2,rv);
+#endif
+
+ return rv;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_icolor_rgb: Stored KCMY back to a RGB */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_icolor_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+ gx_color_value c,m,y,k;
+
+/*
+ * Expand to the Component-Values
+ */
+ k = upd_expand(upd,0,color);
+ c = upd_expand(upd,1,color);
+ m = upd_expand(upd,2,color);
+ y = upd_expand(upd,3,color);
+
+/*
+ * Then Invert and subtract K from the colors
+ */
+ prgb[0] = gx_max_color_value - c;
+ if(prgb[0] > k) prgb[0] -= k;
+ else prgb[0] = 0;
+
+ prgb[1] = gx_max_color_value - m;
+ if(prgb[1] > k) prgb[1] -= k;
+ else prgb[1] = 0;
+
+ prgb[2] = gx_max_color_value - y;
+ if(prgb[2] > k) prgb[2] -= k;
+ else prgb[2] = 0;
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ errprintf(pdev->memory,
+ "icolor_rgb: 0x%0*lx -> (%5.1f,%5.1f,%5.1f,%5.1f) -> (%5.1f,%5.1f,%5.1f,%5.1f) -> (%5.1f,%5.1f,%5.1f)\n",
+ (pdev->color_info.depth + 3)>>2,color,
+ 255.0 * (double) ((color >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
+ / (double) upd->cmap[1].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
+ / (double) upd->cmap[2].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
+ / (double) upd->cmap[3].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ 255.0 * (double) c / (double) gx_max_color_value,
+ 255.0 * (double) m / (double) gx_max_color_value,
+ 255.0 * (double) y / (double) gx_max_color_value,
+ 255.0 * (double) k / (double) gx_max_color_value,
+ 255.0 * (double) prgb[0] / (double) gx_max_color_value,
+ 255.0 * (double) prgb[1] / (double) gx_max_color_value,
+ 255.0 * (double) prgb[2] / (double) gx_max_color_value);
+#endif
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_rgb_1color: Grayscale->Grayscale-index-Mapping */
+/* ------------------------------------------------------------------- */
+
+static gx_color_index
+upd_rgb_1color(gx_device *pdev, const gx_color_value cv[])
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+ gx_color_index rv;
+ gx_color_value g;
+
+ g = cv[0];
+ rv = upd_truncate(upd,0,g);
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ errprintf(pdev->memory,
+ "rgb_1color: (%5.1f) : (%5.1f) : 0x%0*lx\n",
+ 255.0 * (double) g / (double) gx_max_color_value,
+ 255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ (pdev->color_info.depth + 3)>>2,rv);
+#endif
+
+ return rv;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_1color_rgb: reversal of the above */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_1color_rgb(gx_device *pdev, gx_color_index color, gx_color_value cv[1])
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+/*
+ * Actual task: expand to full range of gx_color_value
+ */
+ cv[0] = upd_expand(upd,0,color);
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ errprintf(pdev->memory,"1color_rgb: 0x%0*lx -> %5.1f -> (%5.1f,%5.1f,%5.1f)\n",
+ (pdev->color_info.depth + 3)>>2,color,
+ 255.0 * (double) ((color >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ 255.0 * (double) prgb[0] / (double) gx_max_color_value,
+ 255.0 * (double) prgb[0] / (double) gx_max_color_value,
+ 255.0 * (double) prgb[0] / (double) gx_max_color_value);
+#endif
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_rgb_3color: component-wise RGB->RGB-Mapping */
+/* ------------------------------------------------------------------- */
+
+static gx_color_index
+upd_rgb_3color(gx_device *pdev, const gx_color_value cv[])
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+ gx_color_index rv;
+ gx_color_value r, g, b;
+ r = cv[0]; g = cv[1]; b = cv[2];
+
+ rv = upd_truncate(upd,0,r) | upd_truncate(upd,1,g) | upd_truncate(upd,2,b);
+ if(rv == gx_no_color_index) rv ^= 1;
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ errprintf(pdev->memory,
+ "rgb_3color: (%5.1f,%5.1f,%5.1f) : (%5.1f,%5.1f,%5.1f) : 0x%0*lx\n",
+ 255.0 * (double) r / (double) gx_max_color_value,
+ 255.0 * (double) g / (double) gx_max_color_value,
+ 255.0 * (double) b / (double) gx_max_color_value,
+ 255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
+ / (double) upd->cmap[1].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
+ / (double) upd->cmap[2].bitmsk,
+ (pdev->color_info.depth + 3)>>2,rv);
+#endif
+
+ return rv;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_3color_rgb: reversal of the above */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_3color_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+
+ prgb[0] = upd_expand(upd,0,color);
+ prgb[1] = upd_expand(upd,1,color);
+ prgb[2] = upd_expand(upd,2,color);
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ errprintf(pdev->memory,
+ "3color_rgb: 0x%0*lx -> (%5.1f,%5.1f,%5.1f) -> (%5.1f,%5.1f,%5.1f)\n",
+ (pdev->color_info.depth + 3)>>2,color,
+ 255.0 * (double) ((color >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
+ / (double) upd->cmap[1].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
+ / (double) upd->cmap[2].bitmsk,
+
+ 255.0 * (double) prgb[0] / (double) gx_max_color_value,
+ 255.0 * (double) prgb[1] / (double) gx_max_color_value,
+ 255.0 * (double) prgb[2] / (double) gx_max_color_value);
+#endif
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_rgb_4color: Create an WRGB-Index from RGB */
+/* ------------------------------------------------------------------- */
+
+static gx_color_index
+upd_rgb_4color(gx_device *pdev, const gx_color_value cv[])
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+ gx_color_index rv;
+ gx_color_value r, g, b;
+
+ r = cv[0]; g = cv[1]; b = cv[2];
+
+ if((r == g) && (g == b)) {
+
+ rv = upd_truncate(upd,0,r);
+
+ } else {
+
+ gx_color_value w = g < r ? g : r; w = w < b ? w : b; /* Minimum */
+
+ rv = upd_truncate(upd,0,w) | upd_truncate(upd,1,r) |
+ upd_truncate(upd,2,g) | upd_truncate(upd,3,b);
+
+/* It might still become a "gx_no_color_value" due to truncation, thus: */
+
+ if(rv == gx_no_color_index) rv ^= 1;
+ }
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ errprintf(pdev->memory,
+ "rgb_4color: (%5.1f,%5.1f,%5.1f) : (%5.1f,%5.1f,%5.1f,%5.1f) : 0x%0*lx\n",
+ 255.0 * (double) r / (double) gx_max_color_value,
+ 255.0 * (double) g / (double) gx_max_color_value,
+ 255.0 * (double) b / (double) gx_max_color_value,
+ 255.0 * (double) ((rv >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
+ / (double) upd->cmap[1].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
+ / (double) upd->cmap[2].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
+ / (double) upd->cmap[3].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ (pdev->color_info.depth + 3)>>2,rv);
+#endif
+
+ return rv;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_4color_rgb: Stored WRGB-Index back to a RGB */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_4color_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+
+/*
+ * Expand to the Component-Values
+ */
+ prgb[0] = upd_expand(upd,1,color);
+ prgb[1] = upd_expand(upd,2,color);
+ prgb[2] = upd_expand(upd,3,color);
+
+/* Revert our Grayscale-Trick: */
+ if(!(prgb[0] || prgb[1] || prgb[2]))
+ prgb[0] = prgb[1] = prgb[2] = upd_expand(upd,0,color);
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ errprintf(pdev->memory,
+ "4color_rgb: 0x%0*lx -> (%5.1f,%5.1f,%5.1f,%5.1f) -> (%5.1f,%5.1f,%5.1f)\n",
+ (pdev->color_info.depth + 3)>>2,color,
+ 255.0 * (double) ((color >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
+ / (double) upd->cmap[1].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
+ / (double) upd->cmap[2].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
+ / (double) upd->cmap[3].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ 255.0 * (double) prgb[0] / (double) gx_max_color_value,
+ 255.0 * (double) prgb[1] / (double) gx_max_color_value,
+ 255.0 * (double) prgb[2] / (double) gx_max_color_value);
+#endif
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_cmyk_kcolor: KCMY->KCMY-Index Mapping with Black Generation */
+/* ------------------------------------------------------------------- */
+
+static gx_color_index
+upd_cmyk_kcolor(gx_device *pdev, const gx_color_value cv[])
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+ gx_color_index rv;
+ gx_color_value black;
+
+ gx_color_value c, m, y, k;
+ c = cv[0]; m = cv[1]; y = cv[2]; k = cv[3];
+
+ if((c == m) && (m == y)) {
+
+ black = c > k ? c : k;
+ rv = upd_truncate(upd,0,black);
+
+ } else {
+
+ if(k && !(c | m | y)) {
+ black = k;
+ } else {
+ black = c < m ? c : m;
+ black = black < y ? black : y;
+ }
+
+ rv = upd_truncate(upd,0,black) | upd_truncate(upd,1,c)
+ | upd_truncate(upd,2,m) | upd_truncate(upd,3,y);
+
+/* It might still become a "gx_no_color_value" due to truncation, thus: */
+
+ if(rv == gx_no_color_index) rv ^= 1;
+ }
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ errprintf(pdev->memory,
+"cmyk_kcolor: (%5.1f,%5.1f,%5.1f,%5.1f) : (%5.1f,%5.1f,%5.1f,%5.1f) : 0x%0*lx\n",
+ 255.0 * (double) c / (double) gx_max_color_value,
+ 255.0 * (double) m / (double) gx_max_color_value,
+ 255.0 * (double) y / (double) gx_max_color_value,
+ 255.0 * (double) k / (double) gx_max_color_value,
+ 255.0 * (double) ((rv >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
+ / (double) upd->cmap[1].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
+ / (double) upd->cmap[2].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
+ / (double) upd->cmap[3].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ (pdev->color_info.depth + 3)>>2,rv);
+#endif
+
+ return rv;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_kcolor_rgb: Stored CMY+generated K back to a RGB */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_kcolor_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+ gx_color_value c,m,y,k;
+
+/*
+ * Expand to the Component-Values
+ */
+ k = upd_expand(upd,0,color);
+ c = upd_expand(upd,1,color);
+ m = upd_expand(upd,2,color);
+ y = upd_expand(upd,3,color);
+
+/*
+ * Check for plain Gray-Values
+ */
+ if(!(c | m | y )) {
+
+ prgb[2] = prgb[1] = prgb[0] = gx_max_color_value - k;
+
+ } else {
+ prgb[0] = gx_max_color_value - c;
+ prgb[1] = gx_max_color_value - m;
+ prgb[2] = gx_max_color_value - y;
+ }
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ errprintf(pdev->memory,
+ "kcolor_rgb: 0x%0*lx -> (%5.1f,%5.1f,%5.1f,%5.1f) -> (%5.1f,%5.1f,%5.1f,%5.1f) -> (%5.1f,%5.1f,%5.1f)\n",
+ (pdev->color_info.depth + 3)>>2,color,
+ 255.0 * (double) ((color >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
+ / (double) upd->cmap[1].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
+ / (double) upd->cmap[2].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
+ / (double) upd->cmap[3].bitmsk,
+ 255.0 * (double) ((color >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ 255.0 * (double) c / (double) gx_max_color_value,
+ 255.0 * (double) m / (double) gx_max_color_value,
+ 255.0 * (double) y / (double) gx_max_color_value,
+ 255.0 * (double) k / (double) gx_max_color_value,
+ 255.0 * (double) prgb[0] / (double) gx_max_color_value,
+ 255.0 * (double) prgb[1] / (double) gx_max_color_value,
+ 255.0 * (double) prgb[2] / (double) gx_max_color_value);
+#endif
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_rgb_ovcolor: Create an KCMY-Index from RGB */
+/* ------------------------------------------------------------------- */
+
+static gx_color_index
+upd_rgb_ovcolor(gx_device *pdev, const gx_color_value cv[])
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+ gx_color_index rv;
+ gx_color_value c,m,y,black;
+ gx_color_value r, g, b;
+ r = cv[0]; g = cv[1]; b = cv[2];
+ if((r == g) && (g == b)) {
+
+ black = gx_max_color_value - r;
+ rv = upd_truncate(upd,0,black);
+ c = m = y = 0;
+
+ } else {
+
+ c = gx_max_color_value - r;
+ m = gx_max_color_value - g;
+ y = gx_max_color_value - b;
+
+ black = c < m ? c : m;
+ black = black < y ? black : y;
+
+ if(black != gx_max_color_value) {
+ float tmp,d;
+
+ d = (float)(gx_max_color_value - black);
+
+ tmp = (float) (c-black) / d;
+ if( 0.0 > tmp) tmp = 0.0;
+ else if( 1.0 < tmp) tmp = 1.0;
+ c = (gx_color_value)(tmp * gx_max_color_value + 0.499);
+
+ tmp = (float) (m-black) / d;
+ if( 0.0 > tmp) tmp = 0.0;
+ else if( 1.0 < tmp) tmp = 1.0;
+ m = (gx_color_value)(tmp * gx_max_color_value + 0.499);
+
+ tmp = (float) (y-black) / d;
+ if( 0.0 > tmp) tmp = 0.0;
+ else if( 1.0 < tmp) tmp = 1.0;
+ y = (gx_color_value)(tmp * gx_max_color_value + 0.499);
+
+ } else {
+
+ c = m = y = gx_max_color_value;
+
+ }
+
+ rv = upd_truncate(upd,0,black) | upd_truncate(upd,1,c) |
+ upd_truncate(upd,2,m) | upd_truncate(upd,3,y);
+
+/* It might still become a "gx_no_color_value" due to truncation, thus: */
+
+ if(rv == gx_no_color_index) rv ^= 1;
+ }
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ errprintf(pdev->memory,
+ "rgb_ovcolor: (%5.1f,%5.1f,%5.1f) : (%5.1f,%5.1f,%5.1f,%5.1f) : 0x%0*lx\n",
+ 255.0 * (double) r / (double) gx_max_color_value,
+ 255.0 * (double) g / (double) gx_max_color_value,
+ 255.0 * (double) b / (double) gx_max_color_value,
+ 255.0 * (double) ((rv >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
+ / (double) upd->cmap[1].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
+ / (double) upd->cmap[2].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
+ / (double) upd->cmap[3].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ (pdev->color_info.depth + 3)>>2,rv);
+#endif
+
+ return rv;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_rgb_novcolor: Create an KCMY-Index from RGB */
+/* ------------------------------------------------------------------- */
+
+static gx_color_index
+upd_rgb_novcolor(gx_device *pdev, const gx_color_value cv[])
+{
+ const upd_p upd = ((upd_device *)pdev)->upd;
+ gx_color_index rv;
+ gx_color_value c,m,y,black;
+ gx_color_value r, g, b;
+ r = cv[0]; g = cv[1]; b = cv[2];
+
+ if((r == g) && (g == b)) {
+
+ black = gx_max_color_value - r;
+ rv = upd_truncate(upd,0,black);
+ c = m = y = 0;
+
+ } else {
+
+ c = gx_max_color_value - r;
+ m = gx_max_color_value - g;
+ y = gx_max_color_value - b;
+
+ black = c < m ? c : m;
+ black = black < y ? black : y;
+ c = c - black;
+ m = m - black;
+ y = y - black;
+
+ rv = upd_truncate(upd,0,black) | upd_truncate(upd,1,c) |
+ upd_truncate(upd,2,m) | upd_truncate(upd,3,y);
+
+/* It might still become a "gx_no_color_value" due to truncation, thus: */
+
+ if(rv == gx_no_color_index) rv ^= 1;
+ }
+
+#if UPD_MESSAGES & UPD_M_MAPCALLS
+ errprintf(pdev->memory,
+ "rgb_ovcolor: (%5.1f,%5.1f,%5.1f) : (%5.1f,%5.1f,%5.1f,%5.1f) : 0x%0*lx\n",
+ 255.0 * (double) r / (double) gx_max_color_value,
+ 255.0 * (double) g / (double) gx_max_color_value,
+ 255.0 * (double) b / (double) gx_max_color_value,
+ 255.0 * (double) ((rv >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
+ / (double) upd->cmap[1].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
+ / (double) upd->cmap[2].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
+ / (double) upd->cmap[3].bitmsk,
+ 255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
+ / (double) upd->cmap[0].bitmsk,
+ (pdev->color_info.depth + 3)>>2,rv);
+#endif
+
+ return rv;
+}
+
+/* ------------------------------------------------------------------- */
+/* NOTE: Beyond this point only "uniprint"-special-items. */
+/* ------------------------------------------------------------------- */
+
+/* ------------------------------------------------------------------- */
+/* Truncate a gx_color_value to the desired number of bits. */
+/* ------------------------------------------------------------------- */
+
+static uint32_t
+upd_truncate(upd_pc upd,int i,gx_color_value v) {
+ const updcmap_pc cmap = upd->cmap + i;
+ int32_t s; /* step size */
+ gx_color_value *p; /* value-pointer */
+
+ if(0 == cmap->bits) { /* trivial case */
+
+ v = 0;
+
+ } else if(gx_color_value_bits > cmap->bits) { /* really truncate ? */
+
+ p = cmap->code + ((cmap->bitmsk + 1) >> 1);
+ s = ((cmap->bitmsk + 1) >> 2);
+/*
+ * Perform search in monotonic code-array
+ */
+ while(s > 0) {
+ if(v > *p) { /* we're below */
+ p += s;
+ } else if(v < p[-1]) { /* we're ahead for sure */
+ p -= s;
+ } else {
+/* years ago, i knew what this was good for */
+ if((v-p[-1]) < (p[0]-v)) p -= 1;
+ break;
+ }
+ s >>= 1;
+ }
+ if((v-p[-1]) < (p[0]-v)) p -= 1;
+ v = p - cmap->code;
+ }
+
+ if(!cmap->rise) v = cmap->bitmsk - v; /* Again reverse, if necessary */
+
+ return ((uint32_t) v) << cmap->bitshf;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_open_map: install the color-mapping */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_open_map(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ int imap;
+
+/** _always_ initialize crucial Values! */
+ for(imap = 0; UPD_CMAP_MAX > imap; ++imap) upd->cmap[imap].code = NULL;
+ upd->ncomp = 0;
+
+/** There should not be an error yet */
+ if(B_ERROR & upd->flags) imap = 0;
+
+/** Establish the xfer-Indices */
+ if(imap) {
+ for(imap = 0; UPD_CMAP_MAX > imap; ++imap) {
+ upd->cmap[imap].xfer = -1;
+ upd->cmap[imap].bits = 0;
+ }
+ switch(upd->choice[C_MAPPER]) {
+ case MAP_GRAY:
+ upd->cmap[0].xfer = FA_WXFER;
+ break;
+ case MAP_RGBW:
+ upd->cmap[0].xfer = FA_WXFER;
+ upd->cmap[1].xfer = FA_RXFER;
+ upd->cmap[2].xfer = FA_GXFER;
+ upd->cmap[3].xfer = FA_BXFER;
+ break;
+ case MAP_RGB:
+ upd->cmap[0].xfer = FA_RXFER;
+ upd->cmap[1].xfer = FA_GXFER;
+ upd->cmap[2].xfer = FA_BXFER;
+ break;
+ case MAP_CMYK:
+ upd->cmap[0].xfer = FA_KXFER;
+ upd->cmap[1].xfer = FA_CXFER;
+ upd->cmap[2].xfer = FA_MXFER;
+ upd->cmap[3].xfer = FA_YXFER;
+ break;
+ case MAP_CMYKGEN:
+ upd->cmap[0].xfer = FA_KXFER;
+ upd->cmap[1].xfer = FA_CXFER;
+ upd->cmap[2].xfer = FA_MXFER;
+ upd->cmap[3].xfer = FA_YXFER;
+ break;
+ case MAP_RGBOV:
+ upd->cmap[0].xfer = FA_KXFER;
+ upd->cmap[1].xfer = FA_CXFER;
+ upd->cmap[2].xfer = FA_MXFER;
+ upd->cmap[3].xfer = FA_YXFER;
+ break;
+ case MAP_RGBNOV:
+ upd->cmap[0].xfer = FA_KXFER;
+ upd->cmap[1].xfer = FA_CXFER;
+ upd->cmap[2].xfer = FA_MXFER;
+ upd->cmap[3].xfer = FA_YXFER;
+ break;
+ default:
+#if UPD_MESSAGES & UPD_M_WARNING
+ if(upd_choice[C_MAPPER][0])
+ errprintf(udev->memory,
+ "upd_open_map: unsupported %s=%d\n",
+ upd_choice[C_MAPPER][0],upd->choice[C_MAPPER]);
+ else
+ errprintf(udev->memory,
+ "upd_open_map: unsupported choce[%d]=%d\n",
+ C_MAPPER,upd->choice[C_MAPPER]);
+#endif
+ imap = 0;
+ break;
+ }
+ }
+
+/** The bit number sould be positive & fit into the storage */
+
+ if(imap) { /* Check number of Bits & Shifts */
+
+#if UPD_MESSAGES & UPD_M_WARNING
+ uint32_t used = 0,bitmsk;
+#endif
+ bool success = true;
+
+ for(imap = 0; UPD_CMAP_MAX > imap; ++imap) {
+ if(0 > upd->cmap[imap].xfer) continue;
+
+ if((0 > upd->int_a[IA_COMPBITS].data[imap]) ||
+ (gx_color_value_bits < upd->int_a[IA_COMPBITS].data[imap]) ||
+ (0 > upd->int_a[IA_COMPSHIFT].data[imap]) ||
+ (upd->int_a[IA_COMPBITS].data[imap] >
+ (udev->color_info.depth - upd->int_a[IA_COMPSHIFT].data[imap]))) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "upd_open_map: %d Bits << %d is illegal for %d. Component\n",
+ upd->int_a[IA_COMPBITS].data[imap],
+ upd->int_a[IA_COMPSHIFT].data[imap],imap+1);
+#endif
+
+ success = false;
+
+ } else {
+
+ int n;
+ const float *now;
+ float last;
+
+ if((NULL == upd->float_a[upd->cmap[imap].xfer].data) ||
+ (2 > upd->float_a[upd->cmap[imap].xfer].size) ) {
+ float *fp;
+ UPD_MM_DEL_PARAM(udev->memory, upd->float_a[upd->cmap[imap].xfer]);
+ UPD_MM_GET_ARRAY(udev->memory, fp,2);
+ fp[0] = 0.0;
+ fp[1] = 1.0;
+ upd->float_a[upd->cmap[imap].xfer].data = fp;
+ upd->float_a[upd->cmap[imap].xfer].size = 2;
+ }
+ n = upd->float_a[upd->cmap[imap].xfer].size-1;
+ now = upd->float_a[upd->cmap[imap].xfer].data;
+ last = now[n];
+
+ if( *now < last) { /* Rising */
+ last = *now++;
+ while(n--) {
+ if(last >= *now) break;
+ last = *now++;
+ }
+ } else if(*now > last) { /* Falling */
+ last = *now++;
+ while(n--) {
+ if(last <= *now) break;
+ last = *now++;
+ }
+ } /* Monotony-check */
+
+ if(0 <= n) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "upd_open_map: %d. Component has non monoton Xfer\n",imap+1);
+#endif
+ success = false;
+
+ } else {
+
+#if UPD_MESSAGES & UPD_M_WARNING
+
+ bitmsk = ((uint32_t) 1 << upd->int_a[IA_COMPBITS].data[imap]) -1;
+ bitmsk <<= upd->int_a[IA_COMPSHIFT].data[imap];
+
+ if(used & bitmsk) errprintf(udev->memory,
+ "upd_open_map: %d. Component overlaps with others\n",imap+1);
+
+ used |= bitmsk;
+#endif
+ }
+ }
+ }
+
+ if(!success) imap = 0;
+
+ } /* Check number of Bits */
+
+/** Do the allocation */
+
+ if(imap) {
+
+ for(imap = 0; UPD_CMAP_MAX > imap; ++imap) {
+ if(0 > upd->cmap[imap].xfer) continue;
+
+ upd->cmap[imap].bits = upd->int_a[IA_COMPBITS].data[imap];
+ upd->cmap[imap].bitshf = upd->int_a[IA_COMPSHIFT].data[imap];
+ upd->cmap[imap].bitmsk = 1;
+ upd->cmap[imap].bitmsk <<= upd->cmap[imap].bits;
+ upd->cmap[imap].bitmsk -= 1;
+ upd->cmap[imap].rise =
+ upd->float_a[upd->cmap[imap].xfer].data[0] <
+ upd->float_a[upd->cmap[imap].xfer].data[
+ upd->float_a[upd->cmap[imap].xfer].size-1] ?
+ true : false;
+ upd->cmap[imap].code = gs_malloc(udev->memory, upd->cmap[imap].bitmsk+1,
+ sizeof(upd->cmap[imap].code[0]),"upd/code");
+ if(!upd->cmap[imap].code) break;
+ }
+
+ if(UPD_CMAP_MAX > imap) {
+
+ imap = 0;
+
+#if UPD_MESSAGES & UPD_M_ERROR
+ errprintf(udev->memory,
+ "upd_open_map: could not allocate code-arrays\n");
+# endif
+
+ }
+ }
+
+/** then fill the code-arrays */
+
+ if(imap) {
+/*
+ * Try making things easier: (than with stcolor)
+ * normalize values to 0.0/1.0-Range
+ * X-Axis: Color-Values (implied)
+ * Y-Values: Indices (given)
+ */
+
+ for(imap = 0; UPD_CMAP_MAX > imap; ++imap) {
+
+ const updcmap_p cmap = upd->cmap + imap;
+ uint32_t ly,iy;
+ float ystep,xstep,fx,fy;
+
+/* Variables & Macro for Range-Normalization */
+ double offset,scale;
+#define XFVAL(I) ((upd->float_a[cmap->xfer].data[I]-offset)*scale)
+
+ if(0 > cmap->xfer) continue;
+
+ cmap->code[cmap->bitmsk] = gx_max_color_value;
+
+ if(!cmap->bits) continue;
+
+ offset = upd->float_a[cmap->xfer].data[0];
+ if( 0.0 > offset) offset = 0.0;
+ else if(1.0 < offset) offset = 1.0;
+
+ scale = upd->float_a[cmap->xfer].data[upd->float_a[cmap->xfer].size-1];
+ if( 0.0 > scale ) scale = 0.0;
+ else if(1.0 < scale ) scale = 1.0;
+
+ if(scale != offset) scale = 1.0 / (scale - offset);
+ else scale = 0.0;
+
+/* interpolate */
+ ystep = (float) 1.0 / (float) cmap->bitmsk;
+ xstep = (float) 1.0 / (float)(upd->float_a[cmap->xfer].size - 1);
+
+ iy = 0;
+ for(ly = 0; ly <= cmap->bitmsk; ++ly) {
+
+ fy = ystep * ly; /* Target-Value */
+
+ while(((iy+2) < upd->float_a[cmap->xfer].size) &&
+ (fy > XFVAL(iy+1))) ++iy;
+
+ fx = iy + (fy - XFVAL(iy))/(XFVAL(iy+1) - XFVAL(iy));
+
+ fx *= xstep * gx_max_color_value;
+
+ fx = fx < 0.0 ? 0.0 :
+ (fx > gx_max_color_value ? gx_max_color_value : fx);
+
+ cmap->code[ly] = (gx_color_value)fx;
+ if((fx - cmap->code[ly]) >= 0.5) cmap->code[ly] += 1;
+ }
+
+#undef XFVAL
+
+ }
+ }
+
+/** If we're ok, massage upd->ncomp */
+
+ if(imap) {
+ switch(upd->choice[C_MAPPER]) {
+ case MAP_GRAY:
+ if(1 > imap) imap = 0;
+ upd->ncomp = 1;
+ break;
+ case MAP_RGBW: /* RGB->RGBW */
+ if(4 > imap) imap = 0;
+ upd->ncomp = 4;
+ break;
+ case MAP_RGB: /* Plain RGB */
+ if(3 > imap) imap = 0;
+ upd->ncomp = 3;
+ break;
+ case MAP_CMYK: /* Plain KCMY */
+ if(4 > imap) imap = 0;
+ upd->ncomp = 4;
+ break;
+ case MAP_CMYKGEN: /* KCMY with black-generation */
+ if(4 > imap) imap = 0;
+ upd->ncomp = 4;
+ break;
+ case MAP_RGBOV: /* RGB->KCMY with black-generation */
+ if(4 > imap) imap = 0;
+ upd->ncomp = 4;
+ break;
+ case MAP_RGBNOV: /* RGB->KCMY with black-generation */
+ if(4 > imap) imap = 0;
+ upd->ncomp = 4;
+ break;
+
+ default:
+ imap = 0;
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "upd_open: Mapping %d unknown\n",upd->choice[C_MAPPER]);
+#endif
+
+ break;
+ }
+ }
+
+/** If unsuccesful, install the default routines */
+
+ if(!imap) {
+ upd_close_map(udev);
+ } else {
+ upd->flags |= B_MAP;
+ upd_procs_map(udev);
+ }
+
+ return imap ? 1 : -1;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_procs_map: (de-) install the color-mapping-procedures */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_procs_map(upd_device *udev)
+{
+ int imap;
+
+ if( udev->upd &&
+ (udev->upd->flags & B_MAP)) imap = udev->upd->choice[C_MAPPER];
+ else imap = 0;
+
+ switch(imap) {
+ case MAP_GRAY: /* Grayscale -> Grayscale */
+ set_dev_proc(udev,encode_color, upd_rgb_1color);
+ set_dev_proc(udev,decode_color, upd_1color_rgb);
+ set_dev_proc(udev,map_rgb_color, upd_rgb_1color);
+ set_dev_proc(udev,map_cmyk_color,gx_default_map_cmyk_color);
+ set_dev_proc(udev,map_color_rgb, upd_1color_rgb);
+ break;
+ case MAP_RGBW: /* RGB->RGBW */
+ set_dev_proc(udev,encode_color, upd_rgb_4color);
+ set_dev_proc(udev,decode_color, upd_4color_rgb);
+ set_dev_proc(udev,map_rgb_color, upd_rgb_4color);
+ set_dev_proc(udev,map_cmyk_color,gx_default_map_cmyk_color);
+ set_dev_proc(udev,map_color_rgb, upd_4color_rgb);
+ break;
+ case MAP_RGB: /* Plain RGB */
+ set_dev_proc(udev,encode_color, upd_rgb_3color);
+ set_dev_proc(udev,decode_color, upd_3color_rgb);
+ set_dev_proc(udev,map_rgb_color, upd_rgb_3color);
+ set_dev_proc(udev,map_cmyk_color,gx_default_map_cmyk_color);
+ set_dev_proc(udev,map_color_rgb, upd_3color_rgb);
+ break;
+ case MAP_CMYK: /* Plain KCMY */
+ set_dev_proc(udev,encode_color, upd_cmyk_icolor);
+ set_dev_proc(udev,decode_color, upd_icolor_rgb);
+ set_dev_proc(udev,map_rgb_color, gx_default_map_rgb_color);
+ set_dev_proc(udev,map_cmyk_color,upd_cmyk_icolor);
+ set_dev_proc(udev,map_color_rgb, upd_icolor_rgb);
+ break;
+ case MAP_CMYKGEN: /* KCMY with black-generation */
+ set_dev_proc(udev,encode_color, upd_cmyk_kcolor);
+ set_dev_proc(udev,decode_color, upd_kcolor_rgb);
+ set_dev_proc(udev,map_rgb_color, gx_default_map_rgb_color);
+ set_dev_proc(udev,map_cmyk_color,upd_cmyk_kcolor);
+ set_dev_proc(udev,map_color_rgb, upd_kcolor_rgb);
+ break;
+ case MAP_RGBOV: /* RGB -> KCMY with BG and UCR for CMYK-Output */
+ set_dev_proc(udev,encode_color, upd_rgb_ovcolor);
+ set_dev_proc(udev,decode_color, upd_ovcolor_rgb);
+ set_dev_proc(udev,map_rgb_color, upd_rgb_ovcolor);
+ set_dev_proc(udev,map_cmyk_color,gx_default_map_cmyk_color);
+ set_dev_proc(udev,map_color_rgb, upd_ovcolor_rgb);
+ break;
+ case MAP_RGBNOV: /* RGB -> KCMY with BG and UCR for CMY+K-Output */
+ set_dev_proc(udev,encode_color, upd_rgb_novcolor);
+ set_dev_proc(udev,decode_color, upd_novcolor_rgb);
+ set_dev_proc(udev,map_rgb_color, upd_rgb_novcolor);
+ set_dev_proc(udev,map_cmyk_color,gx_default_map_cmyk_color);
+ set_dev_proc(udev,map_color_rgb, upd_novcolor_rgb);
+ break;
+
+ default:
+ set_dev_proc(udev,encode_color, gx_default_map_rgb_color);
+ set_dev_proc(udev,decode_color, gx_default_map_color_rgb);
+ set_dev_proc(udev,map_rgb_color, gx_default_map_rgb_color);
+ set_dev_proc(udev,map_cmyk_color,gx_default_map_cmyk_color);
+ set_dev_proc(udev,map_color_rgb, gx_default_map_color_rgb);
+ break;
+ }
+ return 0;
+
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_close_map: remove color mapping */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_close_map(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ int imap;
+
+ if(upd) {
+
+ for(imap = 0; UPD_CMAP_MAX > imap; ++imap) {
+
+ if(upd->cmap[imap].code)
+ gs_free(udev->memory, upd->cmap[imap].code,sizeof(upd->cmap[imap].code[0]),
+ upd->cmap[imap].bitmsk+1,"upd/code");
+ upd->cmap[imap].code = NULL;
+
+ upd->cmap[imap].bitmsk = 0;
+ upd->cmap[imap].bitshf = 0;
+ upd->cmap[imap].bits = 0;
+ upd->cmap[imap].rise = false;
+ }
+ upd->flags &= ~B_MAP;
+ }
+
+ upd_procs_map(udev);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* Functions for the rendering of data */
+/* ------------------------------------------------------------------- */
+
+/**
+Inside the main-upd-type are a "valbuf" and some unidentified
+pointers. This stuff is used in conjunction with the rendering,
+which is the process of converting gx_color_indices into something
+suitable for the device.
+
+*/
+
+/* ------------------------------------------------------------------- */
+/* upd_open_render: Initialize rendering */
+/* ------------------------------------------------------------------- */
+
+static void
+upd_open_render(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ int icomp;
+
+/** Reset everything related to rendering */
+ upd->flags &= ~B_RENDER;
+ upd->valbuf = NULL;
+ upd->nvalbuf = 0;
+ upd->render = NULL;
+ upd->start_render = NULL;
+ for(icomp = 0; UPD_VALPTR_MAX > icomp; ++icomp) upd->valptr[icomp] = NULL;
+
+ if( (B_BUF | B_MAP) ==
+ ((B_BUF | B_MAP | B_ERROR) & upd->flags)) {
+
+/** Establish the renderingwidth in upd */
+ upd->rwidth = upd->gswidth;
+ if((0 < upd->ints[I_PWIDTH]) &&
+ (upd->gswidth > upd->ints[I_PWIDTH]) )
+ upd->rwidth = upd->ints[I_PWIDTH];
+
+/** Call the Render-specific Open-Function */
+ switch(upd->choice[C_RENDER]) {
+ case RND_FSCOMP:
+ upd_open_fscomp(udev);
+ break;
+ case RND_FSCMYK:
+ upd_open_fscmyk(udev);
+ break;
+ case RND_FSCMY_K:
+ upd_open_fscmy_k(udev);
+ break;
+ default:
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory, "upd_open_render: Unknown rendering type %d\n",
+ upd->choice[C_RENDER]);
+#endif
+ break;
+ }
+ }
+
+ if(B_RENDER != ((B_ERROR | B_RENDER) & upd->flags))
+ upd_close_render(udev);
+
+ return;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_close_render: Deinitialize rendering */
+/* ------------------------------------------------------------------- */
+
+static void
+upd_close_render(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+
+ if(upd) {
+ int icomp;
+
+ if((upd->render == upd_fscomp) ||
+ (upd->render == upd_fscmyk) ) upd_close_fscomp(udev);
+
+ if((0 < upd->nvalbuf) && upd->valbuf)
+ gs_free(udev->memory, upd->valbuf,upd->nvalbuf,sizeof(upd->valbuf[0]),"upd/valbuf");
+ upd->valbuf = NULL;
+ upd->nvalbuf = 0;
+
+ upd->flags &= ~B_RENDER;
+ upd->render = NULL;
+ upd->start_render = NULL;
+ for(icomp = 0; UPD_VALPTR_MAX > icomp; ++icomp) upd->valptr[icomp] = NULL;
+
+ }
+ return;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_open_fscomp: Initialize Component-Floyd-Steinberg */
+/* ------------------------------------------------------------------- */
+#if UPD_MESSAGES & UPD_M_FSBUF
+static int32_t fs_emin[UPD_VALPTR_MAX],fs_emax[UPD_VALPTR_MAX];
+#endif
+static void
+upd_open_fscomp(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ int icomp,order[UPD_CMAP_MAX];
+
+#if UPD_MESSAGES & UPD_M_FSBUF
+ for(icomp = 0; UPD_VALPTR_MAX < icomp; ++icomp)
+ fs_emin[icomp] = fs_emax[icomp] = 0;
+#endif
+
+ icomp = upd->ncomp;
+
+ if((0 >= icomp) ||
+ (UPD_VALPTR_MAX < icomp) ||
+ (UPD_CMAP_MAX < icomp) ) icomp = 0;
+
+/**
+This Version of the FS-algorithm works on the mapped components, but
+the printing-order might be different from the order dictated by the
+mapping-routines. The optional COMPORDER-Array is used for that. The
+initial test checks it's integrity.
+*/
+ if(icomp) {
+ if(upd->ncomp <= upd->int_a[IA_COMPORDER].size) { /* Reordering */
+ bool success = true;
+ for(icomp = 0; upd->ncomp > icomp; ++icomp) {
+ order[icomp] = upd->int_a[IA_COMPORDER].data[icomp];
+ if((0 > order[icomp]) ||
+ (UPD_CMAP_MAX <= order[icomp]) ) {
+ success = false;
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "upd_open_fscomp: %d is illegal component-index\n",
+ order[icomp]);
+#endif
+ }
+ }
+ if(!success) icomp = 0;
+ } else { /* Default-Ordering */
+ for(icomp = 0; UPD_CMAP_MAX > icomp; ++icomp) order[icomp] = icomp;
+ } /* Ordering defined */
+ }
+
+/**
+If anything was ok. up to now, memory get's allocated.
+*/
+ if(icomp) {
+
+ for(icomp = 0; upd->ncomp > icomp; ++icomp) {
+ upd->valptr[icomp] = gs_malloc(udev->memory, 1,sizeof(updcomp_t),"upd/fscomp");
+ if(NULL == upd->valptr[icomp]) {
+#if UPD_MESSAGES & UPD_M_ERROR
+ errprintf(udev->memory,
+ "upd_open_fscomp: could not allocate %d. updcomp\n",
+ icomp);
+#endif
+ icomp = 0;
+ break;
+ }
+ }
+ }
+
+ if(icomp) {
+ uint need;
+
+ need = (2 + upd->rwidth) * upd->ncomp;
+ upd->valbuf = gs_malloc(udev->memory, need,sizeof(upd->valbuf[0]),"upd/valbuf");
+
+ if(upd->valbuf) {
+ upd->nvalbuf = need;
+ memset(upd->valbuf,0,need*sizeof(upd->valbuf[0]));
+ } else {
+#if UPD_MESSAGES & UPD_M_ERROR
+ errprintf(udev->memory,
+ "upd_open_fscomp: could not allocate %u words for valbuf\n",
+ need);
+#endif
+ icomp = 0;
+ }
+ }
+
+/* Still happy? then compute component-values */
+
+ if(icomp) {
+ for(icomp = 0; upd->ncomp > icomp; ++icomp) {
+
+ const updcomp_p comp = upd->valptr[icomp];
+ const int32_t nsteps = upd->cmap[order[icomp]].bitmsk;
+ float ymin,ymax;
+ int32_t highmod,highval;
+ int i;
+
+ comp->threshold = nsteps;
+ comp->spotsize = nsteps;
+ comp->offset = 0;
+ comp->scale = 1;
+ comp->cmap = order[icomp];
+ upd->cmap[comp->cmap].comp = icomp;
+ comp->bits = upd->cmap[comp->cmap].bits;
+ comp->bitshf = upd->cmap[comp->cmap].bitshf;
+ comp->bitmsk = upd->cmap[comp->cmap].bitmsk;
+
+ if(!nsteps) continue; /* A 0-Bit component is legal! */
+
+ if(upd->cmap[comp->cmap].rise) {
+ ymin = upd->float_a[upd->cmap[comp->cmap].xfer].data[0];
+ ymax = upd->float_a[upd->cmap[comp->cmap].xfer].data[
+ upd->float_a[upd->cmap[comp->cmap].xfer].size-1];
+ } else {
+ ymax = upd->float_a[upd->cmap[comp->cmap].xfer].data[0];
+ ymin = upd->float_a[upd->cmap[comp->cmap].xfer].data[
+ upd->float_a[upd->cmap[comp->cmap].xfer].size-1];
+ }
+
+ if(0.0 > ymin) {
+ ymin = 0.0;
+ if(0.0 > ymax) ymax = 1.0 / (float) (nsteps+1);
+ }
+ if(1.0 < ymax) ymax = 1.0;
+
+ comp->spotsize = ((int32_t) 1 << 28) - 1;
+
+ for(i = 0; i < 32; ++i) { /* Attempt Ideal */
+
+ highval = (int32_t)((ymax-ymin) * (double) comp->spotsize + 0.5);
+
+ if(!(highmod = highval % nsteps)) break; /* Gotcha */
+
+ highval += nsteps - highmod;
+ comp->spotsize = (int32_t)((double) highval / (ymax-ymin) + 0.5);
+
+ if(!(comp->spotsize % 2)) comp->spotsize++;
+
+ } /* Attempt Ideal */
+
+ comp->offset = (int32_t)(ymin * (double) comp->spotsize + (double) 0.5);
+ comp->scale = highval / nsteps;
+ comp->threshold = comp->spotsize / 2;
+
+#if UPD_MESSAGES & UPD_M_SETUP
+ errprintf(udev->memory,
+ "Values for %d. Component after %d iterations\n",comp->cmap+1,i);
+ errprintf(udev->memory,
+ "steps: %10ld, Bits: %d\n",(long) comp->bitmsk,comp->bits);
+ errprintf(udev->memory,
+ "xfer: %10d Points, %s\n",
+ upd->float_a[upd->cmap[comp->cmap].xfer].size,
+ upd->cmap[comp->cmap].rise ? "rising" : "falling");
+ errprintf(udev->memory,
+ "offset: %10d 0x%08x\n",comp->offset,comp->offset);
+ errprintf(udev->memory,
+ "scale: %10d 0x%08x\n",comp->scale,comp->scale);
+ errprintf(udev->memory,
+ "threshold: %10d 0x%08x\n",comp->threshold,comp->threshold);
+ errprintf(udev->memory,
+ "spotsize: %10d 0x%08x\n",comp->spotsize,comp->spotsize);
+#endif
+ }
+ }
+/**
+Optional Random Initialization of the value-Buffer
+*/
+ if(icomp && !(B_FSZERO & upd->flags)) {
+ for(icomp = 0; icomp < upd->ncomp; ++icomp) {
+ const updcomp_p comp = upd->valptr[icomp];
+ int i;
+ int32_t lv = INT32_MAX, hv = INT32_MIN, v;
+ float scale;
+ for(i = icomp; i < upd->nvalbuf; i += upd->ncomp) {
+ v = rand();
+ if(lv > v) lv = v;
+ if(hv < v) hv = v;
+ upd->valbuf[i] = v;
+ }
+ scale = (float) comp->threshold / (float) (hv - lv);
+ lv += (int32_t)(comp->threshold / (2*scale));
+ for(i = icomp; i < upd->nvalbuf; i += upd->ncomp)
+ upd->valbuf[i] = (int32_t)(scale * (upd->valbuf[i] - lv));
+ }
+ }
+
+/**
+The render-Routine acts as an indicator, which render-close is to use!
+*/
+ upd->render = upd_fscomp;
+
+ if(icomp) upd->flags |= B_RENDER;
+ else upd->flags &= ~B_RENDER;
+
+ return;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_close_fscomp: Deinitialize Component-Floyd-Steinberg */
+/* ------------------------------------------------------------------- */
+
+static void
+upd_close_fscomp(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ int icomp;
+
+#if UPD_MESSAGES & UPD_M_FSBUF
+ if(upd && (upd->flags & B_RENDER)) {
+
+ for(icomp = 0; icomp < upd->ncomp; ++icomp) {
+ updcomp_p comp = upd->valptr[icomp];
+ if(!comp) continue;
+ if(!comp->spotsize) continue;
+ errprintf(udev->memory,"%d. Component: %6.3f <= error <= %6.3f\n",
+ icomp+1,
+ (double) fs_emin[icomp] / (double) comp->spotsize,
+ (double) fs_emax[icomp] / (double) comp->spotsize);
+ }
+
+ }
+#endif
+
+ for(icomp = 0; UPD_VALPTR_MAX > icomp; ++icomp) {
+ if(!upd->valptr[icomp]) continue;
+ gs_free(udev->memory, upd->valptr[icomp],1,sizeof(updcomp_t),"upd/fscomp");
+ upd->valptr[icomp] = NULL;
+ }
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_fscomp: Apply Floyd-Steinberg to each component */
+/* ------------------------------------------------------------------- */
+
+/**
+ With UPD_M_FSBUF Max/Min-Values for the Errors are computed
+*/
+#if UPD_MESSAGES & UPD_M_FSBUF
+#define FS_M_ROWERR(I) \
+ if(fs_emin[I] > rowerr[I]) fs_emin[I] = rowerr[I]; \
+ if(fs_emax[I] < rowerr[I]) fs_emax[I] = rowerr[I];
+#else
+#define FS_M_ROWERR(I) ;
+#endif
+/**
+ FS_GOAL computes the desired Pixel-Value
+*/
+#define FS_GOAL(Raw,I) \
+ pixel[I] = (int32_t)(Raw) * comp[I]->scale + comp[I]->offset \
+ + rowerr[I] + colerr[I] - ((colerr[I]+4)>>3); \
+ if( pixel[I] < 0) pixel[I] = 0; \
+ else if( pixel[I] > comp[I]->spotsize) pixel[I] = comp[I]->spotsize;
+
+/*
+ * Distribute the error: prev now next
+ * X 7/16 Y
+ * 3/16 5/16 1/16 Y+1
+ */
+#define FS_DIST(I) \
+ if(!first) rowerr[I-dir] += ((3*pixel[I]+8)>>4); /* 3/16 */ \
+ rowerr[I ] = ((5*pixel[I] )>>4) /* 5/16 */ \
+ + (( colerr[I]+4)>>3); /* 1/16 (rest) */ \
+ colerr[I ] = pixel[I] /* 8/16 (neu) */ \
+ - ((5*pixel[I] )>>4) \
+ - ((3*pixel[I]+8)>>4);
+/**
+ S_FSTEP adjusts the Indices (rowerr, bit and iword)
+*/
+#define S_FSTEP \
+ rowerr += dir; \
+ first = false; \
+ if(0 > dir) { /* Reverse */ \
+ if(!(bit <<= 1)) { bit = 0x01; ibyte--; }\
+ } else { /* Forward */ \
+ if(!(bit >>= 1)) { bit = 0x80; ibyte++; }\
+ } /* Inc/Dec Bit */
+
+static int
+upd_fscomp(upd_p upd)
+{
+ const updscan_p scan = upd->scnbuf[upd->yscnbuf & upd->scnmsk];
+ const updcomp_p *comp = (updcomp_p *) upd->valptr;
+ int32_t *const pixel = upd->valbuf;
+ int32_t *const colerr = pixel + upd->ncomp;
+ int32_t *rowerr = colerr + upd->ncomp;
+ int pwidth = upd->rwidth;
+ int dir,ibyte;
+ int iblack,bblack,pxlset;
+ uint32_t ci;
+ byte bit;
+ bool first = true;
+/*
+ * Erase the component-Data
+ */
+ switch(upd->ncomp) {
+ case 4: memset(scan[3].bytes,0,upd->nbytes);
+ case 3: memset(scan[2].bytes,0,upd->nbytes);
+ memset(scan[1].bytes,0,upd->nbytes);
+ default: memset(scan[0].bytes,0,upd->nbytes);
+ }
+/*
+ * determine the direction
+ */
+ if(upd->flags & B_REVDIR) { /* This one reverse */
+
+ if(upd->flags & B_YFLIP) {
+ dir = upd->ncomp;
+ bit = 0x80;
+ ibyte = 0;
+ } else {
+ dir = -upd->ncomp;
+ rowerr += upd->ncomp * (pwidth-1);
+ bit = 0x80 >> ((pwidth-1) & 7);
+ ibyte = (pwidth-1) >> 3;
+ }
+
+ if(!(upd->flags & B_FSWHITE)) {
+ upd_pxlfwd(upd);
+ while((0 < pwidth) && !upd_pxlget(upd)) pwidth--;
+ }
+
+ upd_pxlrev(upd);
+
+ } else { /* This one forward */
+
+ if(upd->flags & B_YFLIP) {
+ dir = -upd->ncomp;
+ rowerr += upd->ncomp * (pwidth-1);
+ bit = 0x80 >> ((pwidth-1) & 7);
+ ibyte = (pwidth-1) >> 3;
+ } else {
+ dir = upd->ncomp;
+ bit = 0x80;
+ ibyte = 0;
+ }
+
+ if(!(upd->flags & B_FSWHITE)) {
+ upd_pxlrev(upd);
+ while((0 < pwidth) && !upd_pxlget(upd)) pwidth--;
+ }
+
+ upd_pxlfwd(upd);
+
+ } /* reverse or forward */
+/*
+ * Toggle Direction, if not fixed
+ */
+ if(!(upd->flags & B_FIXDIR)) upd->flags ^= B_REVDIR;
+/*
+ * Skip over leading white-space
+ */
+ if(!(upd->flags & B_FSWHITE)) {
+ upd_proc_pxlget((*fun)) = upd->pxlget;
+ byte *ptr = upd->pxlptr;
+ while((0 < pwidth) && !upd_pxlget(upd)) {
+ pwidth--;
+ fun = upd->pxlget;
+ ptr = upd->pxlptr;
+ S_FSTEP
+ }
+ upd->pxlget = fun;
+ upd->pxlptr = ptr;
+ }
+/*
+ * Set iblack, if black-reduction is active
+ */
+ iblack = -1;
+ bblack = 0;
+ if((4 == upd->ncomp) && (B_REDUCEK & upd->flags)) {
+ iblack = upd->cmap[0].comp;
+ bblack = 1<<iblack;
+ }
+/*
+ * Process all Pixels
+ */
+ first = true;
+ while(0 < pwidth--) {
+/*
+ * Execute FS-Algorithm for each active component
+ */
+ pxlset = 0;
+ ci = upd_pxlget(upd);
+ switch(upd->ncomp) {
+ case 4: FS_M_ROWERR(3)
+ FS_GOAL(comp[3]->bitmsk & (ci >> comp[3]->bitshf),3)
+ if(pixel[3] > comp[3]->threshold) { /* "Fire" */
+ pixel[3] -= comp[3]->spotsize;
+ scan[3].bytes[ibyte] |= bit;
+ pxlset |= 8;
+ } /* "Fire" */
+ FS_DIST(3)
+
+ case 3: FS_M_ROWERR(2)
+ FS_GOAL(comp[2]->bitmsk & (ci >> comp[2]->bitshf),2)
+ if(pixel[2] > comp[2]->threshold) { /* "Fire" */
+ pixel[2] -= comp[2]->spotsize;
+ scan[2].bytes[ibyte] |= bit;
+ pxlset |= 4;
+ } /* "Fire" */
+ FS_DIST(2)
+
+ FS_M_ROWERR(1)
+ FS_GOAL(comp[1]->bitmsk & (ci >> comp[1]->bitshf),1)
+ if(pixel[1] > comp[1]->threshold) { /* "Fire" */
+ pixel[1] -= comp[1]->spotsize;
+ scan[1].bytes[ibyte] |= bit;
+ pxlset |= 2;
+ } /* "Fire" */
+ FS_DIST(1)
+
+ default: FS_M_ROWERR(0)
+ FS_GOAL(comp[0]->bitmsk & (ci >> comp[0]->bitshf),0)
+ if(pixel[0] > comp[0]->threshold) { /* "Fire" */
+ pixel[0] -= comp[0]->spotsize;
+ scan[0].bytes[ibyte] |= bit;
+ pxlset |= 1;
+ } /* "Fire" */
+ FS_DIST(0)
+ }
+/*
+ * Black-Reduction
+ */
+ if(bblack) {
+ if(pxlset & bblack) pxlset |= 15;
+ switch(pxlset) {
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 3:
+ case 5:
+ case 9:
+ case 6:
+ case 10:
+ case 12:
+ break;
+ default:
+ scan[0].bytes[ibyte] &= ~bit;
+ scan[1].bytes[ibyte] &= ~bit;
+ scan[2].bytes[ibyte] &= ~bit;
+ scan[3].bytes[ibyte] &= ~bit;
+ scan[iblack].bytes[ibyte] |= bit;
+ break;
+ }
+ }
+/*
+ * Adjust rowerr, bit & iword, depending on direction
+ */
+ S_FSTEP
+ }
+/*
+ * Finally call the limits-Routine
+ */
+ if(0 < upd->nlimits) upd_limits(upd,true);
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_open_fscmyk: Initialize Component-Floyd-Steinberg */
+/* ------------------------------------------------------------------- */
+
+static void
+upd_open_fscmyk(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+
+ upd_open_fscomp(udev);
+
+ if((B_RENDER & upd->flags) &&
+ (4 == upd->ncomp) &&
+ (8 <= upd->cmap[0].bits) && (24 == upd->cmap[0].bitshf) &&
+ (8 <= upd->cmap[1].bits) && (16 == upd->cmap[1].bitshf) &&
+ (8 <= upd->cmap[2].bits) && ( 8 == upd->cmap[2].bitshf) &&
+ (8 <= upd->cmap[3].bits) && ( 0 == upd->cmap[3].bitshf) ) {
+ upd->render = upd_fscmyk;
+ } else {
+ upd->flags &= ~B_RENDER;
+ }
+
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_fscmyk: 32 Bit, K-CMY-Order Dithering */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_fscmyk(upd_p upd)
+{
+ const updscan_p scan = upd->scnbuf[upd->yscnbuf & upd->scnmsk];
+ int32_t *const pixel = upd->valbuf;
+ const updcomp_p *comp = (updcomp_p *) upd->valptr;
+ int32_t *const colerr = pixel + 4;
+ int32_t *rowerr = colerr + 4;
+ int32_t pwidth = upd->rwidth;
+ int dir,ibyte;
+ byte bit,*data;
+ bool first = false;
+/*
+ * Erase the component-Data
+ */
+ memset(scan[0].bytes,0,upd->nbytes);
+ memset(scan[1].bytes,0,upd->nbytes);
+ memset(scan[2].bytes,0,upd->nbytes);
+ memset(scan[3].bytes,0,upd->nbytes);
+
+/*
+ * determine the direction
+ */
+ if(upd->flags & B_REVDIR) { /* This one reverse */
+
+ if(!(upd->flags & B_FSWHITE)) {
+ data = upd->gsscan;
+ while(0 < pwidth && !*(uint32_t *)data) pwidth--, data += 4;
+ if(0 >= pwidth) {
+ if(0 < upd->nlimits) upd_limits(upd,false);
+ return 0;
+ }
+ }
+
+ data = upd->gsscan + 4 * (upd->rwidth-1);
+
+ } else { /* This one forward */
+
+ if(!(upd->flags & B_FSWHITE)) {
+ data = upd->gsscan + 4 * (upd->rwidth-1);
+ while(0 < pwidth && !*(uint32_t *)data) pwidth--, data -= 4;
+ if(0 >= pwidth) {
+ if(0 < upd->nlimits) upd_limits(upd,false);
+ return 0;
+ }
+ }
+
+ data = upd->gsscan;
+
+ } /* reverse or forward */
+/*
+ * Bits depend on FLIP & Direction
+ */
+ if(!(B_REVDIR & upd->flags) == !(B_YFLIP & upd->flags)) {
+ dir = 4;
+ bit = 0x80;
+ ibyte = 0;
+ } else {
+ dir = -4;
+ rowerr += 4 * (upd->rwidth-1);
+ bit = 0x80 >> ((upd->rwidth-1) & 7);
+ ibyte = (upd->rwidth-1) >> 3;
+ }
+
+/*
+ * Toggle Direction, if not fixed
+ */
+ if(!(upd->flags & B_FIXDIR)) upd->flags ^= B_REVDIR;
+/*
+ * Skip over leading white-space
+ */
+ if(!(upd->flags & B_FSWHITE)) {
+ while(0 < pwidth && !*((uint32_t *)data)) {
+ pwidth--;
+ if(B_YFLIP & upd->flags) data -= dir;
+ else data += dir;
+ S_FSTEP
+ }
+ }
+/*
+ * Process all Pixels
+ */
+ first = true;
+ while(0 < pwidth--) {
+/*
+ * Compute the Black-Value first
+ */
+ FS_M_ROWERR(upd->cmap[0].comp) FS_GOAL(data[0],upd->cmap[0].comp);
+
+/*
+ * Decide wether this is a color value
+ */
+ if(data[1] || data[2] || data[3]) {
+
+ FS_M_ROWERR(upd->cmap[1].comp) FS_GOAL(data[1],upd->cmap[1].comp)
+ FS_M_ROWERR(upd->cmap[2].comp) FS_GOAL(data[2],upd->cmap[2].comp)
+ FS_M_ROWERR(upd->cmap[3].comp) FS_GOAL(data[3],upd->cmap[3].comp)
+/*
+ * if black fires, then all other components fire logically too
+ */
+ if(pixel[upd->cmap[0].comp] > comp[upd->cmap[0].comp]->threshold) {
+
+ pixel[0] -= comp[0]->spotsize;
+ pixel[1] -= comp[1]->spotsize;
+ pixel[2] -= comp[2]->spotsize;
+ pixel[3] -= comp[3]->spotsize;
+ scan[upd->cmap[0].comp].bytes[ibyte] |= bit;
+
+/*
+ * if black is below threshold, only components with larger data-values
+ * are allowed to fire
+ */
+ } else { /* Restricted firing */
+
+ if(( data[0] < data[1]) &&
+ (pixel[upd->cmap[1].comp] >
+ comp[upd->cmap[1].comp]->threshold)) { /* "Fire" */
+ pixel[upd->cmap[1].comp] -= comp[upd->cmap[1].comp]->spotsize;
+ scan[upd->cmap[1].comp].bytes[ibyte] |= bit;
+ } /* "Fire" */
+
+ if(( data[0] < data[2]) &&
+ (pixel[upd->cmap[2].comp] >
+ comp[upd->cmap[2].comp]->threshold)) { /* "Fire" */
+ pixel[upd->cmap[2].comp] -= comp[upd->cmap[2].comp]->spotsize;
+ scan[upd->cmap[2].comp].bytes[ibyte] |= bit;
+ } /* "Fire" */
+
+ if(( data[0] < data[3]) &&
+ (pixel[upd->cmap[3].comp] >
+ comp[upd->cmap[3].comp]->threshold)) { /* "Fire" */
+ pixel[upd->cmap[3].comp] -= comp[upd->cmap[3].comp]->spotsize;
+ scan[upd->cmap[3].comp].bytes[ibyte] |= bit;
+ } /* "Fire" */
+
+ } /* Fire-Mode */
+
+/*
+ * Handle Color-Errors
+ */
+ FS_DIST(upd->cmap[3].comp)
+ FS_DIST(upd->cmap[2].comp)
+ FS_DIST(upd->cmap[1].comp)
+
+ } else if(pixel[upd->cmap[0].comp] > comp[upd->cmap[0].comp]->threshold) {
+ scan[upd->cmap[0].comp].bytes[ibyte] |= bit;
+ pixel[upd->cmap[0].comp] -= comp[upd->cmap[0].comp]->spotsize;
+ }
+
+ FS_DIST(upd->cmap[0].comp)
+/*
+ * Adjust bit & iword, depending on direction
+ */
+ S_FSTEP
+ if(upd->flags & B_YFLIP) data -= dir;
+ else data += dir;
+ }
+/*
+ * Finally call the limits-Routine
+ */
+ if(0 < upd->nlimits) upd_limits(upd,true);
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_open_fscmy_k: Initialize for CMY_K Printing */
+/* ------------------------------------------------------------------- */
+
+static void
+upd_open_fscmy_k(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+
+ upd_open_fscomp(udev);
+
+ if((B_RENDER & upd->flags) &&
+ (4 == upd->ncomp)) {
+ upd->render = upd_fscmy_k;
+ } else {
+ upd->flags &= ~B_RENDER;
+ }
+
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_fscmy_k: CMY_K rendering */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_fscmy_k(upd_p upd)
+{
+ const updscan_p scan = upd->scnbuf[upd->yscnbuf & upd->scnmsk];
+ const updcomp_p *comp = (updcomp_p *) upd->valptr;
+ int32_t *const pixel = upd->valbuf;
+ int32_t *const colerr = pixel + upd->ncomp;
+ int32_t *rowerr = colerr + upd->ncomp;
+ int pwidth = upd->rwidth;
+ int dir,ibyte;
+ uint32_t ci;
+ byte bit;
+ bool first = true;
+/*
+ * Erase the component-Data
+ */
+ memset(scan[3].bytes,0,upd->nbytes);
+ memset(scan[2].bytes,0,upd->nbytes);
+ memset(scan[1].bytes,0,upd->nbytes);
+ memset(scan[0].bytes,0,upd->nbytes);
+/*
+ * determine the direction
+ */
+ if(upd->flags & B_REVDIR) { /* This one reverse */
+
+ if(upd->flags & B_YFLIP) {
+ dir = 4;
+ bit = 0x80;
+ ibyte = 0;
+ } else {
+ dir = -4;
+ rowerr += 4 * (pwidth-1);
+ bit = 0x80 >> ((pwidth-1) & 7);
+ ibyte = (pwidth-1) >> 3;
+ }
+
+ if(!(upd->flags & B_FSWHITE)) {
+ upd_pxlfwd(upd);
+ while((0 < pwidth) && !upd_pxlget(upd)) pwidth--;
+ }
+
+ upd_pxlrev(upd);
+
+ } else { /* This one forward */
+
+ if(upd->flags & B_YFLIP) {
+ dir = -4;
+ rowerr += 4 * (pwidth-1);
+ bit = 0x80 >> ((pwidth-1) & 7);
+ ibyte = (pwidth-1) >> 3;
+ } else {
+ dir = 4;
+ bit = 0x80;
+ ibyte = 0;
+ }
+
+ if(!(upd->flags & B_FSWHITE)) {
+ upd_pxlrev(upd);
+ while((0 < pwidth) && !upd_pxlget(upd)) pwidth--;
+ }
+
+ upd_pxlfwd(upd);
+
+ } /* reverse or forward */
+/*
+ * Toggle Direction, if not fixed
+ */
+ if(!(upd->flags & B_FIXDIR)) upd->flags ^= B_REVDIR;
+/*
+ * Skip over leading white-space
+ */
+ if(!(upd->flags & B_FSWHITE)) {
+ upd_proc_pxlget((*fun)) = upd->pxlget;
+ byte *ptr = upd->pxlptr;
+ while((0 < pwidth) && !upd_pxlget(upd)) {
+ pwidth--;
+ fun = upd->pxlget;
+ ptr = upd->pxlptr;
+ S_FSTEP
+ }
+ upd->pxlget = fun;
+ upd->pxlptr = ptr;
+ }
+/*
+ * Process all Pixels
+ */
+ first = true;
+ while(0 < pwidth--) {
+
+/* get the Pixel-Value */
+
+ ci = upd_pxlget(upd);
+
+/* process all components */
+
+ FS_M_ROWERR(0) FS_GOAL(comp[0]->bitmsk & (ci >> comp[0]->bitshf),0)
+ FS_M_ROWERR(1) FS_GOAL(comp[1]->bitmsk & (ci >> comp[1]->bitshf),1)
+ FS_M_ROWERR(2) FS_GOAL(comp[2]->bitmsk & (ci >> comp[2]->bitshf),2)
+ FS_M_ROWERR(3) FS_GOAL(comp[3]->bitmsk & (ci >> comp[3]->bitshf),3)
+
+ if(pixel[0] > comp[0]->threshold) { /* Black fires */
+
+ pixel[0] -= comp[0]->spotsize;
+ scan[0].bytes[ibyte] |= bit;
+
+ } else { /* Colors may fire */
+
+ if((pixel[1] <= comp[1]->threshold) ||
+ (pixel[2] <= comp[2]->threshold) ||
+ (pixel[3] <= comp[3]->threshold) ) { /* Really a Color */
+
+ if(pixel[1] > comp[1]->threshold) {
+ pixel[1] -= comp[1]->spotsize;
+ scan[1].bytes[ibyte] |= bit;
+ }
+
+ if(pixel[2] > comp[2]->threshold) {
+ pixel[2] -= comp[2]->spotsize;
+ scan[2].bytes[ibyte] |= bit;
+ }
+
+ if(pixel[3] > comp[3]->threshold) {
+ pixel[3] -= comp[3]->spotsize;
+ scan[3].bytes[ibyte] |= bit;
+ }
+
+ } else {
+ pixel[1] -= comp[1]->spotsize;
+ pixel[2] -= comp[2]->spotsize;
+ pixel[3] -= comp[3]->spotsize;
+ scan[0].bytes[ibyte] |= bit;
+ }
+ }
+
+ FS_DIST(0)
+ FS_DIST(1)
+ FS_DIST(2)
+ FS_DIST(3)
+
+/*
+ * Adjust rowerr, bit & iword, depending on direction
+ */
+ S_FSTEP
+ }
+/*
+ * Finally call the limits-Routine
+ */
+ if(0 < upd->nlimits) upd_limits(upd,true);
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_open_writer: Initialize rendering */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_open_writer(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ bool success = true;
+
+/** Reset the crucial values */
+ upd->start_writer = NULL;
+ upd->writer = NULL;
+ upd->scnbuf = NULL;
+ upd->nscnbuf = 0;
+ upd->nbytes = 0;
+ upd->nlimits = 0;
+ upd->outbuf = NULL;
+ upd->noutbuf = 0;
+
+/** Rendering should be succesfully initialized */
+ if(B_RENDER != ((B_RENDER | B_ERROR) & upd->flags))
+ success = false;
+
+/** Create number of components */
+ upd->ocomp = upd->ncomp;
+ if(0 < upd->ints[I_OCOMP]) upd->ocomp = upd->ints[I_OCOMP];
+
+/** Massage some Parameters */
+ if(success) {
+
+/* Make sure, that Pass & Pin-Numbers are at least 1 */
+ if(1 > upd->ints[I_NYPASS]) upd->ints[I_NYPASS] = 1;
+ if(1 > upd->ints[I_NXPASS]) upd->ints[I_NXPASS] = 1;
+ if(1 > upd->ints[I_PINS2WRITE]) upd->ints[I_PINS2WRITE] = 1;
+
+ if((upd->ints[I_NXPASS] * upd->ints[I_NYPASS]) > upd->ints[I_NPASS])
+ upd->ints[I_NPASS] = upd->ints[I_NXPASS] * upd->ints[I_NYPASS];
+
+/* Create Default noWeave-Feeds */
+
+ if(upd->ints[I_NPASS] > upd->int_a[IA_STD_DY].size) {
+ int ix,iy,*ip;
+ UPD_MM_DEL_PARAM(udev->memory, upd->int_a[IA_STD_DY]);
+ UPD_MM_GET_ARRAY(udev->memory, ip,upd->ints[I_NPASS]);
+ upd->int_a[IA_STD_DY].data = ip;
+ upd->int_a[IA_STD_DY].size = upd->ints[I_NPASS];
+
+ for(iy = 1; iy < upd->ints[I_NYPASS]; ++iy) {
+ for(ix = 1; ix < upd->ints[I_NXPASS]; ++ix) *ip++ = 0;
+ *ip++ = 1;
+ }
+ for(ix = 1; ix < upd->ints[I_NXPASS]; ++ix) *ip++ = 0;
+ *ip = upd->ints[I_NYPASS] * upd->ints[I_PINS2WRITE]
+ - upd->ints[I_NYPASS] + 1;
+
+ upd->ints[I_BEG_Y] = 0;
+ upd->ints[I_END_Y] = upd->ints[I_PHEIGHT] ?
+ upd->ints[I_PHEIGHT] : upd->gsheight;
+ }
+
+/* Adjust BEG_Y */
+ if(0 >= upd->ints[I_BEG_Y]) {
+ if(0 < upd->int_a[IA_BEG_DY].size) {
+ int i,sum = 0;
+ for(i = 0; i < upd->int_a[IA_BEG_DY].size; ++i)
+ sum += upd->int_a[IA_BEG_DY].data[i];
+ upd->ints[I_BEG_Y] = sum;
+ } else {
+ upd->ints[I_BEG_Y] = 0;
+ }
+ }
+
+/* Adjust END_Y */
+/* Arrgh, I knew, why I refused to provide defaults for crucial */
+/* parameters in uniprint. But o.k. it's nice for size-changing */
+/* PostScript-Code. Nevertheless, it's still not perfect. */
+
+ if(0 >= upd->int_a[IA_ENDTOP].size ||
+ 0 >= upd->int_a[IA_END_DY].size ) upd->ints[I_END_Y] =
+ upd->ints[I_PHEIGHT] ? upd->ints[I_PHEIGHT] : upd->gsheight;
+
+ if(0 >= upd->ints[I_END_Y]) upd->ints[I_END_Y] = upd->ints[I_PHEIGHT] ?
+ upd->ints[I_PHEIGHT] : upd->gsheight;
+
+/* Create Default X-Passes */
+
+ if(0 >= upd->int_a[IA_STD_IX].size) {
+ int ix,i,*ip;
+ UPD_MM_DEL_PARAM(udev->memory, upd->int_a[IA_STD_IX]);
+ UPD_MM_GET_ARRAY(udev->memory, ip,upd->int_a[IA_STD_DY].size);
+ upd->int_a[IA_STD_IX].data = ip;
+ upd->int_a[IA_STD_IX].size = upd->int_a[IA_STD_DY].size;
+
+ for(i = 0, ix = 0; i < upd->int_a[IA_STD_IX].size; ++i) {
+ *ip++ = ix++;
+ if(ix == upd->ints[I_NXPASS]) ix = 0;
+ }
+ }
+
+ if((0 >= upd->int_a[IA_BEG_IX].size) &&
+ (0 < upd->int_a[IA_BEG_DY].size) ) {
+ int ix,i,*ip;
+ UPD_MM_DEL_PARAM(udev->memory, upd->int_a[IA_BEG_IX]);
+ UPD_MM_GET_ARRAY(udev->memory, ip,upd->int_a[IA_BEG_DY].size);
+ upd->int_a[IA_BEG_IX].data = ip;
+ upd->int_a[IA_BEG_IX].size = upd->int_a[IA_BEG_DY].size;
+
+ for(i = 0, ix = 0; i < upd->int_a[IA_BEG_IX].size; ++i) {
+ *ip++ = ix++;
+ if(ix == upd->ints[I_NXPASS]) ix = 0;
+ }
+ }
+
+ if((0 >= upd->int_a[IA_END_IX].size) &&
+ (0 < upd->int_a[IA_END_DY].size) ) {
+ int ix,i,*ip;
+ UPD_MM_DEL_PARAM(udev->memory, upd->int_a[IA_END_IX]);
+ UPD_MM_GET_ARRAY(udev->memory, ip,upd->int_a[IA_END_DY].size);
+ upd->int_a[IA_END_IX].data = ip;
+ upd->int_a[IA_END_IX].size = upd->int_a[IA_END_DY].size;
+
+ for(i = 0, ix = 0; i < upd->int_a[IA_END_IX].size; ++i) {
+ *ip++ = ix++;
+ if(ix == upd->ints[I_NXPASS]) ix = 0;
+ }
+ }
+ }
+
+ if(upd->ints[I_NPASS] > upd->int_a[IA_STD_DY].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "upd_open_writer: Only %d instead of %d normal Feeds\n",
+ (int) upd->int_a[IA_STD_DY].size,upd->ints[I_NPASS]);
+#endif
+ success = false;
+
+ } else if(upd->int_a[IA_STD_IX].size < upd->int_a[IA_STD_DY].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "upd_open_writer: Only %d instead of %d normal Xstarts\n",
+ (int) upd->int_a[IA_STD_IX].size,
+ (int) upd->int_a[IA_STD_DY].size);
+#endif
+ success = false;
+ }
+
+/** The sum of Values in STD_DY should equal NYPASS * PINS2WRITE (diagnostic) */
+
+#if UPD_MESSAGES & UPD_M_WARNING
+ if(success) {
+ int i,sum = 0;
+ for(i = 0; upd->ints[I_NPASS] > i; ++i)
+ sum += upd->int_a[IA_STD_DY].data[i];
+ if((upd->ints[I_NYPASS]*upd->ints[I_PINS2WRITE]) != sum)
+ errprintf(udev->memory,
+ "upd_open_writer: Sum of normal Feeds is %d rather than %d\n",
+ sum,upd->ints[I_NYPASS]*upd->ints[I_PINS2WRITE]);
+ }
+#endif
+
+ if(upd->int_a[IA_BEG_IX].size < upd->int_a[IA_BEG_DY].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "upd_open_writer: Only %d instead of %d initial Xstarts\n",
+ (int) upd->int_a[IA_BEG_IX].size,
+ (int) upd->int_a[IA_BEG_DY].size);
+#endif
+ success = false;
+ }
+
+ if(upd->int_a[IA_BEGBOT].size < upd->int_a[IA_BEG_DY].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "upd_open_writer: Only %d instead of %d initial Pins\n",
+ (int) upd->int_a[IA_BEGBOT].size,
+ (int) upd->int_a[IA_BEG_DY].size);
+#endif
+ success = false;
+
+ } else {
+
+ int i;
+ for(i = 0; i < upd->int_a[IA_BEG_DY].size; ++i)
+ if((upd->int_a[IA_BEGBOT].data[i] > upd->ints[I_PINS2WRITE]) ||
+ (upd->int_a[IA_BEGBOT].data[i] < 0 ) ) break;
+
+ if(i < upd->int_a[IA_BEG_DY].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "upd_open_writer: Only %d is invalid initial Pins\n",
+ upd->int_a[IA_BEGBOT].data[i]);
+#endif
+ success = false;
+ }
+ }
+
+/** The sum of Values in BEG_DY should equal BEG_Y */
+
+#if UPD_MESSAGES & UPD_M_WARNING
+ if(success) {
+ int i,sum = 0;
+ for(i = 0; upd->int_a[IA_BEG_DY].size > i; ++i)
+ sum += upd->int_a[IA_BEG_DY].data[i];
+ if(upd->ints[I_BEG_Y] != sum)
+ errprintf(udev->memory,
+ "upd_open_writer: Sum of initial Feeds is %d rather than %d\n",
+ sum,upd->ints[I_BEG_Y]);
+ }
+#endif
+
+ if(upd->int_a[IA_END_IX].size < upd->int_a[IA_END_DY].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "upd_open_writer: Only %d instead of %d final Xstarts\n",
+ (int) upd->int_a[IA_END_IX].size,
+ (int) upd->int_a[IA_END_DY].size);
+#endif
+ success = false;
+ }
+
+ if(upd->int_a[IA_ENDTOP].size < upd->int_a[IA_END_DY].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "upd_open_writer: Only %d instead of %d Final Pins\n",
+ (int) upd->int_a[IA_ENDTOP].size,
+ (int) upd->int_a[IA_END_DY].size);
+#endif
+ success = false;
+
+ } else {
+
+ int i;
+ for(i = 0; i < upd->int_a[IA_END_DY].size; ++i)
+ if((upd->int_a[IA_ENDTOP].data[i] > upd->ints[I_PINS2WRITE]) ||
+ (upd->int_a[IA_ENDTOP].data[i] < 0 ) ) break;
+
+ if(i < upd->int_a[IA_END_DY].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "upd_open_writer: Only %d is invalid initial Pins\n",
+ upd->int_a[IA_ENDTOP].data[i]);
+#endif
+ success = false;
+ }
+ }
+
+/** SA_SETCOMP must be valid, if present */
+ if((0 < upd->string_a[SA_SETCOMP].size) &&
+ (upd->ocomp > upd->string_a[SA_SETCOMP].size)) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "upd_open_writer: Only %d SETCOMP-Commands (%d required)\n",
+ (int) upd->string_a[SA_SETCOMP].size,upd->ocomp);
+#endif
+ success = false;
+ }
+
+/** Determine required number of scan-Buffers */
+
+ if(success) { /* Compute nscnbuf */
+ int32_t want,use;
+
+ want = upd->ints[I_NYPASS];
+ want *= upd->ints[I_PINS2WRITE];
+
+ if(upd->ints[I_NSCNBUF] > want) want = upd->ints[I_NSCNBUF];
+
+ if(1 > want) want = 1;
+
+ for(use = 1; 0 < use; use <<= 1) if(use > want) break;
+
+ if(use <= INT_MAX) upd->nscnbuf = upd->ints[I_NSCNBUF] = use;
+ else success = false;
+
+ } /* Compute nscnbuf */
+
+/** Determine number of words in scan-buffers */
+
+ if(success) { /* Compute pwidth, scnmsk, nbytes, pheight */
+
+ if(0 < upd->ints[I_PWIDTH]) upd->pwidth = upd->ints[I_PWIDTH];
+ else upd->pwidth = upd->gswidth;
+
+ upd->nbytes = (upd->pwidth+CHAR_BIT*sizeof(upd->scnbuf[0]->bytes[0]) - 1)
+ / (CHAR_BIT*sizeof(upd->scnbuf[0]->bytes[0]));
+
+ upd->scnmsk = upd->nscnbuf - 1;
+
+ if(0 < upd->ints[I_PHEIGHT]) upd->pheight = upd->ints[I_PHEIGHT];
+ else upd->pheight = upd->gsheight;
+
+ } /* Compute pwidth, scnmsk, nbytes */
+
+/** Call the writer-specific open-function */
+
+ if(success) { /* Determine sizes */
+ switch(upd->choice[C_FORMAT]) {
+ case FMT_RAS:
+ if(0 > upd_open_rascomp(udev)) success = false;
+ break;
+ case FMT_EPSON:
+ if(0 > upd_open_wrtescp(udev)) success = false;
+ break;
+ case FMT_ESCP2Y:
+ case FMT_ESCP2XY:
+ case FMT_ESCNMY: /* (GR) */
+ if(0 > upd_open_wrtescp2(udev)) success = false;
+ break;
+ case FMT_RTL:
+ if(0 > upd_open_wrtrtl(udev)) success = false;
+ break;
+ case FMT_CANON: /* (hr) */
+ if(0 > upd_open_wrtcanon(udev)) success = false;
+ break;
+ default:
+ success = false;
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,"upd_open_writer: Unknown writer-type %d\n",
+ upd->choice[C_FORMAT]);
+#endif
+ break;
+ }
+ } /* Determine sizes*/
+
+/** Allocate the Outputbuffer */
+ if(success && (0 < upd->noutbuf)) { /* Allocate outbuf */
+ upd->outbuf = gs_malloc(udev->memory, upd->noutbuf,sizeof(upd->outbuf[0]),"upd/outbuf");
+ if(!upd->outbuf) success = false;
+ } /* Allocate outbuf */
+
+/** Allocate the desired scan-buffer-pointers */
+ if(success) {
+ upd->scnbuf = gs_malloc(udev->memory, upd->nscnbuf,sizeof(upd->scnbuf[0]),"upd/scnbuf");
+ if(NULL == upd->scnbuf) {
+ success = false;
+ } else {
+ int ibuf;
+ for(ibuf = 0; ibuf < upd->nscnbuf; ++ibuf) {
+ if(success) upd->scnbuf[ibuf] =
+ gs_malloc(udev->memory, upd->ocomp,sizeof(upd->scnbuf[0][0]),"upd/scnbuf[]");
+ else upd->scnbuf[ibuf] = NULL;
+
+ if(!upd->scnbuf[ibuf]) {
+ success = false;
+ } else {
+ int icomp;
+ for(icomp = 0; icomp < upd->ocomp; ++icomp) {
+ if(success) upd->scnbuf[ibuf][icomp].bytes =
+ gs_malloc(udev->memory, upd->nbytes,sizeof(upd->scnbuf[0][0].bytes[0]),
+ "upd/bytes");
+ else upd->scnbuf[ibuf][icomp].bytes = NULL;
+ if(!upd->scnbuf[ibuf][icomp].bytes) success = false;
+
+ if(0 < upd->nlimits) {
+
+ upd->scnbuf[ibuf][icomp].xbegin = gs_malloc(udev->memory, upd->nlimits,
+ sizeof(upd->scnbuf[0][0].xbegin[0]),"upd/xbegin");
+ if(!upd->scnbuf[ibuf][icomp].xbegin) success = false;
+
+ upd->scnbuf[ibuf][icomp].xend = gs_malloc(udev->memory, upd->nlimits,
+ sizeof(upd->scnbuf[0][0].xend[0]),"upd/xend");
+ if(!upd->scnbuf[ibuf][icomp].xbegin) success = false;
+
+ } else {
+
+ upd->scnbuf[ibuf][icomp].xbegin = NULL;
+ upd->scnbuf[ibuf][icomp].xend = NULL;
+
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(success) upd->flags |= B_FORMAT;
+ else upd_close_writer(udev);
+
+ return success ? 1 : -1;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_close_writer: Deinitialize rendering */
+/* ------------------------------------------------------------------- */
+
+static void
+upd_close_writer(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+
+ if(upd) {
+ int ibuf,icomp;
+
+ if((0 < upd->noutbuf) && upd->outbuf)
+ gs_free(udev->memory, upd->outbuf,upd->noutbuf,sizeof(upd->outbuf[0]),"upd/outbuf");
+ upd->noutbuf = 0;
+ upd->outbuf = NULL;
+
+ if((0 < upd->nscnbuf) && upd->scnbuf) {
+ for(ibuf = 0; upd->nscnbuf > ibuf; ++ibuf) {
+
+ if(!upd->scnbuf[ibuf]) continue;
+
+ for(icomp = 0; icomp < upd->ocomp; ++icomp) {
+
+ if((0 < upd->nbytes) && upd->scnbuf[ibuf][icomp].bytes)
+ gs_free(udev->memory, upd->scnbuf[ibuf][icomp].bytes,upd->nbytes,
+ sizeof(upd->scnbuf[ibuf][icomp].words[0]),"upd/bytes");
+ upd->scnbuf[ibuf][icomp].bytes = NULL;
+
+ if((0 < upd->nlimits) && upd->scnbuf[ibuf][icomp].xbegin)
+ gs_free(udev->memory, upd->scnbuf[ibuf][icomp].xbegin,upd->nlimits,
+ sizeof(upd->scnbuf[ibuf][icomp].xbegin[0]),"upd/xbegin");
+ upd->scnbuf[ibuf][icomp].xbegin = NULL;
+
+ if((0 < upd->nlimits) && upd->scnbuf[ibuf][icomp].xend)
+ gs_free(udev->memory, upd->scnbuf[ibuf][icomp].xend,upd->nlimits,
+ sizeof(upd->scnbuf[ibuf][icomp].xend[0]),"upd/xend");
+ upd->scnbuf[ibuf][icomp].xend = NULL;
+ }
+
+ if(icomp)
+ gs_free(udev->memory, upd->scnbuf[ibuf],upd->ocomp,sizeof(upd->scnbuf[0][0]),
+ "upd/scnbuf[]");
+ upd->scnbuf[ibuf] = NULL;
+
+ }
+ gs_free(udev->memory, upd->scnbuf,upd->nscnbuf,sizeof(upd->scnbuf[0]),"upd/scnbuf");
+ }
+
+ upd->flags &= ~B_FORMAT;
+ }
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_limits: Establish passwise limits, after rendering */
+/* ------------------------------------------------------------------- */
+
+static void
+upd_limits(upd_p upd, bool check)
+{
+ updscan_p scans = upd->scnbuf[upd->yscnbuf & upd->scnmsk], scan;
+ int xs,x,xe,icomp,pass;
+ byte *bytes,bit;
+
+ for(icomp = 0; icomp < upd->ocomp; ++icomp) {
+ scan = scans + icomp;
+ for(pass = 0; pass < upd->nlimits; ++pass) {
+ scan->xbegin[pass] = upd->pwidth;
+ scan->xend[ pass] = -1;
+ }
+ }
+
+ if(check) { /* Really check */
+ for(icomp = 0; icomp < upd->ocomp; ++icomp) { /* Check Components */
+ scan = scans + icomp;
+ bytes = scan->bytes;
+
+ for(xs = 0; xs < upd->nbytes && !bytes[xs]; ++xs);
+
+ if(xs < upd->nbytes) { /* Has Data */
+ for(xe = upd->nbytes; xs < xe && !bytes[xe-1]; --xe);
+
+ for(pass = 0; pass < upd->nlimits; ++pass) { /* limit (pass) loop */
+
+ x = ((xs<<3)/upd->nlimits)*upd->nlimits + pass;
+ while((x >> 3) < xs) x += upd->nlimits;
+
+ bit = 0x80 >> (x & 7);
+ while(x < scan->xbegin[pass]) {
+ if(bytes[x>>3] & bit) scan->xbegin[pass] = x;
+ x += upd->nlimits;
+ bit = 0x80 >> (x & 7);
+ }
+
+ x = (((xe<<3)|7)/upd->nlimits)*upd->nlimits + pass;
+
+ while((x >> 3) < xe) x += upd->nlimits;
+ while((x >> 3) > xe) x -= upd->nlimits;
+
+ bit = 0x80 >> (xs & 7);
+ while(x > scan->xend[pass]) {
+ if(bytes[x>>3] & bit) scan->xend[pass] = x;
+ x -= upd->nlimits;
+ bit = 0x80 >> (x & 7);
+ }
+
+ } /* limit (pass) loop */
+
+ } /* Has Data */
+
+ } /* Check Components */
+
+ } /* Really check */
+
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_open_rascomp: ncomp * 1Bit Raster-Writer */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_open_rascomp(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ int32_t noutbuf;
+ int error = 0;
+
+ noutbuf = upd->pwidth;
+
+ if(1 < upd->ncomp) noutbuf *= 8; /* ??? upd->ocomp */
+
+ noutbuf = ((noutbuf+15)>>4)<<1;
+
+ if(INT_MAX >= noutbuf) {
+ upd->noutbuf = noutbuf;
+ upd->start_writer = upd_start_rascomp;
+ upd->writer = upd_rascomp;
+ } else {
+ error = -1;
+ }
+
+ return error;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_start_rascomp: write appropiate raster-header */
+/* ------------------------------------------------------------------- */
+#if arch_is_big_endian
+#define put32(I32,Out) \
+ fwrite(&I32,1,4,Out)
+#else
+#define put32(I32,Out) \
+ putc(((I32)>>24)&255,Out),\
+ putc(((I32)>>16)&255,Out),\
+ putc(((I32)>> 8)&255,Out),\
+ putc( (I32) &255,Out)
+#endif
+
+static int
+upd_start_rascomp(upd_p upd, FILE *out) {
+
+/** if no begin-sequence externally set */
+ if(0 == upd->strings[S_BEGIN].size) {
+ int32_t val;
+
+/** ras_magic */
+ val = 0x59a66a95;
+ put32(val,out);
+
+/** ras_width */
+ val = upd->pwidth;
+ put32(val,out);
+
+/** ras_height */
+ val = upd->pheight;
+ put32(val,out);
+
+/** ras_depth */
+ if(1 < upd->ncomp) val = 8; /* ??? upd->ocomp */
+ else val = 1;
+ put32(val,out);
+
+/** ras_length */
+ val *= upd->pwidth;
+ val = ((val+15)>>4)<<1;
+ val *= upd->pheight;
+ put32(val,out);
+
+/** ras_type */
+ val = 1;
+ put32(val,out);
+
+/** ras_maptype */
+ val = 1;
+ put32(val,out);
+
+/** ras_maplength */
+ val = 3 * (1 << upd->ncomp); /* ??? upd->ocomp */
+ put32(val,out);
+
+/** R,G,B-Map */
+ if(1 == upd->ncomp) { /* ??? upd->ocomp */
+ const updcomp_p comp = upd->valptr[0];
+
+ if(upd->cmap[comp->cmap].rise) {
+ putc((char) 0x00,out); putc((char) 0xff,out);
+ putc((char) 0x00,out); putc((char) 0xff,out);
+ putc((char) 0x00,out); putc((char) 0xff,out);
+ } else {
+ putc((char) 0xff,out); putc((char) 0x00,out);
+ putc((char) 0xff,out); putc((char) 0x00,out);
+ putc((char) 0xff,out); putc((char) 0x00,out);
+ }
+
+ } else if(3 == upd->ncomp) { /* ??? upd->ocomp */
+ int rgb;
+
+ for( rgb = 0; rgb < 3; ++rgb) {
+ int entry;
+ for(entry = 0; entry < 8; ++entry) {
+ byte xval = upd->cmap[rgb].rise ? 0x00 : 0xff;
+ if(entry & (1<<upd->cmap[rgb].comp)) xval ^= 0xff;
+ putc(xval,out);
+ }
+ }
+ } else { /* we have 4 components */
+ int rgb;
+
+ for(rgb = 16; 0 <= rgb; rgb -= 8) {
+ int entry;
+ for(entry = 0; entry < 16; ++entry) {
+ uint32_t rgbval = 0;
+
+ if(entry & (1<<upd->cmap[0].comp)) {
+
+ rgbval = 0xffffff;
+
+ } else {
+
+ if(entry & (1<<upd->cmap[1].comp)) rgbval |= 0xff0000;
+ if(entry & (1<<upd->cmap[2].comp)) rgbval |= 0x00ff00;
+ if(entry & (1<<upd->cmap[3].comp)) rgbval |= 0x0000ff;
+ }
+
+ if(!upd->cmap[1].rise) rgbval ^= 0xff0000;
+ if(!upd->cmap[2].rise) rgbval ^= 0x00ff00;
+ if(!upd->cmap[3].rise) rgbval ^= 0x0000ff;
+
+ if(!(upd->choice[C_MAPPER] == MAP_RGBW)) rgbval ^= 0xffffff;
+
+ putc((rgbval>>rgb)&255,out);
+ }
+ }
+ }
+ }
+ memset(upd->outbuf,0,upd->noutbuf);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_rascomp: assemble & write a scanline */
+/* ------------------------------------------------------------------- */
+static int
+upd_rascomp(upd_p upd, FILE *out) {
+ updscan_p scan = upd->scnbuf[upd->yscan & upd->scnmsk];
+ uint bits = upd->pwidth;
+
+ if(1 == upd->ncomp) { /* ??? upd->ocomp */
+ uint nbytes;
+
+ nbytes = (bits+7)>>3;
+ memcpy(upd->outbuf,scan->bytes,nbytes);
+ if((bits &= 7)) upd->outbuf[nbytes-1] &= ((byte) 0xff) << (8-bits);
+
+ } else {
+
+ byte *buf = upd->outbuf, bit = 0x80;
+ int ibyte = 0;
+
+ while(0 < bits--) {
+ byte val = 0;
+ switch(upd->ncomp) { /* ??? upd->ocomp */
+ case 4: if(scan[3].bytes[ibyte] & bit) val |= 8;
+ case 3: if(scan[2].bytes[ibyte] & bit) val |= 4;
+ if(scan[1].bytes[ibyte] & bit) val |= 2;
+ case 1: if(scan[0].bytes[ibyte] & bit) val |= 1;
+ }
+ *buf++ = val;
+ if(!(bit >>= 1)) {
+ bit = 0x80;
+ ibyte += 1;
+ }
+ }
+ }
+
+ fwrite(upd->outbuf,1,upd->noutbuf,out);
+ upd->yscan += 1;
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_open_wrtescp: ESC/P Writer intended for ESC * m commands */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_open_wrtescp(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ int error = 0;
+
+/** Adjust the PageLength, If Requested */
+ if((B_PAGELENGTH & upd->flags) &&
+ (0 < upd->strings[S_BEGIN].size)) { /* BOP-Checker */
+ int i,state = 0,value = 0;
+ byte *bp = (byte *) upd_cast(upd->strings[S_BEGIN].data);
+ for(i = 0; i < upd->strings[S_BEGIN].size; ++i) {
+ switch(state) {
+ case 0:
+ if(0x1b == bp[i]) state = 1;
+ break;
+ case 1:
+ if('C' == bp[i]) state = 2;
+ else state = 0;
+ break;
+ case 2:
+ if(bp[i]) {
+ value = (int)(0.5 + udev->height * (float) bp[i]
+ / udev->y_pixels_per_inch);
+ if( 0 >= value) bp[i] = 1;
+ else if(128 > value) bp[i] = value;
+ else bp[i] = 127;
+ state = 0;
+ } else {
+ state = 3;
+ }
+ break;
+ case 3:
+ value = (int)(0.5 + udev->height / udev->y_pixels_per_inch);
+ if( 0 >= value) bp[i] = 1;
+ else if( 22 > value) bp[i] = value;
+ else bp[i] = 22;
+ state = 0;
+ break;
+ }
+ }
+ } /* BOP-Checker */
+
+/** Either SETLF or YMOVE must be set */
+ if((0 == upd->strings[S_SETLF].size) &&
+ (0 == upd->strings[S_YMOVE].size) ) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "ESC/P-Open: Either SETLF- or YMOVE-Command must be present\n");
+#endif
+ error = -1;
+ }
+
+/** X-Positioning must be set too */
+ if(((1 < upd->ints[I_XSTEP] ) &&
+ (0 == upd->strings[S_XSTEP].size) ) ||
+ ((1 < upd->ints[I_NXPASS] ) &&
+ (0 == upd->strings[S_XMOVE].size) &&
+ (0 == upd->strings[S_XSTEP].size) ) ) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "ESC/P-Open: Missing XSTEP- and/or XMOVE-Command\n");
+#endif
+ error = -1;
+ }
+
+/** SA_WRITECOMP must be valid */
+ if(upd->ncomp > upd->string_a[SA_WRITECOMP].size) { /* ??? upd->ocomp */
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "ESC/P-Open: WRITECOMP-Commands must be given\n");
+#endif
+ error = -1;
+ }
+
+/**
+If all this is correct, it's time to coumput the size of the output-buffer.
+It must hold:
+ 1. Y-Positioning
+ 2. X-Positioning
+ 3. Component-Selection
+ 4. The Raster-Command
+ 5. The Data
+*/
+ if(0 <= error) {
+ int32_t i,noutbuf,need;
+
+ if(0 < upd->strings[S_YMOVE].size) {
+ noutbuf = upd->strings[S_YMOVE].size + 2;
+ } else {
+ int nmax = upd->pheight;
+ if( 1 < upd->ints[I_YSTEP]) nmax /= upd->ints[I_YSTEP];
+ else if(-1 > upd->ints[I_YSTEP]) nmax *= -upd->ints[I_YSTEP];
+ noutbuf = 2 * upd->strings[S_SETLF].size + 2;
+ noutbuf += nmax/255 + 1;
+ }
+
+ if(1 < upd->ints[I_YSTEP])
+ noutbuf += (upd->ints[I_YSTEP]-1) * upd->strings[S_YSTEP].size;
+
+ noutbuf += upd->strings[S_XMOVE].size + 2;
+
+ if(1 < upd->ints[I_XSTEP])
+ noutbuf += (upd->ints[I_XSTEP]-1) * upd->strings[S_XSTEP].size;
+
+ if(0 < upd->string_a[SA_SETCOMP].size) {
+ need = 0;
+ for(i = 0; i < upd->ocomp; ++i)
+ if(need < upd->string_a[SA_SETCOMP].data[i].size)
+ need = upd->string_a[SA_SETCOMP].data[i].size;
+ noutbuf += need;
+ }
+
+ need = 0;
+ for(i = 0; i < upd->ocomp; ++i)
+ if(need < upd->string_a[SA_WRITECOMP].data[i].size)
+ need = upd->string_a[SA_WRITECOMP].data[i].size;
+ noutbuf += need + 2;
+
+ noutbuf += ((upd->ints[I_PINS2WRITE] + 7) / 8)
+ * ((upd->pwidth + upd->ints[I_NXPASS] - 1)/upd->ints[I_NXPASS]);
+
+ if((0 < noutbuf) && (noutbuf <= INT_MAX)) {
+ upd->noutbuf = noutbuf;
+ upd->writer = upd_wrtescp;
+ upd->nlimits = upd->ints[I_NXPASS];
+ error = 1;
+ } else {
+ error = -1;
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "ESC/P-Open: %ld is unreasonable size of Outputbuffer\n",
+ (long) noutbuf);
+#endif
+ }
+ }
+
+ return error;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_wrtescp: Write a pass */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_wrtescp(upd_p upd, FILE *out)
+{
+ int pinbot,pin,pintop,xbegin,x,xend,icomp,ybegin,yend,y,ioutbuf,n,ixpass;
+ byte *obytes,bit;
+ updscan_p scan;
+
+/** Determine the number of pins to write */
+
+ if(upd->yscan < upd->ints[I_BEG_Y]) {
+ ixpass = upd->int_a[IA_BEG_IX].data[upd->ipass];
+ pintop = 0;
+ pinbot = upd->int_a[IA_BEGBOT].data[upd->ipass];
+ } else if(upd->yscan >= upd->ints[I_END_Y]) {
+ ixpass = upd->int_a[IA_END_IX].data[upd->ipass];
+ pinbot = upd->ints[I_PINS2WRITE];
+ pintop = pinbot - upd->int_a[IA_ENDTOP].data[upd->ipass];
+ } else {
+ ixpass = upd->int_a[IA_STD_IX].data[upd->ipass];
+ pintop = 0;
+ pinbot = upd->ints[I_PINS2WRITE];
+ }
+
+ ybegin = pintop * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
+ yend = pinbot * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
+
+/** Determine Width of this scan */
+
+ xbegin = upd->pwidth;
+ xend = -1;
+
+ for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Pin-testloop */
+
+ if(0 > y) continue; /* Inserted Scanlines */
+
+ scan = upd->scnbuf[y & upd->scnmsk];
+
+ for(icomp = 0; icomp < upd->ocomp; ++icomp) { /* Compwise test */
+ if(xbegin > scan[icomp].xbegin[ixpass])
+ xbegin = scan[icomp].xbegin[ixpass];
+ if(xend < scan[icomp].xend[ ixpass])
+ xend = scan[icomp].xend[ ixpass];
+ } /* Compwise test */
+
+ } /* Pin-testloop */
+
+ if(xbegin <= xend) { /* Some data to write */
+
+ ioutbuf = 0;
+
+ if(0 == upd->strings[S_XMOVE].size) xbegin = ixpass;
+
+/*
+ * Adjust the Printers Y-Position
+ */
+ if(upd->yscan != upd->yprinter) { /* Adjust Y-Position */
+ if(B_YABS & upd->flags) y = upd->yscan + upd->ints[I_YOFS];
+ else y = upd->yscan - upd->yprinter;
+
+ if( 1 < upd->ints[I_YSTEP]) {
+ n = y / upd->ints[I_YSTEP]; /* Major-Steps */
+ y -= n * upd->ints[I_YSTEP]; /* Minor-Steps */
+ } else if(-1 > upd->ints[I_YSTEP]) {
+ n = y * -upd->ints[I_YSTEP]; /* May this work? */
+ y = 0;
+ } else {
+ n = y;
+ y = 0;
+ }
+
+ if(n) { /* Coarse Positioning */
+ if(0 < upd->strings[S_YMOVE].size) {
+
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_YMOVE].data,
+ upd->strings[S_YMOVE].size);
+ ioutbuf += upd->strings[S_YMOVE].size;
+
+ upd->outbuf[ioutbuf++] = n & 0xff;
+ upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
+
+ } else {
+
+ while(n) {
+ int n2do = n > 255 ? 255 : n;
+ if(upd->lf != n2do) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_SETLF].data,
+ upd->strings[S_SETLF].size);
+ ioutbuf += upd->strings[S_SETLF].size;
+ upd->outbuf[ioutbuf++] = n2do;
+ upd->lf = n2do;
+ }
+ upd->outbuf[ioutbuf++] = '\n';
+ n -= n2do;
+ }
+ }
+ } /* Coarse Positioning */
+
+ if(0 < upd->strings[S_YSTEP].size) {
+ while(y--) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_YSTEP].data,
+ upd->strings[S_YSTEP].size);
+ ioutbuf += upd->strings[S_YSTEP].size;
+ }
+ }
+
+ upd->yprinter = upd->yscan;
+ } /* Adjust Y-Position */
+
+/*
+ * Now write the required components
+ */
+ for(icomp = 0; icomp < upd->ocomp; ++icomp) { /* Component-Print */
+/*
+ * First check, wether this Component needs printing
+ */
+ for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Comp-Test */
+ if(0 > y) continue;
+ scan = upd->scnbuf[y & upd->scnmsk]+icomp;
+ if(0 <= scan->xend[ixpass]) break;
+ } /* Comp-Test */
+ if(y >= yend) continue; /* Component not required */
+/*
+ * Select the Component
+ */
+ if((0 < upd->string_a[SA_SETCOMP].size) &&
+ (upd->icomp != icomp ) ) { /* Selection enabled */
+ upd->icomp = icomp;
+ if(0 < upd->string_a[SA_SETCOMP].data[icomp].size) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->string_a[SA_SETCOMP].data[icomp].data,
+ upd->string_a[SA_SETCOMP].data[icomp].size);
+ ioutbuf += upd->string_a[SA_SETCOMP].data[icomp].size;
+ }
+ } /* Selection enabled */
+/*
+ * Establish the X-Position
+ */
+ if(xbegin != upd->xprinter) {
+
+ if(0 == upd->strings[S_XMOVE].size) {
+
+ upd->outbuf[ioutbuf++] = '\r';
+ upd->xprinter = 0;
+ n = 0;
+ x = ixpass;
+
+ } else {
+
+ if(B_XABS & upd->flags) n = x = xbegin + upd->ints[I_XOFS];
+ else n = x = xbegin - upd->xprinter;
+
+ if( 1 < upd->ints[I_XSTEP]) {
+ if(0 > n) {
+ n -= upd->ints[I_XSTEP];
+ x -= n;
+ }
+ if(n) n /= upd->ints[I_XSTEP]; /* Major-Steps */
+ if(x) x %= upd->ints[I_XSTEP]; /* Minor-Steps */
+
+ } else if(-1 > upd->ints[I_XSTEP]) {
+ n *= -upd->ints[I_XSTEP]; /* May this work? */
+ x = 0;
+ }
+
+ if(n) { /* Adjust X-Position */
+
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_XMOVE].data,
+ upd->strings[S_XMOVE].size);
+ ioutbuf += upd->strings[S_XMOVE].size;
+
+ upd->outbuf[ioutbuf++] = n & 0xff;
+ upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
+
+ } /* Adjust X-Position */
+
+ }
+
+ if(x && 0 < upd->strings[S_XSTEP].size) { /* Fine-Adjust X */
+ while(x--) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_XSTEP].data,
+ upd->strings[S_XSTEP].size);
+ ioutbuf += upd->strings[S_XSTEP].size;
+ }
+ } /* Fine-Adjust X */
+ }
+ upd->xprinter = xend+1;
+/*
+ * Send the Write-Command
+ */
+ if(0 < upd->string_a[SA_WRITECOMP].data[icomp].size) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->string_a[SA_WRITECOMP].data[icomp].data,
+ upd->string_a[SA_WRITECOMP].data[icomp].size);
+ ioutbuf += upd->string_a[SA_WRITECOMP].data[icomp].size;
+ }
+ n = (xend - xbegin) / upd->ints[I_NXPASS] + 1;;
+ upd->outbuf[ioutbuf++] = n & 255;
+ upd->outbuf[ioutbuf++] = (n>>8) & 255;
+/*
+ * Clear the data-Part
+ */
+ obytes = upd->outbuf+ioutbuf;
+ n *= (upd->ints[I_PINS2WRITE]+7)>>3;
+ memset(obytes,0,n);
+ ioutbuf += n;
+/*
+ * Set the Pixels
+ */
+ for(x = xbegin; x <= xend; x += upd->ints[I_NXPASS]) {
+
+ bit = 0x80 >> (pintop & 7);
+ obytes += pintop>>3;
+
+ for(pin = pintop, y = ybegin; pin < pinbot;
+ pin++, y += upd->ints[I_NYPASS]) {
+ if(0 <= y) {
+ scan = upd->scnbuf[y & upd->scnmsk]+icomp;
+ if(scan->bytes[x>>3] & (0x80 >> (x & 7))) *obytes |= bit;
+ }
+ if(!(bit >>= 1)) { obytes++; bit = 0x80; }
+ }
+
+ obytes += (upd->ints[I_PINS2WRITE]-pinbot+7)>>3;
+ }
+/*
+ * Send this Component to the Printer
+ */
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ ioutbuf = 0;
+ } /* Component-Print */
+ } /* Some data to write */
+
+/** Advance counters in upd, change modi */
+
+ if(upd->yscan < upd->ints[I_BEG_Y]) {
+ upd->yscan += upd->int_a[IA_BEG_DY].data[upd->ipass++];
+ if( upd->ints[I_BEG_Y] <= upd->yscan) upd->ipass = 0;
+ else if(upd->int_a[IA_BEG_DY].size <= upd->ipass) upd->ipass = 0;
+ } else if(upd->yscan >= upd->ints[I_END_Y]) {
+ upd->yscan += upd->int_a[IA_END_DY].data[upd->ipass++];
+ if(upd->int_a[IA_END_DY].size <= upd->ipass) upd->ipass = 0;
+ } else {
+ upd->yscan += upd->int_a[IA_STD_DY].data[upd->ipass++];
+ if(upd->int_a[IA_STD_DY].size <= upd->ipass) upd->ipass = 0;
+ if(upd->yscan >= upd->ints[I_END_Y]) upd->ipass = 0;
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_open_wrtescp2: ESC/P2 Writer intended for ESC . 1 commands */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_open_wrtescp2(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ int error = 0;
+ float pixels_per_inch = 360.0;
+
+/** Analyze (and optionally adjust) the BOP-Sequence */
+ if(0 < upd->strings[S_BEGIN].size) { /* BOP-Checker */
+ int i,state = 0,value = 0;
+ byte *bp = (byte *) upd_cast(upd->strings[S_BEGIN].data);
+ for(i = 0; i < upd->strings[S_BEGIN].size; ++i) {
+ switch(state) {
+ case 0:
+ if(0x1b == bp[i]) state = 1;
+ break;
+ case 1:
+ if('(' == bp[i]) state = 2;
+ else state = 0;
+ break;
+ case 2:
+ switch(bp[i]) {
+ case 'U': state = 3; break; /* Printer-Resolution */
+ case 'C': state = 6; break; /* Page-Length */
+ case 'c': state = 10; break; /* Top/Bottom Margin */
+ default: state = 0; break;
+ }
+ break;
+ case 3:
+ if(1 == bp[i]) state = 4;
+ else state = 0;
+ break;
+ case 4:
+ if(0 == bp[i]) state = 5;
+ else state = 0;
+ break;
+ case 5:
+ pixels_per_inch = 3600.0 / (float) bp[i];
+ state = 0;
+ break;
+ case 6:
+ if(2 == bp[i]) state = 7;
+ else state = 0;
+ break;
+ case 7:
+ if(0 == bp[i]) state = 8;
+ else state = 0;
+ break;
+ case 8:
+ if(B_PAGELENGTH & upd->flags) {
+ value = (int)(0.5 + udev->height
+ * pixels_per_inch / udev->y_pixels_per_inch);
+ bp[i] = value & 0xff;
+ }
+ state = 9;
+ break;
+ case 9:
+ if(B_PAGELENGTH & upd->flags) {
+ bp[i] = (value>>8) & 0xff;
+ }
+ state = 0;
+ break;
+ case 10:
+ if(4 == bp[i]) state = 11;
+ else state = 0;
+ break;
+ case 11:
+ if(0 == bp[i]) state = 12;
+ else state = 0;
+ break;
+ case 12:
+ if(B_TOPMARGIN & upd->flags) {
+ value = (int)(dev_t_margin(udev) * pixels_per_inch);
+ bp[i] = value & 0xff;
+ }
+ state = 13;
+ break;
+ case 13:
+ if(B_TOPMARGIN & upd->flags) {
+ bp[i] = (value>>8) & 0xff;
+ }
+ state = 14;
+ break;
+ case 14:
+ if(B_BOTTOMMARGIN & upd->flags) {
+ value = (int)(0.5 + udev->height
+ * pixels_per_inch / udev->y_pixels_per_inch
+ - dev_b_margin(udev) * pixels_per_inch);
+ bp[i] = value & 0xff;
+ }
+ state = 15;
+ break;
+ case 15:
+ if(B_BOTTOMMARGIN & upd->flags) {
+ bp[i] = (value>>8) & 0xff;
+ }
+ state = 0;
+ break;
+ }
+ }
+ } /* BOP-Checker */
+
+/** Create Y-Move-Command, if not given */
+ if(0 == upd->strings[S_YMOVE].size) {
+ byte *bp;
+ UPD_MM_DEL_PARAM(udev->memory, upd->strings[S_YMOVE]);
+ UPD_MM_GET_ARRAY(udev->memory, bp,5);
+ upd->strings[S_YMOVE].data = bp;
+ upd->strings[S_YMOVE].size = 5;
+ *bp++ = 0x1b; /* ESC */
+ *bp++ = '(';
+ *bp++ = upd->flags & B_YABS ? 'V' : 'v';
+ *bp++ = 2;
+ *bp++ = 0;
+ }
+
+/** X-Positioning must be set too, sometimes */
+ if((1 < upd->ints[I_XSTEP]) && (0 == upd->strings[S_XSTEP].size)) {
+
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "ESC/P2-Open: XSTEP-Command required for XSTEP=%d\n",
+ upd->ints[I_XSTEP]);
+#endif
+ error = -1;
+
+ } else if((1 < upd->ints[I_NXPASS] ) &&
+ (0 == upd->strings[S_XMOVE].size) &&
+ (0 == upd->strings[S_XSTEP].size) ) {
+ byte *bp;
+ int ratio;
+
+ ratio = (int)((udev->y_pixels_per_inch + 0.5) / udev->x_pixels_per_inch);
+
+ if(0 == upd->ints[I_XSTEP]) { /* Adjust scale-factor too! */
+ if(ratio > 1) upd->ints[I_XSTEP] = -ratio;
+ } else { /* Adjust scale-factor too! */
+ ratio = -upd->ints[I_XSTEP];
+ }
+
+ if(2 == upd->ints[I_NXPASS]) { /* Use a relative Step */
+
+ UPD_MM_DEL_PARAM(udev->memory, upd->strings[S_XSTEP]);
+ UPD_MM_GET_ARRAY(udev->memory, bp,4);
+ upd->strings[S_XSTEP].size = 4;
+ upd->strings[S_XSTEP].data = bp;
+ *bp++ = 0x1b;
+ *bp++ = '\\';
+ *bp++ = ratio & 0xff;
+ *bp++ = (ratio>>8) & 0xff;
+
+ } else { /* Use relative or absolute Move */
+
+ UPD_MM_DEL_PARAM(udev->memory, upd->strings[S_XMOVE]);
+ UPD_MM_GET_ARRAY(udev->memory, bp,2);
+ upd->strings[S_XMOVE].size = 2;
+ upd->strings[S_XMOVE].data = bp;
+ *bp++ = 0x1b;
+ *bp++ = upd->flags & B_XABS ? '$' : '\\';
+
+ }
+ }
+
+ /* Check the Nozzle Map parameters and set some defaults */
+ /* Used a switch construct in case FMT_ESCNMXY is added later */
+ switch(upd->choice[C_FORMAT]){
+ case FMT_ESCNMY:
+ /* RowsPerPass */
+ if( 0 == upd->ints[I_ROWS] ){
+ upd->ints[I_ROWS] = 1;
+ }
+ /* PatternRepeat */
+ if( 0 == upd->ints[I_PATRPT] ){
+ upd->ints[I_PATRPT] = 1;
+ }
+ /* RowMask - default is all 1's */
+ if( upd->ints[I_PATRPT] != upd->int_a[IA_ROWMASK].size ) {
+ int i, *bp;
+ UPD_MM_DEL_PARAM(udev->memory, upd->int_a[IA_ROWMASK]);
+ UPD_MM_GET_ARRAY(udev->memory, bp,upd->ints[I_PATRPT]);
+ upd->int_a[IA_ROWMASK].size = upd->ints[I_PATRPT];
+ upd->int_a[IA_ROWMASK].data = bp;
+ for (i = 0 ; i < upd->ints[I_PATRPT] ; i++){
+ *bp++ = 1; /* black */
+ }
+ }
+ /* MaskScanOffset - default is 0-patternRepeat */
+ if( upd->ints[I_PATRPT] != upd->int_a[IA_SCNOFS].size ) {
+ int i, *bp;
+ UPD_MM_DEL_PARAM(udev->memory, upd->int_a[IA_SCNOFS]);
+ UPD_MM_GET_ARRAY(udev->memory, bp,upd->ints[I_PATRPT]);
+ upd->int_a[IA_SCNOFS].size = upd->ints[I_PATRPT];
+ upd->int_a[IA_SCNOFS].data = bp;
+ for (i = 0 ; i < upd->ints[I_PATRPT] ; i++){
+ *bp++ = i;
+ }
+ }
+ break;
+ case FMT_ESCP2Y:
+ case FMT_ESCP2XY:
+ /* Nozzle map parameters are not valid for these formats
+ so ignore them*/
+ break;
+ }
+
+/** If there is neither a writecomp nor a setcomp-command, generate both */
+ if((0 == upd->string_a[SA_WRITECOMP].size) &&
+ (0 == upd->string_a[SA_SETCOMP].size ) ) { /* Default-commands */
+ byte *bp;
+ gs_param_string *ap;
+ int i;
+
+ if(4 == upd->ocomp) { /* Establish Component-Selection */
+ UPD_MM_DEL_APARAM(udev->memory, upd->string_a[SA_SETCOMP]);
+ UPD_MM_GET_ARRAY(udev->memory, ap,4);
+ upd->string_a[SA_SETCOMP].data = ap;
+ upd->string_a[SA_SETCOMP].size = 4;
+ for(i = 0; i < 4; ++i) {
+ UPD_MM_GET_ARRAY(udev->memory, bp,3);
+ ap[i].size = 3;
+ ap[i].data = bp;
+ *bp++ = 0x1b;
+ *bp++ = 'r';
+ switch(((updcomp_p)upd->valptr[i])->cmap) { /* use COMPORDER! */
+ case 0: *bp++ = 0; break; /* Black */
+ case 1: *bp++ = 2; break; /* Cyan */
+ case 2: *bp++ = 1; break; /* Magenta */
+ case 3: *bp++ = 4; break; /* Yellow */
+ } /* use COMPORDER! */
+ }
+ } /* Establish Component-Selection */
+
+ UPD_MM_DEL_APARAM(udev->memory, upd->string_a[SA_WRITECOMP]);
+ UPD_MM_GET_ARRAY(udev->memory, ap,upd->ocomp);
+ upd->string_a[SA_WRITECOMP].data = ap;
+ upd->string_a[SA_WRITECOMP].size = upd->ncomp;
+ for(i = 0; i < upd->ocomp; ++i) {
+ UPD_MM_GET_ARRAY(udev->memory, bp,6);
+ ap[i].size = 6;
+ ap[i].data = bp;
+ *bp++ = 0x1b;
+ *bp++ = '.';
+ *bp++ = 1; /* RLE */
+ switch(upd->choice[C_FORMAT]){
+ case FMT_ESCP2Y:
+ case FMT_ESCP2XY:
+ *bp++ = (byte)(3600.0 * upd->ints[I_NYPASS] /
+ udev->y_pixels_per_inch + 0.5);
+ *bp++ = (byte)(3600.0 * upd->ints[I_NXPASS] /
+ udev->x_pixels_per_inch + 0.5);
+ *bp++ = upd->ints[I_PINS2WRITE];
+ break;
+ case FMT_ESCNMY:
+ /*
+ *bp++ = 3600.0 / udev->y_pixels_per_inch + 0.5;
+ *bp++ = 3600.0 / udev->x_pixels_per_inch + 0.5;
+ */
+ *bp++ = 10; /* needs to always be this for esc300 */
+ *bp++ = 10;
+ *bp++ = upd->ints[I_ROWS];
+ break;
+ }
+ }
+ } /* Default-commands */
+
+/** SA_WRITECOMP must be valid */
+ if(upd->ocomp > upd->string_a[SA_WRITECOMP].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "ESC/P2-Open: WRITECOMP-Commands must be given\n");
+#endif
+ error = -1;
+ }
+
+/** Check Validity of X-Pass */
+ switch(upd->choice[C_FORMAT]) {
+ case FMT_ESCP2Y:
+ if(1 < upd->ints[I_NXPASS]) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "ESC/P2-Open: FMT_ESCP2Y cannot handle multiple X-Passes\n");
+#endif
+ error = -1;
+ } else {
+ upd->writer = upd_wrtescp2;
+ }
+ break;
+ case FMT_ESCP2XY:
+ upd->writer = upd_wrtescp2x;
+ upd->nlimits = upd->ints[I_NXPASS];
+#if UPD_MESSAGES & UPD_M_WARNING
+ if(1 == upd->ints[I_NXPASS])
+ errprintf(udev->memory,
+ "ESC/P2-Open: FMT_ESCP2XY should not be used with 1X-Pass\n");
+#endif
+ break;
+ case FMT_ESCNMY:
+ if(1 < upd->ints[I_NXPASS]) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "ESC/P2-Open: FMT_ESCNMY cannot handle multiple X-Passes\n");
+#endif
+ error = -1;
+ } else {
+ upd->writer = upd_wrtescnm;
+ }
+ break;
+ default:
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "ESC/P2-Open: %d is not a ESC/P2-Format\n",
+ upd->choice[C_FORMAT]);
+#endif
+ error = - 1;
+ break;
+ }
+
+/**
+If all this is correct, it's time to compute the size of the output-buffer.
+It must hold:
+ 1. Y-Positioning
+ 2. X-Positioning
+ 3. Component-Selection
+ 4. The Raster-Command
+ 5. The Data
+*/
+ if(0 <= error) {
+ int32_t i,noutbuf,need;
+ /* Y-Positioning */
+ if(0 < upd->strings[S_YMOVE].size) {
+ noutbuf = upd->strings[S_YMOVE].size + 2;
+ } else {
+ int nmax = upd->pheight;
+ if( 1 < upd->ints[I_YSTEP]) nmax /= upd->ints[I_YSTEP];
+ else if(-1 > upd->ints[I_YSTEP]) nmax *= -upd->ints[I_YSTEP];
+ noutbuf = 2 * upd->strings[S_SETLF].size + 2;
+ noutbuf += nmax/255 + 1;
+ }
+
+ if(1 < upd->ints[I_YSTEP])
+ noutbuf += (upd->ints[I_YSTEP]-1) * upd->strings[S_YSTEP].size;
+
+ /* X-Positioning */
+ if(0 == upd->strings[S_XMOVE].size) {
+ noutbuf += 1; /* The CR */
+ noutbuf += (upd->ints[I_NXPASS]-1) * upd->strings[S_XSTEP].size;
+ } else {
+ noutbuf += upd->strings[S_XMOVE].size + 2;
+
+ if(1 < upd->ints[I_XSTEP])
+ noutbuf += (upd->ints[I_XSTEP]-1) * upd->strings[S_XSTEP].size;
+ }
+
+ /* Component-Selection */
+ if(0 < upd->string_a[SA_SETCOMP].size) {
+ need = 0;
+ for(i = 0; i < upd->ocomp; ++i)
+ if(need < upd->string_a[SA_SETCOMP].data[i].size)
+ need = upd->string_a[SA_SETCOMP].data[i].size;
+ noutbuf += need;
+ }
+
+ /* The Raster-Command */
+ need = 0;
+ for(i = 0; i < upd->ocomp; ++i)
+ if(need < upd->string_a[SA_WRITECOMP].data[i].size)
+ need = upd->string_a[SA_WRITECOMP].data[i].size;
+ noutbuf += need + 2;
+
+ /* The Data */
+ noutbuf += 2*upd->nbytes + (upd->nbytes + 127) / 128;
+
+ upd->noutbuf = noutbuf;
+ error = 1;
+ }
+
+ return error;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_wrtescp2: Write a pass */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_wrtescp2(upd_p upd, FILE *out)
+{
+ int pinbot,pin,pintop,xbegin,x,xend,icomp,ybegin,yend,y,ioutbuf,n;
+ byte *obytes;
+ updscan_p scan;
+
+/** Determine the number of pins to write */
+
+ if(upd->yscan < upd->ints[I_BEG_Y]) {
+ pintop = 0;
+ pinbot = upd->int_a[IA_BEGBOT].data[upd->ipass];
+ } else if(upd->yscan >= upd->ints[I_END_Y]) {
+ pinbot = upd->ints[I_PINS2WRITE];
+ pintop = pinbot - upd->int_a[IA_ENDTOP].data[upd->ipass];
+ } else {
+ pintop = 0;
+ pinbot = upd->ints[I_PINS2WRITE];
+ }
+
+ ybegin = pintop * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
+ yend = pinbot * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
+
+/** Determine Width of this scan */
+
+ xbegin = upd->nbytes;
+ xend = -1;
+
+ for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Pin-testloop */
+
+ if(0 > y) continue; /* Inserted Scanlines */
+
+ scan = upd->scnbuf[y & upd->scnmsk];
+
+ for(icomp = 0; icomp < upd->ocomp; ++icomp) { /* Compwise test */
+ obytes = scan[icomp].bytes;
+
+ for(x = 0; x < xbegin && !obytes[x]; x++);
+ if(x < xbegin) xbegin = x;
+
+ if(x < upd->nbytes) {
+ for(x = upd->nbytes-1; x > xend && !obytes[x]; x--);
+ if(x > xend) xend = x;
+ }
+ } /* Compwise test */
+
+ } /* Pin-testloop */
+
+ if(xbegin <= xend) { /* Some data to write */
+
+ ioutbuf = 0;
+
+ if(0 == upd->strings[S_XMOVE].size) xbegin = 0;
+
+/*
+ * Adjust the Printers Y-Position
+ */
+ if(upd->yscan != upd->yprinter) { /* Adjust Y-Position */
+ if(B_YABS & upd->flags) y = upd->yscan + upd->ints[I_YOFS];
+ else y = upd->yscan - upd->yprinter;
+
+ if( 1 < upd->ints[I_YSTEP]) {
+ n = y / upd->ints[I_YSTEP]; /* Major-Steps */
+ y -= n * upd->ints[I_YSTEP]; /* Minor-Steps */
+ } else if(-1 > upd->ints[I_YSTEP]) {
+ n = y * -upd->ints[I_YSTEP]; /* May this work? */
+ y = 0;
+ } else {
+ n = y;
+ y = 0;
+ }
+
+ if(n) { /* Coarse Positioning */
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_YMOVE].data,upd->strings[S_YMOVE].size);
+ ioutbuf += upd->strings[S_YMOVE].size;
+
+ upd->outbuf[ioutbuf++] = n & 0xff;
+ upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
+
+ } /* Coarse Positioning */
+
+ if(0 < upd->strings[S_YSTEP].size) {
+ while(y--) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_YSTEP].data,
+ upd->strings[S_YSTEP].size);
+ ioutbuf += upd->strings[S_YSTEP].size;
+ }
+ }
+
+ upd->yprinter = upd->yscan;
+ } /* Adjust Y-Position */
+/*
+ * Now write the required components
+ */
+ for(icomp = 0; icomp < upd->ocomp; ++icomp) { /* Component-Print */
+/*
+ * First check, wether this Component needs printing
+ */
+ for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Comp-Test */
+ if(0 > y) continue;
+ obytes = upd->scnbuf[y & upd->scnmsk][icomp].bytes;
+ for(x = xbegin; x <= xend && !obytes[x]; ++x);
+ if( x <= xend) break;
+ } /* Comp-Test */
+ if(y >= yend) continue; /* Component not required */
+/*
+ * Select the Component
+ */
+ if((0 < upd->string_a[SA_SETCOMP].size) &&
+ (upd->icomp != icomp ) ) { /* Selection enabled */
+ upd->icomp = icomp;
+ if(0 < upd->string_a[SA_SETCOMP].data[icomp].size) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->string_a[SA_SETCOMP].data[icomp].data,
+ upd->string_a[SA_SETCOMP].data[icomp].size);
+ ioutbuf += upd->string_a[SA_SETCOMP].data[icomp].size;
+ }
+ } /* Selection enabled */
+/*
+ * Establish the X-Position
+ */
+ if(xbegin != upd->xprinter) {
+
+ if(0 == upd->strings[S_XMOVE].size) {
+
+ upd->outbuf[ioutbuf++] = '\r';
+ upd->xprinter = 0;
+ n = 0;
+ x = 0;
+
+ } else {
+
+ if(B_XABS & upd->flags) n = x = xbegin + upd->ints[I_XOFS];
+ else n = x = xbegin - upd->xprinter;
+
+ if( 1 < upd->ints[I_XSTEP]) {
+ if(0 > n) {
+ n -= upd->ints[I_XSTEP];
+ x -= n;
+ }
+ if(n) n /= upd->ints[I_XSTEP]; /* Major-Steps */
+ if(x) x %= upd->ints[I_XSTEP]; /* Minor-Steps */
+
+ } else if(-1 > upd->ints[I_XSTEP]) {
+ n *= -upd->ints[I_XSTEP]; /* May this work? */
+ x = 0;
+ }
+
+ if(n) { /* Adjust X-Position */
+
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_XMOVE].data,
+ upd->strings[S_XMOVE].size);
+ ioutbuf += upd->strings[S_XMOVE].size;
+
+ upd->outbuf[ioutbuf++] = n & 0xff;
+ upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
+
+ } /* Adjust X-Position */
+
+ }
+
+ if(x && 0 < upd->strings[S_XSTEP].size) { /* Fine-Adjust X */
+ while(x--) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_XSTEP].data,
+ upd->strings[S_XSTEP].size);
+ ioutbuf += upd->strings[S_XSTEP].size;
+ }
+ } /* Fine-Adjust X */
+ }
+ upd->xprinter = xend+1;
+
+/*
+ * Send the Write-Command
+ */
+ if(0 < upd->string_a[SA_WRITECOMP].data[icomp].size) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->string_a[SA_WRITECOMP].data[icomp].data,
+ upd->string_a[SA_WRITECOMP].data[icomp].size);
+ ioutbuf += upd->string_a[SA_WRITECOMP].data[icomp].size;
+ }
+ n = xend + 1 - xbegin;
+ upd->outbuf[ioutbuf++] = (n<<3) & 255;
+ upd->outbuf[ioutbuf++] = (n>>5) & 255;
+/*
+ * Set the Pixels
+ */
+ for(pin = 0; pin < pintop; ++pin) {
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ ioutbuf = 0;
+ }
+
+ for(y = ybegin; 0 > y; y += upd->ints[I_NYPASS]) {
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ ioutbuf = 0;
+ }
+
+ for(; y < yend; y += upd->ints[I_NYPASS]) {
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,
+ upd->scnbuf[y & upd->scnmsk][icomp].bytes+xbegin,n);
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ ioutbuf = 0;
+ }
+
+ for(pin = pinbot; pin < upd->ints[I_PINS2WRITE]; ++pin) {
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ ioutbuf = 0;
+ }
+ } /* Component-Print */
+ } /* Some data to write */
+
+/** Advance counters in upd, change modi */
+ if(upd->yscan < upd->ints[I_BEG_Y]) {
+ upd->yscan += upd->int_a[IA_BEG_DY].data[upd->ipass++];
+ if( upd->ints[I_BEG_Y] <= upd->yscan) upd->ipass = 0;
+ else if(upd->int_a[IA_BEG_DY].size <= upd->ipass) upd->ipass = 0;
+ } else if(upd->yscan >= upd->ints[I_END_Y]) {
+ upd->yscan += upd->int_a[IA_END_DY].data[upd->ipass++];
+ if(upd->int_a[IA_END_DY].size <= upd->ipass) upd->ipass = 0;
+ } else {
+ upd->yscan += upd->int_a[IA_STD_DY].data[upd->ipass++];
+ if(upd->int_a[IA_STD_DY].size <= upd->ipass) upd->ipass = 0;
+ if(upd->yscan >= upd->ints[I_END_Y]) upd->ipass = 0;
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_wrtescnm: Write a pass */
+/* ------------------------------------------------------------------- */
+
+/*GR copied from upd_wrtescp2 and modified */
+
+static int
+upd_wrtescnm(upd_p upd, FILE *out)
+{
+ int pinbot,pin,pintop,xbegin,x,xend,icomp,ybegin,yend,y,ioutbuf,n;
+ int irow,imask,iyofs;
+ byte *obytes;
+ updscan_p scan;
+
+/** Determine the number of pins to write */
+
+ if(upd->yscan < upd->ints[I_BEG_Y]) {
+ pintop = 0;
+ pinbot = upd->int_a[IA_BEGBOT].data[upd->ipass];
+ } else if(upd->yscan >= upd->ints[I_END_Y]) {
+ pinbot = upd->ints[I_PINS2WRITE];
+ pintop = pinbot - upd->int_a[IA_ENDTOP].data[upd->ipass];
+ } else {
+ pintop = 0;
+ pinbot = upd->ints[I_PINS2WRITE];
+ }
+
+ ybegin = pintop * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
+ yend = pinbot * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
+
+/** Determine Width of this scan */
+
+ xbegin = upd->nbytes;
+ xend = -1;
+
+ for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Pin-testloop */
+
+ if(0 > y) continue; /* Inserted Scanlines */
+
+ scan = upd->scnbuf[y & upd->scnmsk];
+
+ for(icomp = 0; icomp < upd->ocomp; ++icomp) { /* Compwise test */
+ obytes = scan[icomp].bytes;
+
+ for(x = 0; x < xbegin && !obytes[x]; x++);
+ if(x < xbegin) xbegin = x;
+
+ if(x < upd->nbytes) {
+ for(x = upd->nbytes-1; x > xend && !obytes[x]; x--);
+ if(x > xend) xend = x;
+ }
+ } /* Compwise test */
+ } /* Pin-testloop */
+
+ if(xbegin <= xend) { /* Some data to write */
+
+ ioutbuf = 0;
+
+ if(0 == upd->strings[S_XMOVE].size) xbegin = 0;
+
+/*
+ * Adjust the Printers Y-Position
+ */
+ if(upd->yscan != upd->yprinter) { /* Adjust Y-Position */
+ if(B_YABS & upd->flags) y = upd->yscan + upd->ints[I_YOFS];
+ else y = upd->yscan - upd->yprinter;
+
+ if( 1 < upd->ints[I_YSTEP]) {
+ n = y / upd->ints[I_YSTEP]; /* Major-Steps */
+ y -= n * upd->ints[I_YSTEP]; /* Minor-Steps */
+ } else if(-1 > upd->ints[I_YSTEP]) {
+ n = y * -upd->ints[I_YSTEP]; /* May this work? */
+ y = 0;
+ } else {
+ n = y;
+ y = 0;
+ }
+
+ if(n) { /* Coarse Positioning */
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_YMOVE].data,upd->strings[S_YMOVE].size);
+ ioutbuf += upd->strings[S_YMOVE].size;
+
+ upd->outbuf[ioutbuf++] = n & 0xff;
+ upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
+
+ } /* Coarse Positioning */
+
+ if(0 < upd->strings[S_YSTEP].size) {
+ while(y--) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_YSTEP].data,
+ upd->strings[S_YSTEP].size);
+ ioutbuf += upd->strings[S_YSTEP].size;
+ }
+ }
+
+ upd->yprinter = upd->yscan;
+ } /* Adjust Y-Position */
+/*
+ * Now write the required components
+ */
+
+/*
+* Select the Component
+*
+* Always issue an ESC 'r' 0 - don't know why - that
+* is just what the windows driver does.
+*/
+ icomp=0;
+ if((0 < upd->string_a[SA_SETCOMP].size) /* &&
+ (upd->icomp != icomp ) */) { /* Selection enabled */
+ upd->icomp = icomp;
+ if(0 < upd->string_a[SA_SETCOMP].data[icomp].size) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->string_a[SA_SETCOMP].data[icomp].data,
+ upd->string_a[SA_SETCOMP].data[icomp].size);
+ ioutbuf += upd->string_a[SA_SETCOMP].data[icomp].size;
+ }
+ } /* Selection enabled */
+/*
+* Establish the X-Position
+*/
+ if(xbegin != upd->xprinter) {
+
+ if(0 == upd->strings[S_XMOVE].size) {
+
+ upd->outbuf[ioutbuf++] = '\r';
+ upd->xprinter = 0;
+ n = 0;
+ x = 0;
+
+ } else {
+
+ if(B_XABS & upd->flags) n = x = xbegin + upd->ints[I_XOFS];
+ else n = x = xbegin - upd->xprinter;
+
+ if( 1 < upd->ints[I_XSTEP]) {
+ if(0 > n) {
+ n -= upd->ints[I_XSTEP];
+ x -= n;
+ }
+ if(n) n /= upd->ints[I_XSTEP]; /* Major-Steps */
+ if(x) x %= upd->ints[I_XSTEP]; /* Minor-Steps */
+
+ } else if(-1 > upd->ints[I_XSTEP]) {
+ n *= -upd->ints[I_XSTEP]; /* May this work? */
+ x = 0;
+ }
+
+ if(n) { /* Adjust X-Position */
+
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_XMOVE].data,
+ upd->strings[S_XMOVE].size);
+ ioutbuf += upd->strings[S_XMOVE].size;
+
+ upd->outbuf[ioutbuf++] = n & 0xff;
+ upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
+
+ } /* Adjust X-Position */
+
+ }
+
+ if(x && 0 < upd->strings[S_XSTEP].size) { /* Fine-Adjust X */
+ while(x--) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_XSTEP].data,
+ upd->strings[S_XSTEP].size);
+ ioutbuf += upd->strings[S_XSTEP].size;
+ }
+ } /* Fine-Adjust X */
+ }
+ upd->xprinter = xend+1;
+
+/*
+* Send the Write-Command - the default is ESC '.' 1
+*/
+ if(0 < upd->string_a[SA_WRITECOMP].data[icomp].size) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->string_a[SA_WRITECOMP].data[icomp].data,
+ upd->string_a[SA_WRITECOMP].data[icomp].size);
+ ioutbuf += upd->string_a[SA_WRITECOMP].data[icomp].size;
+ }
+ n = xend + 1 - xbegin;
+ upd->outbuf[ioutbuf++] = (n<<3) & 255;
+ upd->outbuf[ioutbuf++] = (n>>5) & 255;
+/*
+* Set the Pixels
+*/
+ irow=0; /* row counter for output data */
+
+ /* pins at the top of the head that don't print */
+ for(pin = 0; pin < pintop; ++pin) {
+ int i;
+ for(i=0 ; i < upd->ints[I_PATRPT]; i++){
+ if(irow >= upd->ints[I_ROWS]) break;
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ irow++;
+ ioutbuf = 0;
+ }
+ }
+
+ /* I'm not really sure what this does */
+ /* it looks like we're filling in empty rows */
+ for(y = ybegin; 0 > y; y += upd->ints[I_NYPASS]) {
+
+ int i;
+ for(i=0 ; i < upd->ints[I_PATRPT]; i++){
+ if(irow >= upd->ints[I_ROWS]) break;
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ ioutbuf = 0;
+ irow++;
+ }
+ }
+
+ for(; y < yend; y += upd->ints[I_NYPASS]) {
+
+ int i,masklen=upd->ints[I_PATRPT],yinc=0;
+
+ for(i=0 ; (i < upd->ints[I_PATRPT]); i++){
+ if(irow >= upd->ints[I_ROWS]) break;
+ imask = irow%masklen;
+ icomp = upd->int_a[IA_ROWMASK].data[imask];
+ if(icomp == 0) {
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
+ } else {
+ --icomp;
+ iyofs = upd->int_a[IA_SCNOFS].data[imask];
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,
+ upd->scnbuf[(y+iyofs) & upd->scnmsk][icomp].bytes+xbegin,n);
+ yinc+=upd->ints[I_NYPASS];
+ }
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ ioutbuf = 0;
+ irow++;
+ }
+
+ if (upd->ints[I_NYPASS] < upd->ints[I_PATRPT]) {
+ y+=yinc;
+ if (y > 0)
+ y-=upd->ints[I_NYPASS];
+ }
+ }
+
+ /* I think this is the pins at the bottom of the head that don't print */
+ for(pin = pinbot; pin < upd->ints[I_PINS2WRITE]; ++pin) {
+ int i;
+ for(i=0 ; i < upd->ints[I_PATRPT]; i++){
+ if(irow >= upd->ints[I_ROWS]) break;
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ ioutbuf = 0;
+ irow++;
+ }
+ }
+
+ /* pad empty rows that haven't been filled yet*/
+ if (irow < upd->ints[I_ROWS]) {
+ for( ; irow < upd->ints[I_ROWS]; irow++){
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ ioutbuf = 0;
+ }
+ }
+
+ } /* Some data to write */
+
+/** Advance counters in upd, change modi */
+ if(upd->yscan < upd->ints[I_BEG_Y]) {
+ upd->yscan += upd->int_a[IA_BEG_DY].data[upd->ipass++];
+ if( upd->ints[I_BEG_Y] <= upd->yscan) upd->ipass = 0;
+ else if(upd->int_a[IA_BEG_DY].size <= upd->ipass) upd->ipass = 0;
+ } else if(upd->yscan >= upd->ints[I_END_Y]) {
+ upd->yscan += upd->int_a[IA_END_DY].data[upd->ipass++];
+ if(upd->int_a[IA_END_DY].size <= upd->ipass) upd->ipass = 0;
+ } else {
+ upd->yscan += upd->int_a[IA_STD_DY].data[upd->ipass++];
+ if(upd->int_a[IA_STD_DY].size <= upd->ipass) upd->ipass = 0;
+ if(upd->yscan >= upd->ints[I_END_Y]) upd->ipass = 0;
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_wrtescp2x: Write an ESC/P2-pass with X-Weaving */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_wrtescp2x(upd_p upd, FILE *out)
+{
+ int pinbot,pin,pintop,xbegin,x,xend,icomp,ybegin,yend,y,ioutbuf,n,ixpass;
+ byte *obytes,bit;
+ updscan_p scan;
+
+/** Determine the number of pins to write */
+
+ if(upd->yscan < upd->ints[I_BEG_Y]) {
+ ixpass = upd->int_a[IA_BEG_IX].data[upd->ipass];
+ pintop = 0;
+ pinbot = upd->int_a[IA_BEGBOT].data[upd->ipass];
+ } else if(upd->yscan >= upd->ints[I_END_Y]) {
+ ixpass = upd->int_a[IA_END_IX].data[upd->ipass];
+ pinbot = upd->ints[I_PINS2WRITE];
+ pintop = pinbot - upd->int_a[IA_ENDTOP].data[upd->ipass];
+ } else {
+ ixpass = upd->int_a[IA_STD_IX].data[upd->ipass];
+ pintop = 0;
+ pinbot = upd->ints[I_PINS2WRITE];
+ }
+
+ ybegin = pintop * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
+ yend = pinbot * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
+
+/** Determine Width of this scan */
+
+ xbegin = upd->pwidth;
+ xend = -1;
+
+ for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Pin-testloop */
+
+ if(0 > y) continue; /* Inserted Scanlines */
+
+ scan = upd->scnbuf[y & upd->scnmsk];
+
+ for(icomp = 0; icomp < upd->ocomp; ++icomp) { /* Compwise test */
+ if(xbegin > scan[icomp].xbegin[ixpass])
+ xbegin = scan[icomp].xbegin[ixpass];
+ if(xend < scan[icomp].xend[ ixpass])
+ xend = scan[icomp].xend[ ixpass];
+ } /* Compwise test */
+
+ } /* Pin-testloop */
+
+ if(xbegin <= xend) { /* Some data to write */
+
+ ioutbuf = upd->nbytes;
+
+ if(0 == upd->strings[S_XMOVE].size) xbegin = ixpass;
+
+/*
+ * Adjust the Printers Y-Position
+ */
+ if(upd->yscan != upd->yprinter) { /* Adjust Y-Position */
+ if(B_YABS & upd->flags) y = upd->yscan + upd->ints[I_YOFS];
+ else y = upd->yscan - upd->yprinter;
+
+ if( 1 < upd->ints[I_YSTEP]) {
+ n = y / upd->ints[I_YSTEP]; /* Major-Steps */
+ y -= n * upd->ints[I_YSTEP]; /* Minor-Steps */
+ } else if(-1 > upd->ints[I_YSTEP]) {
+ n = y * -upd->ints[I_YSTEP]; /* May this work? */
+ y = 0;
+ } else {
+ n = y;
+ y = 0;
+ }
+
+ if(n) { /* Coarse Positioning */
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_YMOVE].data,upd->strings[S_YMOVE].size);
+ ioutbuf += upd->strings[S_YMOVE].size;
+
+ upd->outbuf[ioutbuf++] = n & 0xff;
+ upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
+
+ } /* Coarse Positioning */
+
+ if(0 < upd->strings[S_YSTEP].size) {
+ while(y--) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_YSTEP].data,
+ upd->strings[S_YSTEP].size);
+ ioutbuf += upd->strings[S_YSTEP].size;
+ }
+ }
+
+ upd->yprinter = upd->yscan;
+ } /* Adjust Y-Position */
+
+/*
+ * Now write the required components
+ */
+ for(icomp = 0; icomp < upd->ocomp; ++icomp) { /* Component-Print */
+/*
+ * First check, wether this Component needs printing
+ */
+ for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Comp-Test */
+ if(0 > y) continue;
+ scan = upd->scnbuf[y & upd->scnmsk]+icomp;
+ if(0 <= scan->xend[ixpass]) break;
+ } /* Comp-Test */
+ if(y >= yend) continue; /* Component not required */
+/*
+ * Select the Component
+ */
+ if((0 < upd->string_a[SA_SETCOMP].size) &&
+ (upd->icomp != icomp ) ) { /* Selection enabled */
+ upd->icomp = icomp;
+ if(0 < upd->string_a[SA_SETCOMP].data[icomp].size) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->string_a[SA_SETCOMP].data[icomp].data,
+ upd->string_a[SA_SETCOMP].data[icomp].size);
+ ioutbuf += upd->string_a[SA_SETCOMP].data[icomp].size;
+ }
+ } /* Selection enabled */
+/*
+ * Establish the X-Position
+ */
+ if(xbegin != upd->xprinter) {
+
+ if(0 == upd->strings[S_XMOVE].size) {
+
+ upd->outbuf[ioutbuf++] = '\r';
+ upd->xprinter = 0;
+ n = 0;
+ x = ixpass;
+
+ } else {
+
+ if(B_XABS & upd->flags) n = x = xbegin + upd->ints[I_XOFS];
+ else n = x = xbegin - upd->xprinter;
+
+ if( 1 < upd->ints[I_XSTEP]) {
+ if(0 > n) {
+ n -= upd->ints[I_XSTEP];
+ x -= n;
+ }
+ if(n) n /= upd->ints[I_XSTEP]; /* Major-Steps */
+ if(x) x %= upd->ints[I_XSTEP]; /* Minor-Steps */
+
+ } else if(-1 > upd->ints[I_XSTEP]) {
+ n *= -upd->ints[I_XSTEP]; /* May this work? */
+ x = 0;
+ }
+
+ if(n) { /* Adjust X-Position */
+
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_XMOVE].data,
+ upd->strings[S_XMOVE].size);
+ ioutbuf += upd->strings[S_XMOVE].size;
+
+ upd->outbuf[ioutbuf++] = n & 0xff;
+ upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
+
+ } /* Adjust X-Position */
+
+ }
+
+ if(x && 0 < upd->strings[S_XSTEP].size) { /* Fine-Adjust X */
+ while(x--) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->strings[S_XSTEP].data,
+ upd->strings[S_XSTEP].size);
+ ioutbuf += upd->strings[S_XSTEP].size;
+ }
+ } /* Fine-Adjust X */
+ }
+ upd->xprinter = xend+1;
+
+/*
+ * Send the Write-Command
+ */
+ if(0 < upd->string_a[SA_WRITECOMP].data[icomp].size) {
+ memcpy(upd->outbuf+ioutbuf,
+ upd->string_a[SA_WRITECOMP].data[icomp].data,
+ upd->string_a[SA_WRITECOMP].data[icomp].size);
+ ioutbuf += upd->string_a[SA_WRITECOMP].data[icomp].size;
+ }
+ n = ((xend - xbegin) / upd->ints[I_NXPASS] + 8) & ~7;
+ upd->outbuf[ioutbuf++] = n & 255;
+ upd->outbuf[ioutbuf++] = (n>>8) & 255;
+ n >>= 3;
+/*
+ * Set the Pixels
+ */
+ for(pin = 0; pin < pintop; ++pin) {
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
+ fwrite(upd->outbuf+upd->nbytes,1,ioutbuf-upd->nbytes,out);
+ ioutbuf = upd->nbytes;
+ }
+
+ for(y = ybegin; 0 > y; y += upd->ints[I_NYPASS]) {
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
+ fwrite(upd->outbuf+upd->nbytes,1,ioutbuf-upd->nbytes,out);
+ ioutbuf = upd->nbytes;
+ }
+
+ for(; y < yend; y += upd->ints[I_NYPASS]) {
+ byte * ibytes = upd->scnbuf[y & upd->scnmsk][icomp].bytes;
+ obytes = upd->outbuf;
+ memset(obytes,0,upd->nbytes);
+ bit = 0x80;
+ for(x = xbegin; x <= xend; x += upd->ints[I_NXPASS]) {
+ if(ibytes[x>>3] & (0x80 >> (x & 7))) *obytes |= bit;
+ if(!(bit >>= 1)) { obytes++; bit = 0x80; }
+ }
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,upd->outbuf,n);
+ fwrite(upd->outbuf+upd->nbytes,1,ioutbuf-upd->nbytes,out);
+ ioutbuf = upd->nbytes;
+ }
+
+ for(pin = pinbot; pin < upd->ints[I_PINS2WRITE]; ++pin) {
+ ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
+ fwrite(upd->outbuf+upd->nbytes,1,ioutbuf-upd->nbytes,out);
+ ioutbuf = upd->nbytes;
+ }
+ } /* Component-Print */
+ } /* Some data to write */
+
+/** Advance counters in upd, change modi */
+
+ if(upd->yscan < upd->ints[I_BEG_Y]) {
+ upd->yscan += upd->int_a[IA_BEG_DY].data[upd->ipass++];
+ if( upd->ints[I_BEG_Y] <= upd->yscan) upd->ipass = 0;
+ else if(upd->int_a[IA_BEG_DY].size <= upd->ipass) upd->ipass = 0;
+ } else if(upd->yscan >= upd->ints[I_END_Y]) {
+ upd->yscan += upd->int_a[IA_END_DY].data[upd->ipass++];
+ if(upd->int_a[IA_END_DY].size <= upd->ipass) upd->ipass = 0;
+ } else {
+ upd->yscan += upd->int_a[IA_STD_DY].data[upd->ipass++];
+ if(upd->int_a[IA_STD_DY].size <= upd->ipass) upd->ipass = 0;
+ if(upd->yscan >= upd->ints[I_END_Y]) upd->ipass = 0;
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_rle: The Runlength-Compressor */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_rle(byte *out,const byte *in,int nbytes)
+{
+
+ int used = 0;
+ int crun,cdata;
+ byte run;
+
+ if(in != NULL) { /* Data present */
+
+ crun = 1;
+
+ while(nbytes > 0) { /* something to compress */
+
+ run = in[0];
+
+ while((nbytes > crun) && (run == in[crun])) if(++crun == 128) break;
+
+ if((crun > 2) || (crun == nbytes)) { /* use this run */
+
+ *out++ = (257 - crun) & 0xff; *out++ = run; used += 2;
+
+ nbytes -= crun; in += crun;
+ crun = 1;
+
+ } else { /* ignore this run */
+
+ for(cdata = crun; (nbytes > cdata) && (crun < 4);) {
+ if(run == in[cdata]) crun += 1;
+ else run = in[cdata], crun = 1;
+ if(++cdata == 128) break;
+ }
+
+ if(crun < 3) crun = 0; /* ignore trailing run */
+ else cdata -= crun;
+
+ *out++ = cdata-1; used++;
+ memcpy(out,in,cdata); used += cdata; out += cdata;
+
+ nbytes -= cdata; in += cdata;
+
+ } /* use/ignore run */
+
+ } /* something to compress */
+
+ } else { /* Empty scans to fill bands */
+
+ while(nbytes > 0) {
+ crun = nbytes > 128 ? 128 : nbytes;
+ nbytes -= crun;
+ *out++ = (257 - crun) & 0xff;
+ *out++ = 0;
+ used += 2;
+ }
+ } /* Data present or empty */
+ return used;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_open_wrtrtl: Basic HP-RTL Writer */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_open_wrtrtl(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ int error = 0;
+
+/** Adjust the Raster-Width */
+
+ if(0 < upd->strings[S_BEGIN].size) { /* BOP-Checker */
+
+ int i,j,state;
+ char cv[24];
+ byte *bp;
+ uint ncv,nbp;
+
+ j = -1;
+ state = 0;
+ for(i = 0; i < upd->strings[S_BEGIN].size; ++i) {
+ const int c = upd->strings[S_BEGIN].data[i];
+
+ switch(state) {
+/* ----- any character */
+ case 0:
+ if( c == 0x1b) state = 1; /* ESC */
+ break;
+
+/* ----- last was ESC */
+ case 1:
+ if( c == 0x2a) state = 2; /* ESC * */
+ else if( c == 0x25) state = 5; /* ESC % */
+ else state = 0;
+ break;
+
+/* ----- got ESC * */
+ case 2:
+ j = i; /* This character is not part of the replaced text */
+ if( c == 0x72) state = 3; /* ESC * r */
+ else if( c == 0x74) state = 4; /* ESC * t */
+ else state = 0;
+ break;
+
+/* ----- got ESC * r */
+/* Pagewidth and Pagelength might be replaced */
+ case 3:
+
+ if( (B_PAGEWIDTH & upd->flags) &&
+ ((c == 0x73) || (c == 0x53)) ) { /* esc * r # S */
+
+ gs_sprintf(cv,"%d",upd->pwidth);
+ ncv = strlen(cv);
+
+ nbp = (j+1) + ncv + (upd->strings[S_BEGIN].size-i);
+ UPD_MM_GET_ARRAY(udev->memory, bp,nbp);
+
+ if(0 <= j) memcpy(bp,upd->strings[S_BEGIN].data,j+1);
+ memcpy(bp+j+1, cv,ncv);
+ memcpy(bp+j+1+ncv,upd->strings[S_BEGIN].data+i,
+ upd->strings[S_BEGIN].size-i);
+ i = j+1+ncv;
+ UPD_MM_DEL_PARAM(udev->memory, upd->strings[S_BEGIN]);
+ upd->strings[S_BEGIN].data = bp;
+ upd->strings[S_BEGIN].size = nbp;
+
+ } else if((B_PAGELENGTH & upd->flags) &&
+ ((c == 0x74) || (c == 0x54)) ) { /* esc * r # T */
+
+ gs_sprintf(cv,"%d",upd->pheight);
+ ncv = strlen(cv);
+
+ nbp = (j+1) + ncv + (upd->strings[S_BEGIN].size-i);
+ UPD_MM_GET_ARRAY(udev->memory, bp,nbp);
+
+ if(0 <= j) memcpy(bp,upd->strings[S_BEGIN].data,j+1);
+ memcpy(bp+j+1, cv,ncv);
+ memcpy(bp+j+1+ncv,upd->strings[S_BEGIN].data+i,
+ upd->strings[S_BEGIN].size-i);
+ i = j+1+ncv;
+ UPD_MM_DEL_PARAM(udev->memory, upd->strings[S_BEGIN]);
+ upd->strings[S_BEGIN].data = bp;
+ upd->strings[S_BEGIN].size = nbp;
+
+ }
+
+ if( (0x40 < c) && (c < 0x5b)) state = 0; /* Term. cmd. */
+ else if(!((0x2f < c) && (c < 0x3a))) j = i; /* Non-Number */
+
+ break;
+
+/* ----- got ESC * t */
+/* Resolution might be replaced */
+ case 4: /* esc * t */
+
+ if( (B_RESOLUTION & upd->flags) &&
+ ((c == 0x72) || (c == 0x52)) ) { /* esc * t # R */
+
+ gs_sprintf(cv,"%d",(int)
+ ((udev->y_pixels_per_inch < udev->x_pixels_per_inch ?
+ udev->x_pixels_per_inch : udev->y_pixels_per_inch)
+ +0.5));
+ ncv = strlen(cv);
+
+ nbp = (j+1) + ncv + (upd->strings[S_BEGIN].size-i);
+ UPD_MM_GET_ARRAY(udev->memory, bp,nbp);
+
+ if(0 <= j) memcpy(bp,upd->strings[S_BEGIN].data,j+1);
+ memcpy(bp+j+1, cv,ncv);
+ memcpy(bp+j+1+ncv,upd->strings[S_BEGIN].data+i,
+ upd->strings[S_BEGIN].size-i);
+ i = j+1+ncv;
+ UPD_MM_DEL_PARAM(udev->memory, upd->strings[S_BEGIN]);
+ upd->strings[S_BEGIN].data = bp;
+ upd->strings[S_BEGIN].size = nbp;
+
+ }
+
+ if( (0x40 < c) && (c < 0x5b)) state = 0; /* Term. cmd. */
+ else if(!((0x2f < c) && (c < 0x3a))) j = i; /* Non-Number */
+
+ break;
+
+ case 5: /* ESC % - 1 2 3 4 5 X */
+ if( c == 0x2d) state = 6; /* ESC % - */
+ else state = 0;
+ break;
+
+ case 6: /* ESC % - 1 2 3 4 5 X */
+ if( c == 0x31) state = 7; /* ESC % - 1 */
+ else state = 0;
+ break;
+
+ case 7: /* ESC % - 1 2 3 4 5 X */
+ if( c == 0x32) state = 8; /* ESC % - 1 2 */
+ else state = 0;
+ break;
+
+ case 8: /* ESC % - 1 2 3 4 5 X */
+ if( c == 0x33) state = 9; /* ESC % - 1 2 3 */
+ else state = 0;
+ break;
+
+ case 9: /* ESC % - 1 2 3 4 5 X */
+ if( c == 0x34) state = 10; /* ESC % - 1 2 3 4 */
+ else state = 0;
+ break;
+
+ case 10: /* ESC % - 1 2 3 4 5 X */
+ if( c == 0x35) state = 11; /* ESC % - 1 2 3 4 5 */
+ else state = 0;
+ break;
+
+ case 11: /* ESC % - 1 2 3 4 5 X */
+ if( c == 0x58) state = 12; /* ESC % - 1 2 3 4 5 X */
+ else state = 0;
+ break;
+
+ case 12: /* PJL-BOL: @ P J L ws */
+ if( c == 0x40) state = 13; /* @ */
+ else state = 0;
+ break;
+
+ case 13: /* PJL-BOL @ P J L ws */
+ if( c == 0x50) state = 14; /* @ P */
+ else state = 0;
+ break;
+
+ case 14: /* PJL-BOL @ P J L ws */
+ if( c == 0x4a) state = 15; /* @ P J */
+ else state = 0;
+ break;
+
+ case 15: /* PJL-BOL @ P J L ws */
+ if( c == 0x4c) state = 16; /* @ P J L */
+ else state = 0;
+ break;
+
+ case 16: /* PJL-BOL @ P J L ws */
+ if((c == 0x20) || (c == 0x09)) state = 19; /* @ P J L ws */
+ else if( c == 0x0d ) state = 17;
+ else if( c == 0x0a ) state = 12;
+ else state = 0; /* PJL-Error */
+ break;
+
+ case 17: /* PJL-EOL */
+ if( c == 0x0a) state = 12; /* Next PJL-Command */
+ else state = 0; /* PJL-Error */
+ break;
+
+ case 18: /* PJL-Eatup: Expect Newline */
+ if( c == 0x0a) state = 12;
+ break;
+
+ case 19: /* Begin of PJL-Command */
+ if( (c == 0x53) || (c == 0x73)) state = 20; /* S E T*/
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else if( c == 0x0d ) state = 17;
+ break;
+
+ case 20: /* PJL-Set: S E T */
+ if( (c == 0x45) || (c == 0x65)) state = 21; /* S E */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 21: /* PJL-Set: S E T */
+ if( (c == 0x54) || (c == 0x74)) state = 22; /* S E T */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 22: /* PJL-Set: S E T ws */
+ if( (c == 0x20) || (c == 0x09)) state = 23; /* S E T ws */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 23: /* PJL-Set: S E T ws */
+ if( (c == 0x50) || (c == 0x70)) state = 24; /* set paper... */
+ else if((c == 0x52) || (c == 0x72)) state = 41; /* set resolution */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 24: /* PJL-Set: set paper... */
+ if( (c == 0x41) || (c == 0x61)) state = 25; /* set pa */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 25: /* PJL-Set: set paper... */
+ if( (c == 0x50) || (c == 0x70)) state = 26; /* set pap */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 26: /* PJL-Set: set paper... */
+ if( (c == 0x45) || (c == 0x65)) state = 27; /* set pape */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 27: /* PJL-Set: set paper... */
+ if( (c == 0x52) || (c == 0x72)) state = 28; /* set paper */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 28: /* PJL-Set: set paper? */
+ if( (c == 0x4c) || (c == 0x6c)) state = 29; /* set paperlength */
+ else if((c == 0x57) || (c == 0x77)) state = 36; /* set paperwidth */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 29: /* PJL: set paperlength */
+ if( (c == 0x45) || (c == 0x65)) state = 30; /* set paperle */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 30: /* PJL: set paperlength */
+ if( (c == 0x4e) || (c == 0x6e)) state = 31; /* set paperlen */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 31: /* PJL: set paperlength */
+ if( (c == 0x47) || (c == 0x67)) state = 32; /* set paperleng */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 32: /* PJL: set paperlength */
+ if( (c == 0x54) || (c == 0x74)) state = 33; /* set paperlengt */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 33: /* PJL: set paperlength */
+ if( (c == 0x48) || (c == 0x68)) state = 34; /* set paperlength */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 34: /* PJL: set paperlength */
+ j = i; /* This character is not part of the replaced text */
+ if( c == 0x3d ) state = 51; /* set paperlength */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else if((c != 0x20) && (c != 0x09)) state = 18;
+ break;
+
+ case 51: /* PJL: set paperlength = ws */
+ if( c == 0x0a) state = 12;
+ else if((c == 0x20) || (c == 0x09)) j = i;
+ else if(( 0x30 > c) || ( c > 0x39)) state = 18;
+ else state = 35;
+ break;
+
+ case 35: /* PJL: set paperlength */
+ if((0x30 > c) || (c > 0x39)) { /* End of number */
+
+ if(B_PAGELENGTH & upd->flags) { /* insert new number */
+
+ gs_sprintf(cv,"%d",(int)
+ (720.0 * udev->height / udev->y_pixels_per_inch + 0.5));
+ ncv = strlen(cv);
+
+ nbp = (j+1) + ncv + (upd->strings[S_BEGIN].size-i);
+ UPD_MM_GET_ARRAY(udev->memory, bp,nbp);
+
+ if(0 <= j) memcpy(bp,upd->strings[S_BEGIN].data,j+1);
+ memcpy(bp+j+1, cv,ncv);
+ memcpy(bp+j+1+ncv,upd->strings[S_BEGIN].data+i,
+ upd->strings[S_BEGIN].size-i);
+ i = j+1+ncv;
+ UPD_MM_DEL_PARAM(udev->memory, upd->strings[S_BEGIN]);
+ upd->strings[S_BEGIN].data = bp;
+ upd->strings[S_BEGIN].size = nbp;
+ } /* insert new number */
+
+ if( c == 0x0a ) state = 12;
+ else state = 18;
+ }
+ break;
+
+ case 36: /* PJL: set paperwidth */
+ if( (c == 0x49) || (c == 0x69)) state = 37; /* set paperwi */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 37: /* PJL: set paperwidth */
+ if( (c == 0x44) || (c == 0x64)) state = 38; /* set paperwid */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 38: /* PJL: set paperwidth */
+ if( (c == 0x54) || (c == 0x74)) state = 39; /* set paperwidt */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 39: /* PJL: set paperwidth */
+ if( (c == 0x48) || (c == 0x68)) state = 52; /* set paperwidth */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 52: /* PJL: set paperwidth */
+ j = i; /* This character is not part of the replaced text */
+ if( c == 0x3d ) state = 53; /* set paperwidth */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else if((c != 0x20) && (c != 0x09)) state = 18;
+ break;
+
+ case 53: /* PJL: set paperwidth = ws */
+ if( c == 0x0a) state = 12;
+ else if((c == 0x20) || (c == 0x09)) j = i;
+ else if(( 0x30 > c) || ( c > 0x39)) state = 18;
+ else state = 40;
+ break;
+
+ case 40: /* PJL: set paperlength */
+ if((0x30 > c) || (c > 0x39)) { /* End of number */
+
+ if(B_PAGEWIDTH & upd->flags) { /* insert new number */
+
+ gs_sprintf(cv,"%d",(int)
+ (720.0 * udev->width / udev->x_pixels_per_inch + 0.5));
+ ncv = strlen(cv);
+
+ nbp = (j+1) + ncv + (upd->strings[S_BEGIN].size-i);
+ UPD_MM_GET_ARRAY(udev->memory, bp,nbp);
+
+ if(0 <= j) memcpy(bp,upd->strings[S_BEGIN].data,j+1);
+ memcpy(bp+j+1, cv,ncv);
+ memcpy(bp+j+1+ncv,upd->strings[S_BEGIN].data+i,
+ upd->strings[S_BEGIN].size-i);
+ i = j+1+ncv;
+ UPD_MM_DEL_PARAM(udev->memory, upd->strings[S_BEGIN]);
+ upd->strings[S_BEGIN].data = bp;
+ upd->strings[S_BEGIN].size = nbp;
+ } /* insert new number */
+
+ if( c == 0x0a ) state = 12;
+ else state = 18;
+ }
+ break;
+
+ case 41: /* PJL: set resolution */
+ if( (c == 0x45) || (c == 0x65)) state = 42; /* set re */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 42: /* PJL: set resolution */
+ if( (c == 0x53) || (c == 0x73)) state = 43; /* set res */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 43: /* PJL: set resolution */
+ if( (c == 0x4f) || (c == 0x6f)) state = 44; /* set reso */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 44: /* PJL: set resolution */
+ if( (c == 0x4c) || (c == 0x6c)) state = 45; /* set resol */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 45: /* PJL: set resolution */
+ if( (c == 0x55) || (c == 0x75)) state = 46; /* set resolu */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 46: /* PJL: set resolution */
+ if( (c == 0x54) || (c == 0x74)) state = 47; /* set resolut */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 47: /* PJL: set resolution */
+ if( (c == 0x49) || (c == 0x69)) state = 48; /* set resoluti */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 48: /* PJL: set resolution */
+ if( (c == 0x4f) || (c == 0x6f)) state = 49; /* set resolutio */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 49: /* PJL: set resolution */
+ if( (c == 0x4e) || (c == 0x6e)) state = 54; /* set resolution */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else state = 18;
+ break;
+
+ case 54: /* PJL: set resolution */
+ j = i; /* This character is not part of the replaced text */
+ if( c == 0x3d ) state = 55; /* set resolution */
+ else if( c == 0x0a ) state = 12; /* BOL */
+ else if((c != 0x20) && (c != 0x09)) state = 18;
+ break;
+
+ case 55: /* PJL: set resolution = ws */
+ if( c == 0x0a) state = 12;
+ else if((c == 0x20) || (c == 0x09)) j = i;
+ else if(( 0x30 > c) || ( c > 0x39)) state = 18;
+ else state = 50;
+ break;
+
+ case 50: /* PJL: set resolution */
+ if((0x30 > c) || (c > 0x39)) { /* End of number */
+
+ if(B_RESOLUTION & upd->flags) { /* insert new number */
+
+ gs_sprintf(cv,"%d",(int)
+ ((udev->y_pixels_per_inch < udev->x_pixels_per_inch ?
+ udev->x_pixels_per_inch : udev->y_pixels_per_inch)
+ +0.5));
+ ncv = strlen(cv);
+
+ nbp = (j+1) + ncv + (upd->strings[S_BEGIN].size-i);
+ UPD_MM_GET_ARRAY(udev->memory, bp,nbp);
+
+ if(0 <= j) memcpy(bp,upd->strings[S_BEGIN].data,j+1);
+ memcpy(bp+j+1, cv,ncv);
+ memcpy(bp+j+1+ncv,upd->strings[S_BEGIN].data+i,
+ upd->strings[S_BEGIN].size-i);
+ i = j+1+ncv;
+ UPD_MM_DEL_PARAM(udev->memory, upd->strings[S_BEGIN]);
+ upd->strings[S_BEGIN].data = bp;
+ upd->strings[S_BEGIN].size = nbp;
+ } /* insert new number */
+
+ if( c == 0x0a ) state = 12;
+ else state = 18;
+ }
+ break;
+
+ default:
+#if UPD_MESSAGES & UPD_M_ERROR
+ errprintf(udev->memory,
+ "UNIPRINT-Coding error, wrrtl, state = %d\n",state);
+#endif
+ state = 0;
+ break;
+ }
+ }
+ } /* BOP-Checker */
+
+/** SA_WRITECOMP must be valid */
+ if(upd->ocomp > upd->string_a[SA_WRITECOMP].size) {
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "PCL-Open: WRITECOMP-Commands must be given\n");
+#endif
+ error = -1;
+ }
+
+/**
+If all this is correct, it's time to compute the size of the output-buffer.
+It must hold:
+ 1. Y-Positioning
+ 2. Component-Data
+*/
+ if(0 <= error) {
+ int32_t ny,noutbuf;
+ char tmp[16];
+
+ if(0 < upd->strings[S_YMOVE].size) {
+ gs_sprintf(tmp,"%d",upd->pheight);
+ ny = upd->strings[S_YMOVE].size + strlen(tmp);
+ } else {
+ ny = 1 + upd->string_a[SA_WRITECOMP].data[upd->ocomp-1].size;
+ ny *= upd->pheight;
+ }
+
+ noutbuf = upd->nbytes + (upd->nbytes + 127) / 128;
+
+ if(ny > noutbuf) noutbuf = ny;
+ noutbuf += 16;
+
+ if((0 < noutbuf) && (noutbuf <= INT_MAX)) {
+ upd->noutbuf = noutbuf;
+ upd->writer = upd_wrtrtl;
+ error = 1;
+ } else {
+ error = -1;
+#if UPD_MESSAGES & UPD_M_WARNING
+ errprintf(udev->memory,
+ "PCL-Open: %ld is unreasonable size of Outputbuffer\n",
+ (long) noutbuf);
+#endif
+ }
+ }
+
+ return error;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_wrtrtl: Write a pass */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_wrtrtl(upd_p upd, FILE *out)
+{
+ const updscan_p scan = upd->scnbuf[upd->yscan & upd->scnmsk];
+
+ int x,xend,icomp,ioutbuf;
+ byte *data;
+
+/** Determine Width of this scan */
+
+ xend = -1;
+ for(icomp = 0; icomp < upd->ocomp; ++icomp) {
+
+ data = scan[icomp].bytes;
+
+ for(x = upd->nbytes-1; 0 <= x; --x) if(data[x]) break;
+ if(x > xend) xend = x;
+ }
+
+ if(0 <= xend) { /* Some data to write */
+
+ ioutbuf = 0;
+ xend += 1;
+/*
+ * Adjust the Printers Y-Position
+ */
+ if(upd->yscan != upd->yprinter) { /* Adjust Y-Position */
+ if(1 < upd->strings[S_YMOVE].size) {
+ gs_sprintf((char *)upd->outbuf+ioutbuf,
+ (const char *) upd->strings[S_YMOVE].data,
+ upd->yscan - upd->yprinter);
+ ioutbuf += strlen((char *)upd->outbuf+ioutbuf);
+ } else {
+ while(upd->yscan > upd->yprinter) {
+ for(icomp = 0; icomp < upd->ocomp; ++icomp) {
+ gs_sprintf((char *)upd->outbuf+ioutbuf,
+ (const char *) upd->string_a[SA_WRITECOMP].data[icomp].data,0);
+ ioutbuf += strlen((char *)upd->outbuf+ioutbuf);
+ }
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ ioutbuf = 0;
+ upd->yprinter += 1;
+ }
+ }
+ upd->yprinter = upd->yscan;
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ ioutbuf = 0;
+ } /* Adjust Y-Position */
+/*
+ * Now write the all! components
+ */
+ for(icomp = 0; icomp < upd->ocomp; ++icomp) { /* Component-Print */
+ data = scan[icomp].bytes;
+ for(x = 0; x <= xend; ++x) if(data[x]) break;
+ if(x <= xend) {
+ ioutbuf = upd_rle(upd->outbuf,scan[icomp].bytes,xend);
+ fprintf(out,
+ (const char *)upd->string_a[SA_WRITECOMP].data[icomp].data,ioutbuf);
+ fwrite(upd->outbuf,1,ioutbuf,out);
+ } else {
+ fprintf(out,
+ (const char *)upd->string_a[SA_WRITECOMP].data[icomp].data,0);
+ }
+ }
+
+ upd->yprinter += 1;
+
+ } /* Some data to write */
+
+/** Advance scan by one */
+
+ upd->yscan += 1;
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_open_wrtcanon: Basic Canon Extended Mode Writer (hr) */
+/* ------------------------------------------------------------------- */
+
+static int
+upd_open_wrtcanon(upd_device *udev)
+{
+ const upd_p upd = udev->upd;
+ int error = 0;
+
+ /* max length of one printer line */
+ upd->noutbuf = upd->nbytes + (upd->nbytes + 127) / 128;
+ upd->writer = upd_wrtcanon;
+ error = 1;
+
+ return error;
+}
+
+/* ------------------------------------------------------------------- */
+/* upd_wrtcanon: Write a pass (hr) */
+/* ------------------------------------------------------------------- */
+
+#define LOW(b) ((b)&0xFF)
+#define HIGH(b) ((b)>>8)
+#define ESC 0x1B
+#define CR 0x0D
+
+static int
+upd_wrtcanon(upd_p upd, FILE *out)
+{
+ const updscan_p scan = upd->scnbuf[upd->yscan & upd->scnmsk];
+
+ int x, xend, icomp, ioutbuf, step, ioutbuf1;
+ byte *data;
+
+ /* Check length of the printable date */
+ xend = -1;
+ for(icomp = 0; icomp < upd->ocomp; ++icomp) {
+ data = scan[icomp].bytes;
+
+ for(x = upd->nbytes-1; 0 <= x; --x) if(data[x]) break;
+
+ if(x > xend) xend = x;
+ }
+
+ /* If some date to print */
+ if(0 <= xend) { /* Some data to write */
+ ioutbuf = 0;
+ xend += 1;
+
+ /* Perform vertical tab */
+ if(upd->yscan != upd->yprinter) {
+ step = upd->yscan - upd->yprinter;
+
+ fputc(ESC, out);
+ fputc('(', out);
+ fputc('e', out);
+ fputc(2, out);
+ fputc(0, out);
+ fputc(HIGH(step), out);
+ fputc(LOW(step), out);
+
+ upd->yprinter = upd->yscan;
+ }
+
+ for(icomp = 0; icomp < upd->ocomp; ++icomp) {
+
+ /* Are there date to print for the selected color component */
+ data = scan[icomp].bytes;
+ for(x = 0; x <= xend; ++x) if(data[x]) break;
+
+ /* Compressing of the scan line */
+ if(x <= xend) {
+ ioutbuf = upd_rle(upd->outbuf, scan[icomp].bytes, xend);
+ } else {
+ ioutbuf = 0;
+ }
+
+ ioutbuf1 = ioutbuf + 1;
+
+ /* prints the scan line */
+ fputc(ESC, out);
+ fputc('(', out);
+ fputc('A', out);
+ fputc(LOW(ioutbuf1), out);
+ fputc(HIGH(ioutbuf1), out);
+ switch(upd->ocomp) {
+ case 1: fputc('K',out); break;
+ case 3:
+ case 4: fputc("YMCK"[icomp],out); break;
+/*
+ * Please Note:
+ * the validity of the NCOMP-setting should be checked
+ * in the put_params-routine, thus the default-case is
+ * just a matter of coding-style.
+ */
+ default: fputc('K',out); break;
+ }
+
+ fwrite(upd->outbuf, 1, ioutbuf, out);
+
+ fputc(CR, out);
+ }
+
+ /* Printer advances one raster line */
+ fputc(ESC, out);
+ fputc('(', out);
+ fputc('e', out);
+ fputc(2, out);
+ fputc(0, out);
+ fputc(HIGH(1), out);
+ fputc(LOW(1), out);
+
+ upd->yprinter += 1;
+
+ }
+
+ /* Advance scan by one */
+ upd->yscan += 1;
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------- */
+/* All the Pixel-Get Routines */
+/* ------------------------------------------------------------------- */
+
+/* That bunch of Pixel-Get Routines */
+
+static upd_proc_pxlget(upd_pxlgetnix); /* A Dummy */
+
+static upd_proc_pxlget(upd_pxlget1f1); /* 1 Bit Forward */
+static upd_proc_pxlget(upd_pxlget1f2);
+static upd_proc_pxlget(upd_pxlget1f3);
+static upd_proc_pxlget(upd_pxlget1f4);
+static upd_proc_pxlget(upd_pxlget1f5);
+static upd_proc_pxlget(upd_pxlget1f6);
+static upd_proc_pxlget(upd_pxlget1f7);
+static upd_proc_pxlget(upd_pxlget1f8);
+
+static upd_proc_pxlget(upd_pxlget1r1); /* 1 Bit Reverse */
+static upd_proc_pxlget(upd_pxlget1r2);
+static upd_proc_pxlget(upd_pxlget1r3);
+static upd_proc_pxlget(upd_pxlget1r4);
+static upd_proc_pxlget(upd_pxlget1r5);
+static upd_proc_pxlget(upd_pxlget1r6);
+static upd_proc_pxlget(upd_pxlget1r7);
+static upd_proc_pxlget(upd_pxlget1r8);
+
+static upd_proc_pxlget(upd_pxlget2f1); /* 2 Bit Forward */
+static upd_proc_pxlget(upd_pxlget2f2);
+static upd_proc_pxlget(upd_pxlget2f3);
+static upd_proc_pxlget(upd_pxlget2f4);
+
+static upd_proc_pxlget(upd_pxlget2r1); /* 2 Bit Reverse */
+static upd_proc_pxlget(upd_pxlget2r2);
+static upd_proc_pxlget(upd_pxlget2r3);
+static upd_proc_pxlget(upd_pxlget2r4);
+
+static upd_proc_pxlget(upd_pxlget4f1); /* 4 Bit Forward */
+static upd_proc_pxlget(upd_pxlget4f2);
+
+static upd_proc_pxlget(upd_pxlget4r1); /* 4 Bit Reverse */
+static upd_proc_pxlget(upd_pxlget4r2);
+
+static upd_proc_pxlget(upd_pxlget8f); /* 8 Bit Forward */
+static upd_proc_pxlget(upd_pxlget8r); /* 8 Bit Reverse */
+
+static upd_proc_pxlget(upd_pxlget16f); /* 16 Bit Forward */
+static upd_proc_pxlget(upd_pxlget16r); /* 16Bit Reverse */
+
+static upd_proc_pxlget(upd_pxlget24f); /* 24 Bit Forward */
+static upd_proc_pxlget(upd_pxlget24r); /* 24 Bit Reverse */
+
+static upd_proc_pxlget(upd_pxlget32f); /* 32 Bit Forward */
+static upd_proc_pxlget(upd_pxlget32r); /* 32 Bit Reverse */
+
+/* Initialize Forward-Run */
+
+static uint32_t
+upd_pxlfwd(upd_p upd)
+{
+ if(!(upd->pxlptr = upd->gsscan)) {
+
+ upd->pxlget = upd_pxlgetnix;
+
+ } else {
+ switch(upd->int_a[IA_COLOR_INFO].data[1]) {
+ case 1: upd->pxlget = upd_pxlget1f1; break;
+ case 2: upd->pxlget = upd_pxlget2f1; break;
+ case 4: upd->pxlget = upd_pxlget4f1; break;
+ case 8: upd->pxlget = upd_pxlget8f; break;
+ case 16: upd->pxlget = upd_pxlget16f; break;
+ case 24: upd->pxlget = upd_pxlget24f; break;
+ case 32: upd->pxlget = upd_pxlget32f; break;
+ default:
+#if UPD_MESSAGES & UPD_M_ERROR
+ errprintf(upd->memory, "upd_pxlfwd: unsupported depth (%d)\n",
+ upd->int_a[IA_COLOR_INFO].data[1]);
+#endif
+ upd->pxlget = upd_pxlgetnix;
+ break;
+ }
+ }
+ return (uint32_t) 0;
+}
+
+/* 1 Bit Forward */
+
+static uint32_t
+upd_pxlget1f1(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1f2;
+ return *upd->pxlptr & 0x80 ? (uint32_t) 1 : (uint32_t) 0;
+}
+
+static uint32_t
+upd_pxlget1f2(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1f3;
+ return *upd->pxlptr & 0x40 ? (uint32_t) 1 : (uint32_t) 0;
+}
+
+static uint32_t
+upd_pxlget1f3(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1f4;
+ return *upd->pxlptr & 0x20 ? (uint32_t) 1 : (uint32_t) 0;
+}
+
+static uint32_t
+upd_pxlget1f4(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1f5;
+ return *upd->pxlptr & 0x10 ? (uint32_t) 1 : (uint32_t) 0;
+}
+
+static uint32_t
+upd_pxlget1f5(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1f6;
+ return *upd->pxlptr & 0x08 ? (uint32_t) 1 : (uint32_t) 0;
+}
+
+static uint32_t
+upd_pxlget1f6(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1f7;
+ return *upd->pxlptr & 0x04 ? (uint32_t) 1 : (uint32_t) 0;
+}
+
+static uint32_t
+upd_pxlget1f7(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1f8;
+ return *upd->pxlptr & 0x02 ? (uint32_t) 1 : (uint32_t) 0;
+}
+
+static uint32_t
+upd_pxlget1f8(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1f1;
+ return *upd->pxlptr++ & 0x01 ? (uint32_t) 1 : (uint32_t) 0;
+}
+
+/* 2 Bit Forward */
+
+static uint32_t
+upd_pxlget2f1(upd_p upd)
+{
+ upd->pxlget = upd_pxlget2f2;
+ return ((uint32_t) (*upd->pxlptr ) & (uint32_t) 0xC0) >> 6;
+}
+
+static uint32_t
+upd_pxlget2f2(upd_p upd)
+{
+ upd->pxlget = upd_pxlget2f3;
+ return ((uint32_t) (*upd->pxlptr ) & (uint32_t) 0x30) >> 4;
+}
+
+static uint32_t
+upd_pxlget2f3(upd_p upd)
+{
+ upd->pxlget = upd_pxlget2f4;
+ return ((uint32_t) (*upd->pxlptr ) & (uint32_t) 0x0C) >> 2;
+}
+
+static uint32_t
+upd_pxlget2f4(upd_p upd)
+{
+ upd->pxlget = upd_pxlget2f1;
+ return (uint32_t) (*upd->pxlptr++) & (uint32_t) 0x03;
+}
+
+/* 4 Bit Forward */
+static uint32_t
+upd_pxlget4f1(upd_p upd)
+{
+ upd->pxlget = upd_pxlget4f2;
+ return ((uint32_t) (*upd->pxlptr ) & (uint32_t) 0xF0) >> 4;
+}
+
+static uint32_t
+upd_pxlget4f2(upd_p upd)
+{
+ upd->pxlget = upd_pxlget4f1;
+ return (uint32_t) (*upd->pxlptr++) & (uint32_t) 0x0F;
+}
+
+/* 8 Bit Forward */
+static uint32_t
+upd_pxlget8f(upd_p upd)
+{
+ return (uint32_t) (*upd->pxlptr++);
+}
+
+/* 16 Bit Forward */
+static uint32_t
+upd_pxlget16f(upd_p upd)
+{
+ uint32_t ci = (uint32_t) (*upd->pxlptr++) << 8;
+ ci |= *upd->pxlptr++;
+ return ci;
+}
+
+/* 24 Bit Forward */
+static uint32_t
+upd_pxlget24f(upd_p upd)
+{
+ uint32_t ci = (uint32_t) (*upd->pxlptr++) << 16;
+ ci |= (uint32_t) (*upd->pxlptr++) << 8;
+ ci |= *upd->pxlptr++;
+ return ci;
+}
+
+/* 32 Bit Forward */
+static uint32_t
+upd_pxlget32f(upd_p upd)
+{
+ uint32_t ci = (uint32_t) (*upd->pxlptr++) << 24;
+ ci |= (uint32_t) (*upd->pxlptr++) << 16;
+ ci |= (uint32_t) (*upd->pxlptr++) << 8;
+ ci |= *upd->pxlptr++;
+ return ci;
+}
+
+/* Dummy-Routine */
+
+static uint32_t
+upd_pxlgetnix(upd_p upd)
+{
+ return (uint32_t) 0;
+}
+
+/* Initialize Reverse-Run */
+
+static uint32_t
+upd_pxlrev(upd_p upd)
+{
+ const uint width = upd->pwidth < upd->gswidth ? upd->pwidth : upd->gswidth;
+
+ if(!(upd->pxlptr = upd->gsscan)) {
+
+ upd->pxlget = upd_pxlgetnix;
+
+ } else {
+ uint32_t ofs = (uint32_t) upd->int_a[IA_COLOR_INFO].data[1] * (width-1);
+
+ upd->pxlptr += ofs>>3;
+
+ ofs &= 7;
+
+ switch(upd->int_a[IA_COLOR_INFO].data[1]) {
+ case 1: switch(ofs) {
+ case 0: upd->pxlget = upd_pxlget1r1; break;
+ case 1: upd->pxlget = upd_pxlget1r2; break;
+ case 2: upd->pxlget = upd_pxlget1r3; break;
+ case 3: upd->pxlget = upd_pxlget1r4; break;
+ case 4: upd->pxlget = upd_pxlget1r5; break;
+ case 5: upd->pxlget = upd_pxlget1r6; break;
+ case 6: upd->pxlget = upd_pxlget1r7; break;
+ case 7: upd->pxlget = upd_pxlget1r8; break;
+ } break;
+ case 2: switch(ofs) {
+ case 0: upd->pxlget = upd_pxlget2r1; break;
+ case 2: upd->pxlget = upd_pxlget2r2; break;
+ case 4: upd->pxlget = upd_pxlget2r3; break;
+ case 6: upd->pxlget = upd_pxlget2r4; break;
+ } break;
+ case 4: switch(ofs) {
+ case 0: upd->pxlget = upd_pxlget4r1; break;
+ case 4: upd->pxlget = upd_pxlget4r2; break;
+ } break;
+ case 8: upd->pxlget = upd_pxlget8r; break;
+ case 16:
+ upd->pxlget = upd_pxlget16r;
+ upd->pxlptr += 1;
+ break;
+ case 24:
+ upd->pxlget = upd_pxlget24r;
+ upd->pxlptr += 2;
+ break;
+ case 32:
+ upd->pxlget = upd_pxlget32r;
+ upd->pxlptr += 3;
+ break;
+ default:
+#if UPD_MESSAGES & UPD_M_ERROR
+ errprintf(upd->memory, "upd_pxlrev: unsupported depth (%d)\n",
+ upd->int_a[IA_COLOR_INFO].data[1]);
+#endif
+ upd->pxlget = upd_pxlgetnix;
+ break;
+ }
+ }
+ return (uint32_t) 0;
+}
+
+/* 1 Bit Reverse */
+
+static uint32_t
+upd_pxlget1r1(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1r8;
+ return *upd->pxlptr-- & 0x80 ? (uint32_t) 1 : (uint32_t) 0;
+}
+
+static uint32_t
+upd_pxlget1r2(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1r1;
+ return *upd->pxlptr & 0x40 ? (uint32_t) 1 : (uint32_t) 0;
+}
+
+static uint32_t
+upd_pxlget1r3(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1r2;
+ return *upd->pxlptr & 0x20 ? (uint32_t) 1 : (uint32_t) 0;
+}
+
+static uint32_t
+upd_pxlget1r4(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1r3;
+ return *upd->pxlptr & 0x10 ? (uint32_t) 1 : (uint32_t) 0;
+}
+
+static uint32_t
+upd_pxlget1r5(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1r4;
+ return *upd->pxlptr & 0x08 ? (uint32_t) 1 : (uint32_t) 0;
+}
+
+static uint32_t
+upd_pxlget1r6(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1r5;
+ return *upd->pxlptr & 0x04 ? (uint32_t) 1 : (uint32_t) 0;
+}
+
+static uint32_t
+upd_pxlget1r7(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1r6;
+ return *upd->pxlptr & 0x02 ? (uint32_t) 1 : (uint32_t) 0;
+}
+
+static uint32_t
+upd_pxlget1r8(upd_p upd)
+{
+ upd->pxlget = upd_pxlget1r7;
+ return *upd->pxlptr & 0x01 ? (uint32_t) 1 : (uint32_t) 0;
+}
+
+/* 2 Bit Reverse */
+
+static uint32_t
+upd_pxlget2r1(upd_p upd)
+{
+ upd->pxlget = upd_pxlget2r4;
+ return ((uint32_t) (*upd->pxlptr--) & (uint32_t) 0xC0) >> 6;
+}
+
+static uint32_t
+upd_pxlget2r2(upd_p upd)
+{
+ upd->pxlget = upd_pxlget2r1;
+ return ((uint32_t) (*upd->pxlptr ) & (uint32_t) 0x30) >> 4;
+}
+
+static uint32_t
+upd_pxlget2r3(upd_p upd)
+{
+ upd->pxlget = upd_pxlget2r2;
+ return ((uint32_t) (*upd->pxlptr ) & (uint32_t) 0x0C) >> 2;
+}
+
+static uint32_t
+upd_pxlget2r4(upd_p upd)
+{
+ upd->pxlget = upd_pxlget2r3;
+ return (uint32_t) (*upd->pxlptr ) & (uint32_t) 0x03;
+}
+
+/* 4 Bit Reverse */
+
+static uint32_t
+upd_pxlget4r1(upd_p upd)
+{
+ upd->pxlget = upd_pxlget4r2;
+ return ((uint32_t) (*upd->pxlptr--) & (uint32_t) 0xF0) >> 4;
+}
+
+static uint32_t
+upd_pxlget4r2(upd_p upd)
+{
+ upd->pxlget = upd_pxlget4r1;
+ return (uint32_t) (*upd->pxlptr ) & (uint32_t) 0x0F;
+}
+
+/* 8 Bit Reverse */
+static uint32_t
+upd_pxlget8r(upd_p upd)
+{
+ return (uint32_t) (*upd->pxlptr--);
+}
+
+/* 16 Bit Reverse */
+static uint32_t
+upd_pxlget16r(upd_p upd)
+{
+ uint32_t ci = *upd->pxlptr--;
+ ci |= (uint32_t) (*upd->pxlptr--) << 8;
+ return ci;
+}
+
+/* 24 Bit Reverse */
+static uint32_t
+upd_pxlget24r(upd_p upd)
+{
+ uint32_t ci = *upd->pxlptr--;
+ ci |= (uint32_t) (*upd->pxlptr--) << 8;
+ ci |= (uint32_t) (*upd->pxlptr--) << 16;
+ return ci;
+}
+
+/* 32 Bit Reverse */
+static uint32_t
+upd_pxlget32r(upd_p upd)
+{
+ uint32_t ci = *upd->pxlptr--;
+ ci |= (uint32_t) (*upd->pxlptr--) << 8;
+ ci |= (uint32_t) (*upd->pxlptr--) << 16;
+ ci |= (uint32_t) (*upd->pxlptr--) << 24;
+ return ci;
+}