/* Copyright (C) 1997-2004 artofcode LLC. 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. For more information about licensing, please refer to http://www.ghostscript.com/licensing/. For information on commercial licensing, go to http://www.artifex.com/licensing/ or contact Artifex Software, Inc., 101 Lucas Valley Road #110, San Rafael, CA 94903, U.S.A., +1(415)492-9861. */ /* $Id: gdevupd.c,v 1.16 2004/08/04 19:36:12 stefan Exp $ */ /* 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 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 */ /* ------------------------------------------------------------------- */ /* 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 /** for rand */ #include /** for INT_MIN */ #include /** for isupper */ #endif /* hess_test_INCLUDED A private test-Option */ #if UPD_SIGNAL #include /** 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 _device> */ /* ------------------------------------------------------------------- */ /* Major Driver-Functions */ /* ------------------------------------------------------------------- */ private dev_proc_print_page(upd_print_page); /** print a page (required) */ private dev_proc_open_device(upd_open); /** device-initialization (opt) */ private dev_proc_close_device(upd_close); /** device-release (opt) */ private dev_proc_get_params(upd_get_params); /** export parameters (opt) */ private 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. */ private dev_proc_encode_color( upd_rgb_1color); /** Gray-Gray->Index */ private dev_proc_decode_color( upd_1color_rgb); /** Gray-Index->Gray */ private dev_proc_encode_color( upd_rgb_3color); /** RGB->RGB-Index */ private 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! */ private dev_proc_encode_color( upd_rgb_4color); /** RGB->WRGB-Index */ private 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! */ private dev_proc_encode_color(upd_cmyk_icolor); /** KCMY->KCMY-Index */ private 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. */ private dev_proc_encode_color(upd_cmyk_kcolor); /** adds black generation */ private 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) */ private 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) */ private 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. */ private 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)) private 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 (1cmap + 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. */ private void upd_open_render( upd_device *udev); private void upd_close_render( upd_device *udev); private void upd_open_fscomp( upd_device *udev); private int upd_fscomp( upd_p upd); private void upd_close_fscomp( upd_device *udev); private void upd_open_fscmyk( upd_device *udev); private int upd_fscmyk( upd_p upd); private void upd_open_fscmy_k( upd_device *udev); private 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). */ private int upd_open_writer( upd_device *udev); private void upd_close_writer( upd_device *udev); #if UPD_SIGNAL private 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. */ private int upd_open_rascomp( upd_device *udev); private int upd_start_rascomp( upd_p upd, FILE *out); private 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. */ private void upd_limits( upd_p upd, bool check); private int upd_open_wrtescp( upd_device *udev); private 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 */ private int upd_rle(byte *out,const byte *in,int nbytes); private int upd_open_wrtescp2( upd_device *udev); private int upd_wrtescp2( upd_p upd, FILE *out); private int upd_wrtescp2x( upd_p upd, FILE *out); /** The fifth writer is a HP-RTL/PCL-Writer */ private int upd_open_wrtrtl( upd_device *udev); private int upd_wrtrtl( upd_p upd, FILE *out); /** The sixth writer is for Canon Extended Mode (currently BJC610) (hr) */ private int upd_open_wrtcanon( upd_device *udev); private int upd_wrtcanon( upd_p upd, FILE *out); /** The seventh writer is for ESC P/2 Nozzle Map Mode (currently Stylus Color 300) (GR) */ private int upd_wrtescnm( upd_p upd, FILE *out); /** Generalized Pixel Get & Read */ private uint32_t upd_pxlfwd(upd_p upd); private uint32_t upd_pxlrev(upd_p upd); #define upd_pxlget(UPD) (*UPD->pxlget)(UPD) private 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: 1.16 $"; /** Default-Transfer-curve */ static const float upd_data_xfer[2] = { 0.0, 1.0 }; /*@ > */ /* ------------------------------------------------------------------- */ /* upd_cast: keeps some compilers more happy [dangerous] */ /* ------------------------------------------------------------------- */ private void * upd_cast(const void *data) { return (void *) data; } /* ------------------------------------------------------------------- */ /* upd_signal_handler: Catch interrupts */ /* ------------------------------------------------------------------- */ #if UPD_SIGNAL static upd_p sigupd = NULL; private 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. */ private 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("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("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("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("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("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 */ if((NULL != udev->fname ) && strchr(udev->fname,'%')) { 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("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. */ private int upd_open(gx_device *pdev) { upd_device *const udev = (upd_device *) pdev; const upd_p upd = udev->upd; int error; #if UPD_MESSAGES & UPD_M_TOPCALLS errprintf("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) ) { static 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); /** 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("\nupd->flags = 0x%05lx\n",(unsigned long)upd->flags); errprintf( "upd->pdwidth = %5d\n",upd->pdwidth); errprintf( "upd->pdheight = %5d\n",upd->pdheight); errprintf( "upd->ngsbuf = %5u\n",upd->ngsbuf); errprintf( "upd->gswidth = %5d\n",upd->gswidth); errprintf( "upd->gsheight = %5d\n",upd->gsheight); errprintf( "upd->rwidth = %5d\n",upd->rwidth); errprintf( "upd->pwidth = %5d\n",upd->pwidth); errprintf( "upd->pheight = %5d\n",upd->pheight); errprintf( "upd->nvalbuf = %5u\n",upd->nvalbuf); errprintf( "upd->nscnbuf = %5d\n",upd->nscnbuf); errprintf( "upd->ncomp = %5d\n",upd->ncomp); errprintf( "upd->ocomp = %5d\n",upd->ocomp); errprintf( "upd->nbytes = %5d\n",upd->nbytes); errprintf( "upd->nlimits = %5d\n",upd->nlimits); errprintf( "upd->scnmsk = %5d\n",upd->scnmsk); errprintf( "upd->noutbuf = %5u\n",upd->noutbuf); errprintf( "upd->ixpass = %5d\n",upd->ixpass); errprintf( "upd->ipass = %5d\n",upd->ipass); errprintf( "upd->icomp = %5d\n",upd->icomp); errprintf( "upd->lf = %5d\n",upd->lf); errprintf( "upd->xprinter = %5d\n",upd->xprinter); errprintf( "upd->yscan = %5d\n",upd->yscan); errprintf( "upd->yprinter = %5d\n",upd->yprinter); errprintf( "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("%*s = %-*s (%2d)\n",ln,upd_choice[i][0], lv,upd_choice[i][upd->choice[i]],upd->choice[i]); } else { errprintf("%*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("%*s = %s\n",ln,upd_flags[i], ((uint32_t) 1 << i) & upd->flags ? "true" : "false"); } else { errprintf("%*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("%*s = %5d\n",ln,upd_ints[i],upd->ints[i]); } else { errprintf("%*s[%2d] = %5d\n",ln-4,"upd_ints",i,upd->ints[i]); } } } errprintf("\n%sready to print\n\n", B_OK4GO != (upd->flags & (B_OK4GO | B_ERROR)) ? "NOT " : ""); #endif } #if UPD_MESSAGES & UPD_M_TOPCALLS errprintf("RETURN: %d = upd_open(0x%05lx)\n", error,(long) pdev); #endif return error; } /* ------------------------------------------------------------------- */ /* upd_close: Release everything allocated in upd_open */ /* ------------------------------------------------------------------- */ private 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("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("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("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 private 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("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("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 */ /* ------------------------------------------------------------------- */ private 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("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) \ 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( \ "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) \ 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) /** 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); 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); 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); 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); 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); 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); 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); 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; 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("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. */ private 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( "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 */ /* ------------------------------------------------------------------- */ private 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( "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 */ /* ------------------------------------------------------------------- */ private 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( "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 */ /* ------------------------------------------------------------------- */ private 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("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 */ /* ------------------------------------------------------------------- */ private 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( "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 */ /* ------------------------------------------------------------------- */ private 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( "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 */ /* ------------------------------------------------------------------- */ private 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( "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 */ /* ------------------------------------------------------------------- */ private 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( "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 */ /* ------------------------------------------------------------------- */ private 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( "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 */ /* ------------------------------------------------------------------- */ private 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( "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 */ /* ------------------------------------------------------------------- */ private 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( "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 */ /* ------------------------------------------------------------------- */ private 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( "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. */ /* ------------------------------------------------------------------- */ private 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 */ /* ------------------------------------------------------------------- */ private 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( "upd_open_map: unsupported %s=%d\n", upd_choice[C_MAPPER][0],upd->choice[C_MAPPER]); else errprintf( "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( "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( "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( "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("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( "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 */ /* ------------------------------------------------------------------- */ private 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 */ /* ------------------------------------------------------------------- */ private 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 */ /* ------------------------------------------------------------------- */ private 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("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 */ /* ------------------------------------------------------------------- */ private 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 private 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( "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( "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( "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( "Values for %d. Component after %d iterations\n",comp->cmap+1,i); errprintf( "steps: %10ld, Bits: %d\n",(long) comp->bitmsk,comp->bits); errprintf( "xfer: %10d Points, %s\n", upd->float_a[upd->cmap[comp->cmap].xfer].size, upd->cmap[comp->cmap].rise ? "rising" : "falling"); errprintf( "offset: %10d 0x%08x\n",comp->offset,comp->offset); errprintf( "scale: %10d 0x%08x\n",comp->scale,comp->scale); errprintf( "threshold: %10d 0x%08x\n",comp->threshold,comp->threshold); errprintf( "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 */ /* ------------------------------------------------------------------- */ private 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("%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 */ private 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<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 */ /* ------------------------------------------------------------------- */ private 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 */ /* ------------------------------------------------------------------- */ private 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 */ /* ------------------------------------------------------------------- */ private 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 */ /* ------------------------------------------------------------------- */ private 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 */ /* ------------------------------------------------------------------- */ private 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( "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( "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( "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( "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( "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( "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( "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( "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( "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( "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( "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("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 */ /* ------------------------------------------------------------------- */ private 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 */ /* ------------------------------------------------------------------- */ private 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 */ /* ------------------------------------------------------------------- */ private 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 private 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<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<cmap[0].comp)) { rgbval = 0xffffff; } else { if(entry & (1<cmap[1].comp)) rgbval |= 0xff0000; if(entry & (1<cmap[2].comp)) rgbval |= 0x00ff00; if(entry & (1<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 */ /* ------------------------------------------------------------------- */ private 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 */ /* ------------------------------------------------------------------- */ private 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( "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( "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( "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( "ESC/P-Open: %ld is unreasonable size of Outputbuffer\n", (long) noutbuf); #endif } } return error; } /* ------------------------------------------------------------------- */ /* upd_wrtescp: Write a pass */ /* ------------------------------------------------------------------- */ private 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 */ /* ------------------------------------------------------------------- */ private 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( "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( "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( "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( "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( "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( "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 */ /* ------------------------------------------------------------------- */ private 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 */ private 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 */ /* ------------------------------------------------------------------- */ private 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 */ /* ------------------------------------------------------------------- */ private 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 */ /* ------------------------------------------------------------------- */ private 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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("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( "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) { 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( "PCL-Open: %ld is unreasonable size of Outputbuffer\n", (long) noutbuf); #endif } } return error; } /* ------------------------------------------------------------------- */ /* upd_wrtrtl: Write a pass */ /* ------------------------------------------------------------------- */ private 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) { 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) { 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) */ /* ------------------------------------------------------------------- */ private 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 private 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 */ private upd_proc_pxlget(upd_pxlgetnix); /* A Dummy */ private upd_proc_pxlget(upd_pxlget1f1); /* 1 Bit Forward */ private upd_proc_pxlget(upd_pxlget1f2); private upd_proc_pxlget(upd_pxlget1f3); private upd_proc_pxlget(upd_pxlget1f4); private upd_proc_pxlget(upd_pxlget1f5); private upd_proc_pxlget(upd_pxlget1f6); private upd_proc_pxlget(upd_pxlget1f7); private upd_proc_pxlget(upd_pxlget1f8); private upd_proc_pxlget(upd_pxlget1r1); /* 1 Bit Reverse */ private upd_proc_pxlget(upd_pxlget1r2); private upd_proc_pxlget(upd_pxlget1r3); private upd_proc_pxlget(upd_pxlget1r4); private upd_proc_pxlget(upd_pxlget1r5); private upd_proc_pxlget(upd_pxlget1r6); private upd_proc_pxlget(upd_pxlget1r7); private upd_proc_pxlget(upd_pxlget1r8); private upd_proc_pxlget(upd_pxlget2f1); /* 2 Bit Forward */ private upd_proc_pxlget(upd_pxlget2f2); private upd_proc_pxlget(upd_pxlget2f3); private upd_proc_pxlget(upd_pxlget2f4); private upd_proc_pxlget(upd_pxlget2r1); /* 2 Bit Reverse */ private upd_proc_pxlget(upd_pxlget2r2); private upd_proc_pxlget(upd_pxlget2r3); private upd_proc_pxlget(upd_pxlget2r4); private upd_proc_pxlget(upd_pxlget4f1); /* 4 Bit Forward */ private upd_proc_pxlget(upd_pxlget4f2); private upd_proc_pxlget(upd_pxlget4r1); /* 4 Bit Reverse */ private upd_proc_pxlget(upd_pxlget4r2); private upd_proc_pxlget(upd_pxlget8f); /* 8 Bit Forward */ private upd_proc_pxlget(upd_pxlget8r); /* 8 Bit Reverse */ private upd_proc_pxlget(upd_pxlget16f); /* 16 Bit Forward */ private upd_proc_pxlget(upd_pxlget16r); /* 16Bit Reverse */ private upd_proc_pxlget(upd_pxlget24f); /* 24 Bit Forward */ private upd_proc_pxlget(upd_pxlget24r); /* 24 Bit Reverse */ private upd_proc_pxlget(upd_pxlget32f); /* 32 Bit Forward */ private upd_proc_pxlget(upd_pxlget32r); /* 32 Bit Reverse */ /* Initialize Forward-Run */ private 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_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 */ private uint32_t upd_pxlget1f1(upd_p upd) { upd->pxlget = upd_pxlget1f2; return *upd->pxlptr & 0x80 ? (uint32_t) 1 : (uint32_t) 0; } private uint32_t upd_pxlget1f2(upd_p upd) { upd->pxlget = upd_pxlget1f3; return *upd->pxlptr & 0x40 ? (uint32_t) 1 : (uint32_t) 0; } private uint32_t upd_pxlget1f3(upd_p upd) { upd->pxlget = upd_pxlget1f4; return *upd->pxlptr & 0x20 ? (uint32_t) 1 : (uint32_t) 0; } private uint32_t upd_pxlget1f4(upd_p upd) { upd->pxlget = upd_pxlget1f5; return *upd->pxlptr & 0x10 ? (uint32_t) 1 : (uint32_t) 0; } private uint32_t upd_pxlget1f5(upd_p upd) { upd->pxlget = upd_pxlget1f6; return *upd->pxlptr & 0x08 ? (uint32_t) 1 : (uint32_t) 0; } private uint32_t upd_pxlget1f6(upd_p upd) { upd->pxlget = upd_pxlget1f7; return *upd->pxlptr & 0x04 ? (uint32_t) 1 : (uint32_t) 0; } private uint32_t upd_pxlget1f7(upd_p upd) { upd->pxlget = upd_pxlget1f8; return *upd->pxlptr & 0x02 ? (uint32_t) 1 : (uint32_t) 0; } private uint32_t upd_pxlget1f8(upd_p upd) { upd->pxlget = upd_pxlget1f1; return *upd->pxlptr++ & 0x01 ? (uint32_t) 1 : (uint32_t) 0; } /* 2 Bit Forward */ private uint32_t upd_pxlget2f1(upd_p upd) { upd->pxlget = upd_pxlget2f2; return ((uint32_t) (*upd->pxlptr ) & (uint32_t) 0xC0) >> 6; } private uint32_t upd_pxlget2f2(upd_p upd) { upd->pxlget = upd_pxlget2f3; return ((uint32_t) (*upd->pxlptr ) & (uint32_t) 0x30) >> 4; } private uint32_t upd_pxlget2f3(upd_p upd) { upd->pxlget = upd_pxlget2f4; return ((uint32_t) (*upd->pxlptr ) & (uint32_t) 0x0C) >> 2; } private uint32_t upd_pxlget2f4(upd_p upd) { upd->pxlget = upd_pxlget2f1; return (uint32_t) (*upd->pxlptr++) & (uint32_t) 0x03; } /* 4 Bit Forward */ private uint32_t upd_pxlget4f1(upd_p upd) { upd->pxlget = upd_pxlget4f2; return ((uint32_t) (*upd->pxlptr ) & (uint32_t) 0xF0) >> 4; } private uint32_t upd_pxlget4f2(upd_p upd) { upd->pxlget = upd_pxlget4f1; return (uint32_t) (*upd->pxlptr++) & (uint32_t) 0x0F; } /* 8 Bit Forward */ private uint32_t upd_pxlget8f(upd_p upd) { return (uint32_t) (*upd->pxlptr++); } /* 16 Bit Forward */ private uint32_t upd_pxlget16f(upd_p upd) { uint32_t ci = (uint32_t) (*upd->pxlptr++) << 8; ci |= *upd->pxlptr++; return ci; } /* 24 Bit Forward */ private 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 */ private 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 */ private uint32_t upd_pxlgetnix(upd_p upd) { return (uint32_t) 0; } /* Initialize Reverse-Run */ private 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_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 */ private uint32_t upd_pxlget1r1(upd_p upd) { upd->pxlget = upd_pxlget1r8; return *upd->pxlptr-- & 0x80 ? (uint32_t) 1 : (uint32_t) 0; } private uint32_t upd_pxlget1r2(upd_p upd) { upd->pxlget = upd_pxlget1r1; return *upd->pxlptr & 0x40 ? (uint32_t) 1 : (uint32_t) 0; } private uint32_t upd_pxlget1r3(upd_p upd) { upd->pxlget = upd_pxlget1r2; return *upd->pxlptr & 0x20 ? (uint32_t) 1 : (uint32_t) 0; } private uint32_t upd_pxlget1r4(upd_p upd) { upd->pxlget = upd_pxlget1r3; return *upd->pxlptr & 0x10 ? (uint32_t) 1 : (uint32_t) 0; } private uint32_t upd_pxlget1r5(upd_p upd) { upd->pxlget = upd_pxlget1r4; return *upd->pxlptr & 0x08 ? (uint32_t) 1 : (uint32_t) 0; } private uint32_t upd_pxlget1r6(upd_p upd) { upd->pxlget = upd_pxlget1r5; return *upd->pxlptr & 0x04 ? (uint32_t) 1 : (uint32_t) 0; } private uint32_t upd_pxlget1r7(upd_p upd) { upd->pxlget = upd_pxlget1r6; return *upd->pxlptr & 0x02 ? (uint32_t) 1 : (uint32_t) 0; } private uint32_t upd_pxlget1r8(upd_p upd) { upd->pxlget = upd_pxlget1r7; return *upd->pxlptr & 0x01 ? (uint32_t) 1 : (uint32_t) 0; } /* 2 Bit Reverse */ private uint32_t upd_pxlget2r1(upd_p upd) { upd->pxlget = upd_pxlget2r4; return ((uint32_t) (*upd->pxlptr--) & (uint32_t) 0xC0) >> 6; } private uint32_t upd_pxlget2r2(upd_p upd) { upd->pxlget = upd_pxlget2r1; return ((uint32_t) (*upd->pxlptr ) & (uint32_t) 0x30) >> 4; } private uint32_t upd_pxlget2r3(upd_p upd) { upd->pxlget = upd_pxlget2r2; return ((uint32_t) (*upd->pxlptr ) & (uint32_t) 0x0C) >> 2; } private uint32_t upd_pxlget2r4(upd_p upd) { upd->pxlget = upd_pxlget2r3; return (uint32_t) (*upd->pxlptr ) & (uint32_t) 0x03; } /* 4 Bit Reverse */ private uint32_t upd_pxlget4r1(upd_p upd) { upd->pxlget = upd_pxlget4r2; return ((uint32_t) (*upd->pxlptr--) & (uint32_t) 0xF0) >> 4; } private uint32_t upd_pxlget4r2(upd_p upd) { upd->pxlget = upd_pxlget4r1; return (uint32_t) (*upd->pxlptr ) & (uint32_t) 0x0F; } /* 8 Bit Reverse */ private uint32_t upd_pxlget8r(upd_p upd) { return (uint32_t) (*upd->pxlptr--); } /* 16 Bit Reverse */ private uint32_t upd_pxlget16r(upd_p upd) { uint32_t ci = *upd->pxlptr--; ci |= (uint32_t) (*upd->pxlptr--) << 8; return ci; } /* 24 Bit Reverse */ private 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 */ private 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; }