diff options
Diffstat (limited to 'devices/gdevupd.c')
-rw-r--r-- | devices/gdevupd.c | 7620 |
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; +} |