home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 2 / AACD 2.iso / AACD / Magazine / UsingPDF / GhostScript / source / gs5.10 / gdevupd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-30  |  210.4 KB  |  6,270 lines

  1. /* Copyright (C) 1997 Aladdin Enterprises.  All rights reserved.
  2.  
  3.   This file is part of Aladdin Ghostscript.
  4.  
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.  
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevupd.c $Revision: 1.77 $ */
  20. /* "uniprint" -- Ugly Printer Driver by Gunther Hess (gunther@elmos.de) */
  21.  
  22. /* Revision-History:
  23.    23-Mar-1997 -  1.43: First published version
  24.    24-Mar-1997 -  1.44: gs4.03 compatible version on the web
  25.    31-Mar-1997 -  1.53: First Version inside gs-fileset (limited)
  26.    28-Apr-1997 -  1.54: Version intended for public gs-release
  27.     4-May-1997 -  1.55: Deactivated an accidentially active Debug-Option
  28.    14-Jun-1997 -  1.56: Bug-Workaround for White on White Printing (gs5.0)
  29.    17-Jun-1997 -  1.57: More reasonable Fix for the above Bug
  30.    ...
  31.     7-Jul-1997 -  1.68: NULL-Param-BUG, HR's BJC, Pwidth/-height BUG, YFlip
  32.    25-Jul-1997 -  1.69: Bug-Fix: incomplete Change of PHEIGHT-Treatment
  33.     4-Aug-1997 -  1.70: Arrgh: still incomplete Change of PHEIGHT-Treatment
  34.    17-AUG-1997 -  1.71: Fix of BSD-sprintf bug. (returns char * there)
  35.    ...
  36.    28-Sep-1977 -  1.77: Fixed the byte<>char and casted-lvalue Problems
  37. */
  38.  
  39. /* Canon BJC 610 additions from (hr)
  40.       Helmut Riegler <helmut-riegler@net4you.co.at>
  41.  
  42.    The BJC-4000 can be supported very easily, only by creating the right .upp
  43.    parameter file. If you have this printer and you are willing to do this,
  44.    contact me, I'll give you the technical details (ESC codes).
  45. */
  46.  
  47. /* ------------------------------------------------------------------- */
  48. /* Compile-Time-Options                                                */
  49. /* ------------------------------------------------------------------- */
  50.  
  51. /**
  52. There are two compile-time options for this driver:
  53.    1. UPD_SIGNAL   enables interrupt detection, that aborts printing and
  54.    2. UPD_MESSAGES controls the amount of messages generated by the driver
  55. */
  56.  
  57. #ifndef   UPD_SIGNAL
  58. #ifdef      __unix__
  59. #define       UPD_SIGNAL 1 /** Activated, if undefined, on UNIX-Systems */
  60. #else  /*  !__unix__ */
  61. #define       UPD_SIGNAL 0 /** Inactive on others, by default */
  62. #endif /*  ?__unix__ */
  63. #endif /* UPD_SIGNAL */
  64.  
  65. #ifndef   UPD_MESSAGES
  66. #define   UPD_MESSAGES UPD_M_ERROR /** Error-messages only, if not defined */
  67. #endif /* UPD_MESSAGES */
  68.  
  69. /* ------------------------------------------------------------------- */
  70. /* Required Header-Files                                               */
  71. /* ------------------------------------------------------------------- */
  72.  
  73. #ifndef   hess_test_INCLUDED /* A private test-Option */
  74.  
  75. #include "gdevprn.h" /** Printer-superclass header */
  76. #include "gsparam.h" /** For the Parameter-Handling (optional) */
  77.  
  78. #include <stdlib.h> /** for rand */
  79. #include <limits.h> /** for INT_MIN */
  80. #include <ctype.h>  /** for isupper */
  81.  
  82. #endif /* hess_test_INCLUDED    A private test-Option */
  83.  
  84. #if       UPD_SIGNAL
  85. #include <signal.h> /** Only included, if UPD_SIGNAL is active (true) */
  86. #endif /* UPD_SIGNAL */
  87.  
  88. /* ------------------------------------------------------------------- */
  89. /* Device-Structure (including an additional Structure-Pointer-Type)   */
  90. /* ------------------------------------------------------------------- */
  91.  
  92. typedef struct upd_s upd_t,*upd_p; /** Type & Pointer of device-specifics */
  93. typedef const upd_t *upd_pc;       /** Pointer to constant device-specfics */
  94.  
  95. typedef struct upd_device_s {      /** The driver must typedef ... */
  96.    gx_device_common;               /**    common fields for all devices */
  97.    gx_prn_device_common;           /**    common fields for printing-devices */
  98.    gs_param_string upd_version;    /**    Source-Code Version */
  99.    upd_p           upd;            /**    uniprint-specific extension */
  100. } upd_device;                      /** some type usually  <name>_device> */
  101.  
  102. /* ------------------------------------------------------------------- */
  103. /* Major Driver-Functions                                              */
  104. /* ------------------------------------------------------------------- */
  105.  
  106. private dev_proc_print_page(upd_print_page); /** print a page (required) */
  107.  
  108. private dev_proc_open_device(upd_open);      /** device-initialization (opt) */
  109. private dev_proc_close_device(upd_close);    /** device-release (opt) */
  110.  
  111. private dev_proc_get_params(upd_get_params); /** export parameters (opt) */
  112. private dev_proc_put_params(upd_put_params); /** import parameters (opt) */
  113.  
  114. /**
  115. A `normal' Device-Driver wil only implement one of the following pairs
  116. of functions for the colormapping. But "uniprint" is something special and
  117. it really provides all four reasonable pairs and in addition to that
  118. a fifth set of functions, that delivers better FS-Results with KCMY.
  119.  
  120. The first pair is for the mapping into a single stored component, that
  121. usually represents a grayscale. But nevertheless GHOSTSCRIPT deals with
  122. RGB-Values, but promises to deal with R==G==B-Values when asking to map.
  123.  
  124. The second pair deals with RGB-Values.
  125. */
  126.  
  127. private dev_proc_map_rgb_color( upd_rgb_1color);  /** RGB->Gray-Index */
  128. private dev_proc_map_color_rgb( upd_1color_rgb);  /** Gray-Index->RGB */
  129.  
  130. private dev_proc_map_rgb_color( upd_rgb_3color);  /** RGB->RGB-Index */
  131. private dev_proc_map_color_rgb( upd_3color_rgb);  /** RGB-Index->RGB */
  132.  
  133. /**
  134. The third pair maps RGB-Values into four components, which one might
  135. expect to be KCMY-Values, but they are not: "uniprint" considers this four
  136. Values as White+RGB Values!
  137. */
  138.  
  139. private dev_proc_map_rgb_color( upd_rgb_4color);  /** RGB->WRGB-Index */
  140. private dev_proc_map_color_rgb(upd_4color_rgb);   /** WRGB-Index->RGB */
  141.  
  142. /**
  143. Finally the fourth pair deals with KCMY-Values. The Mapping-Function
  144. is of a different type, due to the additional argument, but the
  145. inverse-Function is of the same type, and expects RGB-Values to be
  146. deliverd into the receiving 3-Component-Array!
  147. */
  148.  
  149. private dev_proc_map_cmyk_color(upd_cmyk_icolor); /** KCMY->KCMY-Index */
  150. private dev_proc_map_color_rgb( upd_icolor_rgb);  /** KCMY->RGB-Index */
  151.  
  152. /**
  153. The difference between the icolor-pair and the kcolor-pair is the enforced
  154. black-generation in the forward-mapping. that is taken into account by the
  155. reverse-mapping too.
  156. */
  157.  
  158. private dev_proc_map_cmyk_color(upd_cmyk_kcolor); /** adds black generation */
  159. private dev_proc_map_color_rgb( upd_kcolor_rgb);  /** watches black-gen */
  160.  
  161. /**
  162. For the sake of efficiency there is that bunch of functions and they
  163. perform no validity checks, thus it has to be assured that they are
  164. only active, if there is a valid device-structure for then.
  165. upd_procs_map performs this task.
  166. */
  167.  
  168. private int             upd_procs_map( P1(upd_device *udev));
  169.  
  170. /* ------------------------------------------------------------------- */
  171. /* Prototype of the Device-Structure (the only thing exported!)        */
  172. /* ------------------------------------------------------------------- */
  173.  
  174. /**
  175. "uniprint" needs a procedure-table of its own, since it provides several
  176. optional procedures. Simpler-Drivers (e.g. non-color-drivers) may use
  177. prn_std_procs instead of defining their own procedure-table.
  178. */
  179.  
  180. #define upd_set_dev_proc(dev, p, proc) \
  181.    ((dev)->std_procs.p = (dev)->orig_procs.p = (proc))
  182.  
  183. private gx_device_procs upd_procs = {  /** Table of procedures */
  184.    upd_open,                      /** open-function, upd-special */
  185.    gx_default_get_initial_matrix, /** retrieve matrix */
  186.    gx_default_sync_output,        /** sync display */
  187.    gdev_prn_output_page,          /** superclass-print (calls back) */
  188.    upd_close,                     /** close-function, upd-special */
  189.    gx_default_map_rgb_color,      /** RGB-mapping */
  190.    gx_default_map_color_rgb,      /** reverse mapping */
  191.    NULL,                          /** fill_rectangle */
  192.    NULL,                          /** tile_rectangle */
  193.    NULL,                          /** copy_mono */
  194.    NULL,                          /** copy_color */
  195.    NULL,                          /** draw_line */
  196.    gx_default_get_bits,           /** reads scanlines, e.g. for the driver */
  197.    upd_get_params,                /** Export parameters, upd-special */
  198.    upd_put_params,                /** Import parameters, upd-special */
  199.    gx_default_map_cmyk_color      /** KCMY-mapping */
  200. };                                     /** */
  201.  
  202. /**
  203. The prototype-instance of the device-structure _must_ have the name
  204. "gs_uniprint_device", where "uniprint" is the external name of the driver.
  205. This notice is bluntly copied from drivers.txt, which a potential
  206. driver-author should carefully read.
  207.  
  208. Just to mention: this prototype is quite similar to the one, that
  209. "prn_device" produces and it identifies "uniprint" as a monochrome 1Bit
  210. device to GHOSTSCRIPT. But during the lifetime of a driver-instance
  211. this might change.
  212.  
  213. This is the end of the part of declarations, that are common for
  214. color-drivers. The next sections address "uniprint"-specific data-types
  215. and the reader might directly skip to the section titled
  216.  
  217.     upd_print_page: The main workhorse
  218. */
  219.  
  220. upd_device far_data gs_uniprint_device = { /** */
  221.    prn_device_body(upd_device, upd_procs,  /** The Type and Procedures */
  222.       "uniprint",                          /** External name of the Device */
  223.       DEFAULT_WIDTH_10THS,                 /** X-Size (1/10") */
  224.       DEFAULT_HEIGHT_10THS,                /** Y-Size (1/10") */
  225.       72, 72,                              /** X,Y-DpI */
  226.       0.0, 0.0, 0.0, 0.0,                  /** L,B,R,T-Margin */
  227.       1, /**  color_info.num_components 1/3/4 */
  228.       1, /**  color_info.depth         1/2/4/8/16/24/32 */
  229.       1, /**  color_info.max_gray      # of distinct gray levels -1 (255/1) */
  230.       0, /**  color_info.max_color     # of distinct color levels -1 (255/1/0)*/
  231.       1, /**  color_info.dither_grays  size of gray ramp for dithering (5/2) */
  232.       0, /**  color_info.dither_colors size of color cube ditto (5/2/0) */
  233.       upd_print_page),                     /** Print-procedure */
  234.       { NULL, 0, true },                   /** Driver-Version */
  235.       NULL                                 /** upd-field: Initially none */
  236. };                                         /** */
  237.  
  238.  
  239. /* ------------------------------------------------------------------- */
  240. /* UPD-Data- and Prototypes                                            */
  241. /* ------------------------------------------------------------------- */
  242.  
  243. /*@ gdevupd.h < */
  244. /* ------------------------------------------------------------------- */
  245. /* External names of the UPD-Parameters                                */
  246. /* ------------------------------------------------------------------- */
  247.  
  248. /** UPD-Parameters
  249.  
  250. "uniprint" supports a hole bunch of external parameters. This Parameters
  251. fall into the following categories:
  252.  
  253.  0. special-string the upd_version, readonly          upd_version
  254.  1. choice         name-indices, stored in            upd->choice
  255.  2. boolean        single bits, stored in             upd->flags
  256.  3. integers       single numbers, stored in          upd->ints
  257.  4. integer-Arrays arrays of numbers, stored in       upd->int_a
  258.  5. string         device-commands, stored in         upd->strings
  259.  6. string-Arrays  arrayed device-commands, stored in upd->string_a
  260.  7. float-Arrays   arrays of floats, stored in        upd->float_a
  261.  
  262. Currently there is no need for single floats, but they may be introduced in
  263. future versions. Since "uniprint" somtimes manipulates the contents of the
  264. array-variables it dynamically allocates storage for all this parameters.
  265.  
  266. The following sections defines the names for this parameters in the order,
  267. they are stored within the mentioned dynamic fields of the upd-structure.
  268. A NULL-name means that the corresponding parameter is not externally visible.
  269. Besides the name, there is always a symbolic index #defined, that MUST match
  270. the Index-Number of the name.
  271. Actually
  272. */
  273.  
  274. static const char *const upd_version = "upVersion"; /** Readonly Version */
  275.  
  276. /** Names for the multiple-choice-Parameters
  277.  
  278. Currently there are three Parameters, that are handled as named choices.
  279. For each of them, there is an array of constant strings that consists of
  280.  
  281. 1.       the Parameter-Name
  282. 2. - n-1 the available choices.
  283. n.       A terminating NULL
  284. */
  285.  
  286. static const char *const upd_mapper[] = { "upColorModel",
  287. #define MAP_GRAY        1   /** Monochrome & Grayscale Devices */
  288. "DeviceGray",               /** Monochrome & Grayscale Devices */
  289. #define MAP_RGBW        2   /** RGB with White-Generation */
  290. "DeviceRGBW",               /** RGB with White-Generation */
  291. #define MAP_RGB         3   /** RGB-Mapping */
  292. "DeviceRGB",                /** RGB-Mapping */
  293. #define MAP_CMYK        4   /** CMYK-Mapping */
  294. "DeviceCMYK",               /** CMYK-Mapping */
  295. #define MAP_CMYKGEN     5   /** CMYK-Mapping with Black-Generation */
  296. "DeviceCMYKgenerate",       /** CMYK-Mapping with Black-Generation */
  297. NULL
  298. };
  299.  
  300. static const char *const upd_render[] = { "upRendering",
  301. #define RND_FSCOMP      1   /** Componentwise Floyd-Steinberg */
  302. "ErrorDiffusion",           /** Componentwise Floyd-Steinberg */
  303. #define RND_FSCMYK      2   /** CMYK-specialized 32Bit Floyd-Steinberg */
  304. "FSCMYK32",                 /** CMYK-specialized 32Bit Floyd-Steinberg */
  305. NULL
  306. };
  307.  
  308. static const char *const upd_format[] = { "upOutputFormat",
  309. #define FMT_RAS         1   /** Generates SUN-Rasterfiles */
  310. "SunRaster",                /** Generates SUN-Rasterfiles */
  311. #define FMT_EPSON       2   /** Generates X+Y-Weaved ESC/P-Output */
  312. "Epson",                    /** Generates X+Y-Weaved ESC/P-Output */
  313. #define FMT_ESCP2Y      3   /** Generates Y-Weaved ESC/P2-Output */
  314. "EscP2",                    /** Generates Y-Weaved ESC/P2-Output */
  315. #define FMT_ESCP2XY     4   /** Generates X+Y-Weaved ESC/P2-Output */
  316. "EscP2XY",                  /** Generates X+Y-Weaved ESC/P2-Output */
  317. #define FMT_RTL         5   /** Generates HP-PCL/RTL-Output */
  318. "Pcl",                      /** Generates HP-PCL/RTL-Output */
  319. #define FMT_CANON       6   /** Generates Output for Canon extended mode (hr) */
  320. "Canon",                    /** Generates Output for Canon extended mode (hr) */
  321. NULL
  322. };
  323.  
  324. static const char *const *const upd_choice[] = {
  325. #define C_MAPPER        0   /** the selected Mapper */
  326.    upd_mapper,
  327. #define C_RENDER        1   /** the selected Rendering */
  328.    upd_render,
  329. #define C_FORMAT        2   /** the selected Choice */
  330.    upd_format
  331. };
  332.  
  333. /** Names for the flags (bool)
  334. */
  335.  
  336. static const char *const upd_flags[] = {      /** */
  337. #define B_REVDIR            ((uint32) 1<<0)   /** FS-Dir-Flag */
  338. "upFSReverseDirection",                       /** FS-Dir-Flag */
  339. #define B_FIXDIR            ((uint32) 1<<1)   /** Do not alter FS-direction */
  340. "upFSFixedDirection",                         /** Do not alter FS-direction */
  341. #define B_FSWHITE           ((uint32) 1<<2)   /** Process white in FS */
  342. "upFSProcessWhiteSpace",                      /** Process white in FS */
  343. #define B_FSZERO            ((uint32) 1<<3)   /** Zero FS-Initialization */
  344. "upFSZeroInit",                               /** Zero FS-Initialization */
  345.  
  346. #define B_PAGEWIDTH         ((uint32) 1<<4)   /** Adjust Width in BOP */
  347. "upAdjustPageWidthCommand",                   /** Adjust Page-Width in BOP */
  348. #define B_PAGELENGTH        ((uint32) 1<<5)   /** Adjust Length in BOP */
  349. "upAdjustPageLengthCommand",                  /** Adjust Page-Length in BOP */
  350. #define B_TOPMARGIN         ((uint32) 1<<6)   /** Adjust Top-Margin in BOP */
  351. "upAdjustTopMarginCommand",                   /** Adjust Top-Margin in BOP */
  352. #define B_BOTTOMMARGIN      ((uint32) 1<<7)   /** Adjust Bottom-Margin in BOP */
  353. "upAdjustBottomMarginCommand",                /** Adjust Bottom-Margin in BOP */
  354. #define B_RESOLUTION        ((uint32) 1<<8)   /** Adjust Resolution in BOP */
  355. "upAdjustResolutionCommand",                  /** Adjust Resolution in BOP */
  356. #define B_MEDIASIZE         ((uint32) 1<<9)   /** Adjust Mediasize in BOP */
  357. "upAdjustMediaSize",                          /** Adjust Mediasize in BOP */
  358.  
  359. #define B_XABS              ((uint32) 1<<10)   /** Use Absolute X-Values */
  360. "upFormatXabsolute",                          /** Use Absolute X-Values */
  361. #define B_YABS              ((uint32) 1<<11)  /** Use Absolute Y-Values */
  362. "upFormatYabsolute",                          /** Use Absolute Y-Values */
  363.  
  364. #define B_MAP               ((uint32) 1<<12)  /** Mapping Initialized */
  365. "upColorModelInitialized",                    /** Mapping Initialized */
  366. #define B_BUF               ((uint32) 1<<13)  /** Raster-Buffer Initialized */
  367. "upRasterBufferInitialized",                  /** Raster-Buffer Initialized */
  368. #define B_RENDER            ((uint32) 1<<14)  /** Rendering Initialized */
  369. "upRenderingInitialized",                     /** Rendering Initialized */
  370. #define B_FORMAT            ((uint32) 1<<15)  /** Formatter Initialized */
  371. "upOutputFormatInitialized",                  /** Formatter Initialized */
  372. #define B_ABORT             ((uint32) 1<<16)  /** Abort on Interrupt */
  373. "upOutputAborted",                            /** Abort on Interrupt */
  374. #define B_ERROR             ((uint32) 1<<17)  /** Severe Error detected */
  375. "upErrorDetected",                            /** Severe Error detected */
  376.  
  377. #define B_OPEN              ((uint32) 1<<18)  /** Open-Command written */
  378. "upWroteData",                                /** Open-Command written */
  379.  
  380. #define B_YFLIP             ((uint32) 1<<19)  /** Mirrored printing (hr) */
  381. "upYFlip"                                     /** Mirrored printing (hr) */
  382.  
  383. };
  384.  
  385. /** B_OK4GO: Bits required to execute the print-loop */
  386.  
  387. #define B_OK4GO  (B_MAP | B_BUF | B_RENDER | B_FORMAT)
  388.  
  389. /** Names for the ints
  390. */
  391.  
  392. static const char *const upd_ints[] = {
  393. #define I_PWIDTH            0                 /** Output-Width */
  394. "upOutputWidth",
  395. #define I_PHEIGHT           1                 /** Output-Height */
  396. "upOutputHeight",
  397. #define I_NCOMP             2                 /** Output-Components */
  398. "upOutputComponents",
  399. #define I_NSCNBUF           3                 /** Output-Buffers */
  400. "upOutputBuffers",
  401. #define I_XSTEP             4                 /** Unit-Step */
  402. "upOutputXStep", /* > 0 -> divide Raster-X, < 0 muliply Raster-X */
  403. #define I_XOFS              5                 /** abs. X-Offset */
  404. "upOutputXOffset",
  405. #define I_YSTEP             6                 /** Unit-Step */
  406. "upOutputYStep", /* > 0 -> divide Raster-Y, < 0 muliply Raster-Y */
  407. #define I_YOFS              7                 /** abs. Y-Offset */
  408. "upOutputYOffset",
  409. #define I_PINS2WRITE        8                 /** Number of Pins */
  410. "upOutputPins",
  411.  
  412. #define I_NXPASS            9                 /** X-Passes */
  413. "upWeaveXPasses",
  414. #define I_NYPASS           10                 /** Y-Passes */
  415. "upWeaveYPasses",
  416. #define I_NPASS            11                 /** Total # Passes */
  417. "upWeavePasses",
  418. #define I_BEG_Y            12                 /** Start of normal Weaving */
  419. "upWeaveInitialScan",
  420. #define I_END_Y            13                 /** End of normal Weaving */
  421. "upWeaveFinalScan",
  422. #define I_BEGSKIP          14                 /** A Scan-Offset */
  423. "upWeaveYOffset"
  424. };
  425.  
  426. /** Names for the Integer-Arrays
  427. */
  428.  
  429. static const char *const upd_int_a[] = {      /** */
  430. #define IA_COLOR_INFO       0                 /** external color_info */
  431. "upColorInfo",                                /** external color_info */
  432.  
  433. #define IA_COMPBITS         1                 /** Bits stored per Component */
  434. "upComponentBits",                            /** Bits stored per Component */
  435. #define IA_COMPSHIFT        2                 /** Shift for the stored Bits */
  436. "upComponentShift",                           /** Shift for the stored Bits */
  437. #define IA_COMPORDER        3                 /** Order of Output-Components */
  438. "upOutputComponentOrder",                     /** Order of Output-Components */
  439.  
  440. #define IA_STD_DY           4                 /** Standard-Weave Feeds */
  441. "upWeaveYFeeds",                              /** Standard-Weave Feeds */
  442. #define IA_STD_IX           5                 /** Standard-Weave X-Passes */
  443. "upWeaveXStarts",                             /** Standard-Weave X-Start */
  444. #define IA_BEG_DY           6                 /** Initial-Weave Feeds */
  445. "upWeaveInitialYFeeds",                       /** Initial-Weave Feeds */
  446. #define IA_BEG_IX           7                 /** Initial-Weave X-Start */
  447. "upWeaveInitialXStarts",                      /** Initial-Weave X-Start */
  448. #define IA_BEGBOT           8                 /** Initial-Weave #Pins */
  449. "upWeaveInitialPins",                         /** Initial-Weave #Pins */
  450. #define IA_END_DY           9                 /** Final-Weave Feeds */
  451. "upWeaveFinalYFeeds",                         /** Final-Weave Feeds */
  452. #define IA_END_IX          10                 /** Final-Weave X-Start */
  453. "upWeaveFinalXStarts",                        /** Final-Weave X-Start */
  454. #define IA_ENDTOP          11                 /** Final-Weave #Pins */
  455. "upWeaveFinalPins"                            /** Final-Weave #Pins */
  456. };
  457.  
  458. /** Names of the String-Parameters
  459. */
  460.  
  461. static const char *const upd_strings[] = { /** */
  462. #define S_MODEL             0                 /** Name of the Printer-Model */
  463. "upModel",                                    /** Name of the Printer-Model */
  464. #define S_OPEN              1                 /** Printer-Begin-Job */
  465. "upBeginJobCommand",                          /** Printer-Begin-Job */
  466. #define S_CLOSE             2                 /** Printer-End-Job */
  467. "upEndJobCommand",                            /** Printer-End-Job */
  468. #define S_BEGIN             3                 /** Printer-Begin-Page */
  469. "upBeginPageCommand",                         /** Printer-Begin-Page */
  470. #define  S_END              4                 /** Printer-End-Page */
  471. "upEndPageCommand",                           /** Printer-End-Page */
  472. #define  S_ABORT            5                 /** Printer-Abort-Command */
  473. "upAbortCommand",                             /** Printer-Abort-Command */
  474.  
  475. #define S_XMOVE             6                 /** X-Positioning-Command */
  476. "upXMoveCommand",                             /** X-Positioning-Command */
  477. #define S_XSTEP             7                 /** X-Step Command (1<I_XSTEP) */
  478. "upXStepCommand",                             /** X-Step Command (1<I_XSTEP) */
  479. #define S_SETLF             8                 /** Set-Linefeed-Command */
  480. "upSetLineFeedCommand",                       /** Set-Linefeed-Command */
  481. #define S_YMOVE             9                 /** Y-Positioning-Command */
  482. "upYMoveCommand",                             /** Y-Positioning-Command */
  483. #define S_YSTEP            10                 /** Y-Step Command (1<I_YSTEP) */
  484. "upYStepCommand"                              /** Y-Step Command (1<I_YSTEP) */
  485. }; /** */
  486.  
  487. /** Names for the String-Arrays
  488. */
  489.  
  490. static const char *const upd_string_a[] = {   /** */
  491. #define SA_SETCOMP          0                 /** Select Components */
  492. "upSelectComponentCommands",                  /** Select Components */
  493. #define SA_WRITECOMP        1                 /** Write Component Comands */
  494. "upWriteComponentCommands"                    /** Write Component Commands */
  495. };                                            /** */
  496.  
  497. /** Names for the float-Arrays
  498. */
  499. static const char *const upd_float_a[] = {    /** */
  500. #define FA_WXFER            0                 /** White-Transfer */
  501. "upWhiteTransfer",                            /** White-Transfer */
  502. #define FA_RXFER            1                 /** Red-Transfer */
  503. "upRedTransfer",                              /** Red-Transfer */
  504. #define FA_GXFER            2                 /** Green-Transfer */
  505. "upGreenTransfer",                            /** Green-Transfer */
  506. #define FA_BXFER            3                 /** Blue-Transfer */
  507. "upBlueTransfer",                             /** Blue-Transfer */
  508. #define FA_KXFER            4                 /** Black-Transfer */
  509. "upBlackTransfer",                            /** Black-Transfer */
  510. #define FA_CXFER            5                 /** Cyan-Transfer */
  511. "upCyanTransfer",                             /** Cyan-Transfer */
  512. #define FA_MXFER            6                 /** Magenta-Transfer */
  513. "upMagentaTransfer",                          /** Magenta-Transfer */
  514. #define FA_YXFER            7                 /** Yellow-Transfer */
  515. "upYellowTransfer",                           /** Yellow-Transfer */
  516. #define FA_MARGINS          8                 /** private Margins */
  517. "upMargins"                                   /** private Margins */
  518. };                                            /** */
  519.  
  520. /* ------------------------------------------------------------------- */
  521. /* UPD-specific datatypes                                              */
  522. /* ------------------------------------------------------------------- */
  523.  
  524. /**
  525. int32 and uint32 are 32Bit-Integer-Types used in the
  526. Floyd-Steinberg Algorithm and instead of gx_color_index. The
  527. 8-Byte long's on some 64Bit-Machines are apparently useless,
  528. since gdevprn.c does (currently) support only 32-Bit Rasterdata.
  529. */
  530.  
  531. #if     arch_log2_sizeof_int < 2  /* int is too small */
  532.    typedef          long  int32;
  533. #define                   INT32_MIN  LONG_MIN
  534. #define                   INT32_MAX  LONG_MAX
  535.    typedef unsigned long uint32;
  536. #define                  UINT32_MAX ULONG_MAX
  537. #else                             /* int is sufficient */
  538.    typedef          int   int32;
  539. #define                   INT32_MIN   INT_MIN
  540. #define                   INT32_MAX   INT_MAX
  541.    typedef unsigned int  uint32;
  542. #define                  UINT32_MAX  UINT_MAX
  543. #endif                            /* use int or long ? */
  544.  
  545. /**
  546. "updcmap" is used by the color-mapping functions of the driver.
  547. there are four cmaps in the "uniprint"-structure, one for each component.
  548. To be exact, it's not "4" but rather "UPD_CMAP_MAX", which is a synonym.
  549. */
  550.  
  551. typedef struct updcmap_s { /** */
  552.    gx_color_value      *code;      /** Values related to codes */
  553.    uint32               bitmsk;    /** Mask, right justified */
  554.    int                  bitshf;    /** Shift to right-justify */
  555.    int                  xfer;      /** Index to the Xfer-Array */
  556.    int                  bits;      /** # of Bits */
  557.    int                  comp;      /** Output-Number */
  558.    bool                 rise;      /* Rising/Falling Curve */
  559. } updcmap_t, *updcmap_p;  /** */
  560. typedef const updcmap_t *updcmap_pc;
  561.  
  562.  
  563. /**
  564. "updcomp" holds similar informations, but is used for the rendering
  565. */
  566.  
  567. typedef struct updcomp_s {  /* Parameters for Floyd-Steinberg */
  568.    int32                offset;    /* Offset added to scaled values */
  569.    int32                scale;     /* Scale for the raw values */
  570.    int32                threshold; /* Val must be larger than this to fire */
  571.    int32                spotsize;  /* subtracted from Val when fired */
  572.    uint32               bitmsk;    /* Mask */
  573.    int                  bitshf;    /* shift */
  574.    int                  bits;      /* # of Bits */
  575.    int                  cmap;      /* Index for the Parameter-name */
  576. } updcomp_t, *updcomp_p;    /* Parameters for Floyd-Steinberg */
  577.  
  578. /** updscan is the Element of the scan-buffer. */
  579.  
  580. typedef struct updscan_s { /* Single Scanline (1 Bit/Pixel) */
  581.    byte   *bytes;      /* Buffer used w. 32-Bit Words */
  582.    int    *xbegin;     /* 1st  Pixel set (or nbytes<<3 if none) */
  583.    int    *xend;       /* last Pixel set (or -1, if none) */
  584. } updscan_t, *updscan_p;   /* Single Scanline (1 Bit/Pixel) */
  585.  
  586.  
  587. /** Main upd-Structure ***/
  588.  
  589. #define UPD_CMAP_MAX     4 /** Number of Colormaps provided */
  590. #define UPD_VALPTR_MAX  32 /** Number of valbuf-Pointers */
  591.  
  592. #define upd_proc_pxlget(name) uint32 name(P1(upd_p upd))
  593. #define upd_proc_render(name) int name(P1(upd_p upd))
  594. #define upd_proc_writer(name) int name(P2(upd_p upd,FILE *out))
  595.  
  596. struct upd_s { /* All upd-specific data */
  597.  
  598.    int                   *choice;     /** Named-Choices */
  599.    int                   *ints;       /** Integers */
  600.    gs_param_int_array    *int_a;      /** Integer-Arrays */
  601.    gs_param_string       *strings;    /** Strings */
  602.    gs_param_string_array *string_a;   /** String-Arrays */
  603.    gs_param_float_array  *float_a;    /** Float-Arrays */
  604.  
  605.    updcmap_t              cmap[UPD_CMAP_MAX]; /** Mapping-Data */
  606.  
  607.    byte                  *gsbuf;      /* Storage for GS-Rasterdata */
  608.    byte                  *gsscan;     /* Begin of GS-Rasterdata */
  609.  
  610.    byte                  *pxlptr;     /* Source for pxlget */
  611.    upd_proc_pxlget(     (*pxlget));   /* The Pixel-Reader */
  612.    upd_proc_render(     (*render));   /* Actual Rendering */
  613.    upd_proc_writer(     (*writer));
  614.  
  615.    updscan_p             *scnbuf;     /* Output-Values */
  616.    int32                 *valbuf;     /* Floyd-Steinberg-Buffer */
  617.    void                  *valptr[UPD_VALPTR_MAX];
  618.  
  619.    byte                  *outbuf;     /* Output-Buffer */
  620.    upd_proc_render(     (*start_render)); /* Setup for rendering */
  621.    upd_proc_writer(     (*start_writer)); /* Setup for writilg */
  622.  
  623.    uint32                 flags;      /** Some flags */
  624.    int                    pdwidth;    /** pdev-width upon open */
  625.    int                    pdheight;   /** pdev-height upon open */
  626.  
  627.    uint                   ngsbuf;     /* Size of gsbuf */
  628.    int                    gswidth;    /* Width in GS-Pixels */
  629.    int                    gsheight;   /* Height in GS-Pixels */
  630.  
  631.    int                    rwidth;     /* Rendering-Width */
  632.  
  633.    int                    pwidth;     /* Printing-Width */
  634.    int                    pheight;    /* # scanlines printed */
  635.  
  636.    uint                   nvalbuf;    /* Size of valbuf */
  637.    int                    nscnbuf;    /* Number of entries in scnbuf. */
  638.    int                    ncomp;      /* # Components in scnbuf */
  639.    int                    nbytes;     /* Size of scnbuf[][].words */
  640.    int                    nlimits;    /* Size of scnbuf[][].xbegin/end */
  641.    int                    scnmsk;     /* Size of scanbuf - 1 */
  642.    uint                   noutbuf;    /* Size of the Output-Buffer */
  643.  
  644.    int                    ixpass;     /* Current X-pass (0 ... nxpass-1) */
  645.    int                    ipass;      /* Current pass (0 ... npass-1) */
  646.    int                    icomp;      /* Selected Component */
  647.    int                    lf;         /* Selected Line-Space */
  648.  
  649.    int                    xprinter;   /* Actual X-Position */
  650.  
  651.    int                    yscan;      /* Top-Scan (page-vari) */
  652.    int                    yprinter;   /* Actual Y-Position (page-vari) */
  653.    int                    yscnbuf;    /* Y not yet buffered */
  654. };             /* All upd-specific data */
  655.  
  656.  
  657. /* ------------------------------------------------------------------- */
  658. /* Various Message-Levels                                              */
  659. /* ------------------------------------------------------------------- */
  660.  
  661. /**
  662. UPD_MESSAGES, Is collection of Bits, that controls Messages
  663. */
  664.  
  665. #define UPD_M_NONE      0x0000 /** No Messages at all */
  666. #define UPD_M_ERROR     0x0001 /** Errors */
  667. #define UPD_M_WARNING   0x0002 /** Warnings */
  668. #define UPD_M_TOPCALLS  0x0004 /** Log Calls to main Functions */
  669. #define UPD_M_MAPCALLS  0x0008 /** Log Color-Mapping-Calls */
  670. #define UPD_M_SETUP     0x0010 /** Log Setup-Activity */
  671. #define UPD_M_FSBUF     0x0020 /** Error-Summary for valbuf */
  672.  
  673.  
  674. /* ------------------------------------------------------------------- */
  675. /* The UPD-Routines                                                    */
  676. /* ------------------------------------------------------------------- */
  677.  
  678. /**
  679. Besides the main routines required for the color-mapping, that were
  680. declared near the beginning, there are some auxillary functions.
  681. Most prominent are "upd_open_map" and "upd_close_map", which
  682. do the proper actions when opening and closing the device.
  683. */
  684.  
  685. private int             upd_open_map( P1(upd_device *udev));
  686. private int             upd_close_map(P1(upd_device *udev));
  687.  
  688. /**
  689. But "upd_truncate" and "upd_expand" are also mentionable. They are
  690. the actual workhorses for the component-oriented mapping. When mapping
  691. the 16Bit Component-Values to the indices, some truncation takes place
  692. and this is what "upd_truncate" does, in the most general manner i can
  693. think of and with O(log(n)) in time. "upd_expand" is required for the
  694. reverse mapping-functions and is a constant-time `algorithm'.
  695. */
  696. private uint32          upd_truncate(P3(upd_pc,int,gx_color_value));
  697. private gx_color_value  upd_expand(  P3(upd_pc,int,uint32));
  698.  
  699. /**
  700. The next group of internal functions adresses the rendering. Besides
  701. the main-functions "upd_open_render" and "upd_close_render", there
  702. are groups of up to 3 Functions, for each algorithm available with
  703. UPD. Two routines are invoked during open and close and the third
  704. is called for each scanline. Actually a fourth function is provided,
  705. that is invoked at the beginning of each page to be printed, but the
  706. current algorithms do not need it.
  707. */
  708. private void            upd_open_render(   P1(upd_device *udev));
  709. private void            upd_close_render(  P1(upd_device *udev));
  710.  
  711. private void            upd_open_fscomp(   P1(upd_device *udev));
  712. private int             upd_fscomp(        P1(upd_p upd));
  713. private void            upd_close_fscomp(  P1(upd_device *udev));
  714.  
  715. private void            upd_open_fscmyk(   P1(upd_device *udev));
  716. private int             upd_fscmyk(        P1(upd_p upd));
  717.  
  718. /**
  719. I hope that the formatting stuff can be kept simple and thus most
  720. of the work is done inside the general open and close-functions.
  721. During open, there is a call to a format-specific open-function, but
  722. this is only for checking and determining the amount of of bytes required
  723. for the output-buffer (and limit-values in the scan-buffer).
  724. */
  725. private int             upd_open_writer(   P1(upd_device *udev));
  726. private void            upd_close_writer(  P1(upd_device *udev));
  727. #if UPD_SIGNAL
  728. private void            upd_signal_handler(P1(int sig));
  729. #endif
  730.  
  731. /**
  732. The first format are the uncompressed! SUN-Rasterfiles. The primary intention
  733. of this format is testing, but it might turn out to be useful for other
  734. purposes, even if the amount of generated data is huge. On the other hand
  735. it is a violation of UPD's rules: the start-routine computes the Begin-Page
  736. sequence (the Rasterfile header) since it would be a nuisance to provide
  737. this code within each (test-)personalization in PostScript.
  738. */
  739. private int             upd_open_rascomp(   P1(upd_device *udev));
  740. private int             upd_start_rascomp(  P2(upd_p upd, FILE *out));
  741. private int             upd_rascomp(        P2(upd_p upd, FILE *out));
  742.  
  743. /**
  744. The second format is ESC/P, the format introduced with the first Epson
  745. impact printers. This format is used by a lot of other printers too.
  746. It is also uncompressed. This formatter supports X- and Y-Weaving,
  747. which makes it the most sophisticated one inside this driver.
  748. */
  749.  
  750. private void            upd_limits(        P2(upd_p upd, bool check));
  751. private int             upd_open_wrtescp(  P1(upd_device *udev));
  752. private int             upd_wrtescp(       P2(upd_p upd, FILE *out));
  753.  
  754. /**
  755. The third format is ESC/P2, the format use by the newer Epson-Printers.
  756. It allows runlength-Compression similar to the RTL/PCL-Family of Printers.
  757. This formatter does not allow for X-Weaving.
  758.  
  759. The fourth writer is a ESC/P2-Writer, that supports X-Weaving
  760. */
  761. private int             upd_rle(P3(byte *out,const byte *in,int nbytes));
  762. private int             upd_open_wrtescp2( P1(upd_device *udev));
  763. private int             upd_wrtescp2(      P2(upd_p upd, FILE *out));
  764. private int             upd_wrtescp2x(     P2(upd_p upd, FILE *out));
  765.  
  766. /**
  767. The fifth writer is a HP-RTL/PCL-Writer
  768. */
  769.  
  770. private int             upd_open_wrtrtl(   P1(upd_device *udev));
  771. private int             upd_wrtrtl(        P2(upd_p upd, FILE *out));
  772.  
  773. /**
  774. The sixth writer is for Canon Extended Mode (currently BJC610) (hr)
  775. */
  776.  
  777. private int             upd_open_wrtcanon( P1(upd_device *udev));
  778. private int             upd_wrtcanon(      P2(upd_p upd, FILE *out));
  779.  
  780. /**
  781. Generalized Pixel Get & Read
  782. */
  783. private uint32 upd_pxlfwd(P1(upd_p upd));
  784. private uint32 upd_pxlrev(P1(upd_p upd));
  785. #define upd_pxlget(UPD) (*UPD->pxlget)(UPD)
  786.  
  787.  
  788. /* ------------------------------------------------------------------- */
  789. /* Macros to deal with the Parameter-Memory                            */
  790. /* ------------------------------------------------------------------- */
  791.  
  792. /**
  793. Usually the creation of copies of external parameters is not necessary,
  794. at least with gs-versions > 4.03. But uniprint writes to the parameters
  795. in some cases or creates some by itself, thus to get a unified interface
  796. all parameter-data are copied and thus it is legal to manipulate them.
  797.  
  798. Here are several Macros, named "UPD_MM_*" to deal with that.
  799. */
  800.  
  801. /** UPD_MM_GET_ARRAY allocates & initializes an array of values */
  802. #define UPD_MM_GET_ARRAY(Which,Nelts)                                 \
  803.    Which = NULL;                                                      \
  804.    if(0 < (Nelts)) {                                                  \
  805.       byte *tmp = gs_malloc(Nelts,sizeof(Which[0]),"uniprint/params");\
  806.       if(tmp) {                                                       \
  807.          memset(tmp,0,(Nelts)*sizeof(Which[0]));                      \
  808.          Which = (void *) tmp;                                        \
  809.       } else {                                                        \
  810.           return_error(gs_error_VMerror);                             \
  811.       }                                                               \
  812.    }
  813.  
  814. /** UPD_MM_DEL_ARRAY frees an array of values */
  815. #define UPD_MM_DEL_ARRAY(Which,Nelts,Delete)                          \
  816.    if(Which && 0 < (Nelts)) {                                         \
  817.       uint ii;                                                        \
  818.       for(ii = 0; (Nelts) > ii; ++ii) Delete(Which[ii]);              \
  819.       gs_free((byte *)Which,Nelts,sizeof(Which[0]),"uniprint/params");\
  820.    }                                                                  \
  821.    Which = 0
  822.  
  823. /** UPD_MM_DEL_VALUE deletes a value, does nothing */
  824. #define UPD_MM_DEL_VALUE(Which) /* */
  825.  
  826. /** UPD_MM_DEL_PARAM deletes a single gs-array-parameter */
  827. #define UPD_MM_DEL_PARAM(Which)  {                                \
  828.    if(Which.data && Which.size)                                   \
  829.       gs_free((byte *)Which.data,Which.size,sizeof(Which.data[0]),\
  830.          "uniprint/params");                                      \
  831. }
  832.  
  833. /** UPD_MM_DEL_APARAM deletes a nested gs-array-parameter */
  834. #define UPD_MM_DEL_APARAM(Which) {                                \
  835.    if(Which.data && Which.size) {                                 \
  836.       uint iii;                                                   \
  837.       for(iii = 0; iii < Which.size; ++iii)                       \
  838.          UPD_MM_DEL_PARAM(Which.data[iii]);                       \
  839.       gs_free((byte *)Which.data,Which.size,sizeof(Which.data[0]),\
  840.          "uniprint/params");                                      \
  841.    }                                                              \
  842. }
  843.  
  844. /** UPD_MM_CPY_ARRAY creates a new copy of an array of values */
  845. #define UPD_MM_CPY_ARRAY(To,From,Nelts,Copy)                \
  846.    UPD_MM_GET_ARRAY(To,Nelts);                              \
  847.    if(To && From) {                                         \
  848.       uint ii;                                              \
  849.       for(ii = 0; (Nelts) > ii; ++ii) Copy(To[ii],From[ii]);\
  850.    }
  851.  
  852. /** UPD_MM_CPY_VALUE Copies a simple Value */
  853. #define UPD_MM_CPY_VALUE(To,From)  To = From
  854.  
  855. /** UPD_MM_CPY_PARAM Creates a copy of a gs-parameter */
  856. #define UPD_MM_CPY_PARAM(To,From)                                     \
  857.    if(From.data && From.size) {                                       \
  858.       UPD_MM_GET_ARRAY(To.data,From.size);                            \
  859.       if(To.data) {                                                   \
  860.          To.size = From.size;                                         \
  861.          memcpy((byte *)To.data,From.data,To.size*sizeof(To.data[0]));\
  862.       }                                                               \
  863.    }
  864.  
  865. /** UPD_MM_CPY_APARAM Creates a copy of a nested gs-parameter */
  866. #define UPD_MM_CPY_APARAM(To,From)                                    \
  867.    if(From.data && From.size) {                                       \
  868.       UPD_MM_GET_ARRAY(To.data,From.size);                            \
  869.       if(To.data) {                                                   \
  870.          gs_param_string *tmp2 = (gs_param_string *) To.data;         \
  871.          uint iii;                                                    \
  872.          To.size = From.size;                                         \
  873.          for(iii = 0; To.size > iii; ++iii)                           \
  874.             UPD_MM_CPY_PARAM(tmp2[iii],From.data[iii]);               \
  875.       }                                                               \
  876.    }
  877.  
  878. /* ------------------------------------------------------------------- */
  879. /* UPD-Initialized-Data                                                */
  880. /* ------------------------------------------------------------------- */
  881.  
  882. /** Version-String */
  883.  
  884. static const char rcsid[] = "$Revision: 1.77 $";
  885.  
  886. /** Default-Transfer-curve */
  887.  
  888. static const float upd_data_xfer[2] = { 0.0, 1.0 };
  889.  
  890. /*@ > */
  891.  
  892.  
  893. /* ------------------------------------------------------------------- */
  894. /* upd_signal_handler: Catch interrupts                                */
  895. /* ------------------------------------------------------------------- */
  896.  
  897. #if UPD_SIGNAL
  898. static upd_p sigupd = NULL;
  899. private void
  900. upd_signal_handler(int sig)
  901. {
  902.   if(sigupd) sigupd->flags |= B_ABORT;
  903. }
  904. #endif
  905.  
  906.  
  907. /* ------------------------------------------------------------------- */
  908. /* upd_print_page: The main workhorse                                  */
  909. /* ------------------------------------------------------------------- */
  910.  
  911. /**
  912. Function: upd_print_page
  913.  
  914. This is the top-level printing routine. It works through this
  915. steps:
  916.  
  917.  1. Once for each generated file, the "device-open-sequence" is written.
  918.  2. The "page-begin-sequence" is written.
  919.  
  920.  3. The data are generated and written:
  921.     3.1: Data are converted into a "printer-family"-specific format.
  922.          This step includes the halftoning, if selected.
  923.     3.2: Data are written with a printer-specific function.
  924.          There is not much code-compression inside theese functions,
  925.          since i observed to improvments in print-speed. Other
  926.          drivers do a better job in this.
  927.  
  928.  4. The "page-end-sequence" is written.
  929.  5. If a one-page-per-file mode is selected, the "device-close-sequence"
  930.     is added to the output. For multi-page files, this writing is
  931.     performed in "upd_close", the drivers close-function.
  932.  
  933. The routine is quite short, since all the allocation and checking
  934. occur in upd_open and upd_putparams. The only test, that upd_print_page
  935. does, is the verification wether the device is in a sane state. This
  936. must be done here, since during the initialisation, the device is
  937. usually opened several times, before obtaining a valid state.
  938. */
  939.  
  940. private int
  941. upd_print_page(gx_device_printer *pdev, FILE *out)
  942. {
  943.    upd_device *const udev  = (upd_device *) pdev;
  944.    const upd_p       upd   = udev->upd;
  945.    const int *const  ints  = upd ? upd->ints : NULL;
  946.    int error,need,yfill;
  947.  
  948. #if UPD_SIGNAL /* variables required for signal-handling only */
  949.    void (*oldint )(P1(int)) = NULL;
  950.    void (*oldterm)(P1(int)) = NULL;
  951.    upd_p  oldupd            = sigupd;
  952. #endif         /* variables required for signal-handling only */
  953.  
  954. /*
  955.  * Refuse to work, if not explicitly enabled during open
  956.  * (some/lot of allocated memory is required)
  957.  */
  958.    if(!upd || B_OK4GO != (upd->flags & (B_OK4GO | B_ERROR))) {
  959. #if UPD_MESSAGES & (UPD_M_ERROR | UPD_M_TOPCALLS)
  960.          fprintf(stderr,"CALL-REJECTED upd_print_page(0x%05lx,0x%05lx)\n",
  961.              (long) udev,(long) out);
  962. #endif
  963.       return gs_error_undefined;
  964.    }
  965.  
  966. #if UPD_MESSAGES & UPD_M_TOPCALLS
  967.    fprintf(stderr,"CALL: upd_print_page(0x%05lx,0x%05lx)\n",
  968.       (long) udev,(long) out);
  969. #endif
  970.  
  971. #if UPD_SIGNAL /* Setup of signal-handling */
  972.    sigupd  = upd;
  973.    oldint  = signal(SIGINT, upd_signal_handler);
  974.    oldterm = signal(SIGTERM,upd_signal_handler);
  975. #endif         /* Setup of signal-handling */
  976.  
  977. /*
  978.  * If the OutputFile was just opened, transfer the Open-Sequence to it.
  979.  */
  980.    if(!(upd->flags & B_OPEN)) {
  981.  
  982.       if(0   <  upd->strings[S_OPEN].size)
  983.          fwrite(upd->strings[S_OPEN].data,1,upd->strings[S_OPEN].size,out);
  984.       upd->flags |= B_OPEN;
  985.    }
  986. /*
  987.  * Always write the the Page-begin-sequence
  988.  */
  989.    if(0  <   upd->strings[S_BEGIN].size)
  990.       fwrite(upd->strings[S_BEGIN].data,1,upd->strings[S_BEGIN].size,out);
  991. /*
  992.  * Establish page-variables
  993.  */
  994.  
  995. /* Positions */
  996.    upd->xprinter  = 0;
  997.    upd->yscan     = 0; /* Position we are processing */
  998.    upd->yprinter  = 0; /* Actual Printer-Positions */
  999.    upd->yscnbuf   = 0; /* Next free scnbuf-Line */
  1000.  
  1001. /* Rendering & Writing Setup, if available */
  1002.    if(upd->start_render) (*upd->start_render)(upd);
  1003.    if(upd->start_writer) (*upd->start_writer)(upd,out);
  1004.  
  1005. /* How many scanlines do we need ? */
  1006.    need = ints[I_NYPASS] * ints[I_PINS2WRITE];
  1007.    if(0 >= need) need = 1;
  1008.  
  1009. /* The Weave-counters */
  1010.    upd->ipass  =  0;
  1011.    upd->ixpass =  0;
  1012.    upd->icomp  = -1; /* Enforces initial selection */
  1013.    upd->lf     = -1; /* Enforces initial selection */
  1014. /*
  1015.  * Main Loop
  1016.  */
  1017.    while(upd->pheight > upd->yscan) { /* Main-Loop */
  1018.  
  1019. /*
  1020.  *    Load as much data into the scan-buffer as possible
  1021.  *    (this is done in scan-sequence, the printing not necessarily.)
  1022.  */
  1023.       if(ints[I_BEGSKIP] > upd->yscan) yfill = 0;
  1024.       else                             yfill = upd->yscan - ints[I_BEGSKIP];
  1025.  
  1026.       for(yfill += upd->nscnbuf; upd->yscnbuf < yfill; upd->yscnbuf++) {
  1027.  
  1028.          if(upd->gsheight > upd->yscnbuf)  {
  1029.  
  1030.             if(0 > (*dev_proc(udev,get_bits))((gx_device *) udev,
  1031.                                    upd->yscnbuf,upd->gsbuf,&upd->gsscan)) {
  1032. #if UPD_MESSAGES & UPD_M_WARNING
  1033.                fprintf(stderr,"get_bits aborted with error, yscnbuf = %4d\n",
  1034.                   upd->yscnbuf);
  1035. #endif
  1036.                break;
  1037.             }
  1038.          } else {
  1039.  
  1040.             memset(upd->gsscan = upd->gsbuf,0,upd->ngsbuf);
  1041.  
  1042.          }
  1043.  
  1044.          if(0 > (*upd->render)(upd)) {
  1045. #if UPD_MESSAGES & UPD_M_WARNING
  1046.             fprintf(stderr,"Rendering aborted with error, yscnbuf = %4d\n",
  1047.                upd->yscnbuf);
  1048. #endif
  1049.             break;
  1050.          }
  1051.  
  1052.       }
  1053. /*
  1054.  *    Did the buffering loop take an error exit ?
  1055.  */
  1056.       if((upd->yscnbuf ^ yfill) & upd->scnmsk) break;
  1057. /*
  1058.  *    Print as much as possible
  1059.  */
  1060.       while((upd->yscan - ints[I_BEGSKIP] + need) < upd->yscnbuf) {
  1061.  
  1062. /*        first write the scan(s) */
  1063.           (*upd->writer)(upd,out);
  1064.  
  1065. /*        Check for termination */
  1066.           if(upd->yscan >= upd->pheight) break;
  1067.           if(upd->flags  & B_ABORT ) {
  1068. #if UPD_MESSAGES & UPD_M_WARNING
  1069.              fprintf(stderr,"Printing aborted upon interrupt, yscan = %4d\n",
  1070.                 upd->yscan);
  1071. #endif
  1072.              break;
  1073.           }
  1074.       }
  1075. /*
  1076.  *    Did the print-Loop take an error exit ?
  1077.  */
  1078.       if((upd->yscan - ints[I_BEGSKIP] + need) < upd->yscnbuf) break;
  1079.    }                                  /* Main-Loop */
  1080.  
  1081. /*
  1082.  * If we aborted for some reason, use the dedicated sequence
  1083.  */
  1084.  
  1085.    if((upd->pheight > upd->yscan) &&
  1086.       (0  <  upd->strings[S_ABORT].size)) { /* Only This! */
  1087.       fwrite(upd->strings[S_ABORT].data,1,upd->strings[S_ABORT].size,out);
  1088.  
  1089.       upd->flags &= ~B_OPEN; /* Inhibit Close-Sequence ! */
  1090. /*
  1091.  * If there is no special sequence, or we came to normal end,
  1092.  * write the normal sequence, if any
  1093.  */
  1094.  
  1095.    } else if(0  <   upd->strings[S_END].size) {
  1096.       fwrite(upd->strings[S_END].data,1,upd->strings[S_END].size,out);
  1097.    }
  1098. /*
  1099.  * If necessary, write the close-sequence
  1100.  */
  1101.    if((NULL != udev->fname  ) && strchr(udev->fname,'%')) {
  1102.  
  1103.       if(0  <   upd->strings[S_CLOSE].size)
  1104.          fwrite(upd->strings[S_CLOSE].data,1,upd->strings[S_CLOSE].size,out);
  1105.  
  1106.       upd->flags &= ~B_OPEN;
  1107.    }
  1108.  
  1109. /*
  1110.  * clean up, and return status
  1111.  */
  1112.  
  1113.    fflush(out); /* just to prepare for ferror */
  1114.  
  1115.    if(upd->pheight > upd->yscan) error = gs_error_interrupt;
  1116.    else if(ferror(out))          error = gs_error_ioerror;
  1117.    else                          error = 0;
  1118.  
  1119. #if UPD_MESSAGES & UPD_M_TOPCALLS
  1120.    fprintf(stderr,"RETURN: %d = upd_print_page(0x%05lx,0x%05lx)\n",
  1121.       error,(long) udev,(long)out);
  1122. #endif
  1123.  
  1124. #if UPD_SIGNAL /* Restore Interrupt-state */
  1125.       sigupd = oldupd;
  1126.       (void) signal(SIGINT ,oldint);
  1127.       (void) signal(SIGTERM,oldterm);
  1128. #endif         /* Restore Interrupt-state */
  1129.  
  1130.    return error;
  1131. }
  1132.  
  1133. /* ------------------------------------------------------------------- */
  1134. /* upd_open: Initialize everything for printing                        */
  1135. /* ------------------------------------------------------------------- */
  1136. /**
  1137. "upd_open" is -through the specified table of procedures- called instead
  1138. of the normal open-procedures for printer-devices, that performs quite
  1139. a complex job. Thus it is necessary to call this  `superclass-open´
  1140. here.
  1141.  
  1142. Besides that, this routine does quite a complex job too, in initializes
  1143. everything required to print a page. This might be time-consuming, the
  1144. alternative would be "upd_print_page", but i often print 100 pages or
  1145. more, but i never experienced more than 5-6 open-calls.
  1146. */
  1147.  
  1148. private int
  1149. upd_open(gx_device *pdev)
  1150. {
  1151.    upd_device *const udev    =  (upd_device *) pdev;
  1152.    const upd_p       upd     =  udev->upd;
  1153.    int              error;
  1154.  
  1155. #if UPD_MESSAGES & UPD_M_TOPCALLS
  1156.       fprintf(stderr,"CALL: upd_open(0x%05lx)\n",(long) pdev);
  1157. #endif
  1158.  
  1159. /** enforce the UPD-Margins */
  1160.  
  1161.    if((NULL != upd) && 
  1162.       (NULL != upd->float_a[FA_MARGINS].data) &&
  1163.       (4    == upd->float_a[FA_MARGINS].size)    ) {
  1164.       static float m[4];
  1165.       m[1] = upd->float_a[FA_MARGINS].data[1] / 72.0;
  1166.       m[3] = upd->float_a[FA_MARGINS].data[3] / 72.0;
  1167.       if(B_YFLIP & upd->flags) {
  1168.          m[0] = upd->float_a[FA_MARGINS].data[2] / 72.0;
  1169.          m[2] = upd->float_a[FA_MARGINS].data[0] / 72.0;
  1170.       } else {
  1171.          m[0] = upd->float_a[FA_MARGINS].data[0] / 72.0;
  1172.          m[2] = upd->float_a[FA_MARGINS].data[2] / 72.0;
  1173.       }
  1174.       gx_device_set_margins((gx_device *) udev, m, true);
  1175.    }
  1176.  
  1177. /** call the super-class open **/
  1178.    error = gdev_prn_open(pdev);
  1179.  
  1180. /** invoke the subroutines, if an upd is present. */
  1181.  
  1182.    if(upd) {
  1183.  
  1184.       upd->flags &= ~B_OK4GO;
  1185.  
  1186. /**
  1187. The following initializations are run, even in case of an error in
  1188. the super-class open, just to bring our upd into a sane state.
  1189. */
  1190.       if(0 > error) upd->flags |= B_ERROR;
  1191.  
  1192.       if(gs_error_VMerror == upd_open_map(udev)) error = gs_error_VMerror;
  1193.  
  1194. /**
  1195. The following piece of code is here for demonstration-purposes:
  1196. It determines the size of the printed image and allocates the
  1197. buffer for the raw raster-data
  1198. */
  1199.       upd->gswidth  = udev->width -
  1200.          (dev_l_margin(udev)+dev_r_margin(udev))*udev->x_pixels_per_inch;
  1201.  
  1202.       upd->gsheight = udev->height -
  1203.          (dev_t_margin(udev)+dev_b_margin(udev))*udev->y_pixels_per_inch;
  1204.  
  1205.       upd->ngsbuf = 0;    /* Ensure sane values */
  1206.       upd->gsbuf  = NULL; /* Ensure sane values */
  1207.  
  1208.       if(B_MAP & upd->flags) { /* Only if prerequisites were met */
  1209.          uint want  = gx_device_raster(pdev,true);
  1210.          upd->gsbuf = gs_malloc(want,1,"upd/gsbuf");
  1211.  
  1212.          if(upd->gsbuf) {
  1213.             upd->ngsbuf = want;
  1214.             upd->flags |= B_BUF;  /* Signal Success */
  1215.          } else {
  1216.             error = gs_error_VMerror; /* Signal Error */
  1217.             upd->flags |= B_ERROR;
  1218.          }
  1219.  
  1220.       }                            /* Only if prerequisites were met */
  1221.  
  1222.       upd_open_render(udev);  /* First subloop in printing */
  1223.  
  1224.       if(gs_error_VMerror == upd_open_writer(udev)) error = gs_error_VMerror;
  1225.  
  1226. #if UPD_MESSAGES & UPD_M_SETUP
  1227.       fprintf(stderr,"\n%sready to print\n\n",
  1228.          B_OK4GO != (upd->flags & (B_OK4GO | B_ERROR)) ?
  1229.          "NOT " : "");
  1230. #endif
  1231.       udev->upd->pdwidth  = udev->width;
  1232.       udev->upd->pdheight = udev->height;
  1233.  
  1234.    }
  1235.  
  1236. #if UPD_MESSAGES & UPD_M_TOPCALLS
  1237.       fprintf(stderr,"RETURN: %d = upd_open(0x%05lx)\n",
  1238.          error,(long) pdev);
  1239. #endif
  1240.  
  1241.    return error;
  1242. }
  1243.  
  1244. /* ------------------------------------------------------------------- */
  1245. /* upd_close: Release everything allocated in upd_open                 */
  1246. /* ------------------------------------------------------------------- */
  1247.  
  1248. private int
  1249. upd_close(gx_device *pdev)
  1250. {
  1251.    upd_device *const udev    =  (upd_device *) pdev;
  1252.    const upd_p       upd     =  udev->upd;
  1253.    int         error = 0;
  1254.    int         code;
  1255.  
  1256. #if UPD_MESSAGES & UPD_M_TOPCALLS
  1257.    fprintf(stderr,"CALL: upd_close(0x%05lx)\n",(long)pdev);
  1258. #endif
  1259.  
  1260. /** If necessary, write the close-sequence **/
  1261.  
  1262.    if( upd && (( B_OPEN | B_OK4GO) ==
  1263.                ((B_OPEN | B_OK4GO | B_ERROR) & upd->flags))) {
  1264.  
  1265.       if(udev->file && upd->strings && 0 < upd->strings[S_CLOSE].size)
  1266.          fwrite(upd->strings[S_CLOSE].data,1,
  1267.                 upd->strings[S_CLOSE].size,udev->file);
  1268.  
  1269.       upd->flags &= ~B_OPEN;
  1270.    }
  1271.  
  1272. /** Then release the open-allocated memory */
  1273.    if(upd) {
  1274.  
  1275.       upd_close_writer(udev);
  1276.  
  1277.       if(upd->gsbuf)
  1278.          gs_free(upd->gsbuf,upd->ngsbuf,1,"uniprint/gsbuf");
  1279.       upd->gsbuf  = NULL;
  1280.       upd->ngsbuf = 0;
  1281.       upd->flags &= ~B_BUF;
  1282.  
  1283.       upd_close_render(udev);
  1284.       upd_close_map(udev);
  1285.  
  1286.       UPD_MM_DEL_ARRAY(upd->choice,  countof(upd_choice),  UPD_MM_DEL_VALUE);
  1287.       UPD_MM_DEL_ARRAY(upd->ints,    countof(upd_ints),    UPD_MM_DEL_VALUE);
  1288.       UPD_MM_DEL_ARRAY(upd->int_a,   countof(upd_int_a),   UPD_MM_DEL_PARAM);
  1289.       UPD_MM_DEL_ARRAY(upd->strings, countof(upd_strings), UPD_MM_DEL_PARAM);
  1290.       UPD_MM_DEL_ARRAY(upd->string_a,countof(upd_string_a),UPD_MM_DEL_APARAM);
  1291.       UPD_MM_DEL_ARRAY(upd->float_a, countof(upd_float_a), UPD_MM_DEL_PARAM);
  1292.  
  1293.       gs_free(upd,sizeof(upd[0]),1,"uniprint");
  1294.  
  1295.       udev->upd = NULL;
  1296.    }
  1297.  
  1298. /** Then call the superclass close **/
  1299.    code = gdev_prn_close(pdev);
  1300.    error = error > code ? code : error;
  1301.  
  1302.  
  1303. #if UPD_MESSAGES & UPD_M_TOPCALLS
  1304.       fprintf(stderr,"RETURN: %d = upd_close(0x%05lx)\n",
  1305.          error,(long) pdev);
  1306. #endif
  1307.  
  1308.    return error;
  1309. }
  1310.  
  1311. /* ------------------------------------------------------------------- */
  1312. /* upd_get_params: Export Parameters to the Interpreter                */
  1313. /* ------------------------------------------------------------------- */
  1314.  
  1315. #if UPD_MESSAGES & UPD_M_TOPCALLS
  1316. #define UPD_EXIT_GET(Err,Dev,List)                                      \
  1317.    if(0 > Err) {                                                        \
  1318.       fprintf(stderr,"RETURN-%d: %d upd_get_params(0x%05lx,0x%05lx)\n", \
  1319.          __LINE__,Err,(long) Dev,(long) List);                          \
  1320.       return_error(Err);                                                \
  1321.    }
  1322. #else
  1323. #define UPD_EXIT_GET(Err,Dev,List) if(0 > Err) return_error(Err);
  1324. #endif
  1325.  
  1326. private int
  1327. upd_get_params(gx_device *pdev, gs_param_list *plist)
  1328. {
  1329.    upd_device *const udev    =  (upd_device *) pdev;
  1330.    const upd_p       upd     =  udev->upd;
  1331.    int               error,i;
  1332.  
  1333. #if UPD_MESSAGES & UPD_M_TOPCALLS
  1334.       fprintf(stderr,"CALL: upd_get_params(0x%05lx,0x%05lx)\n",
  1335.          (long) udev,(long) plist);
  1336. #endif
  1337.  
  1338. /** Call the SuperClass-get_params at the beginning */
  1339.    error = gdev_prn_get_params((gx_device *)udev,plist);
  1340.    UPD_EXIT_GET(error,udev,plist);
  1341.  
  1342. /** Export the version */
  1343.    if(upd_version) { /* Version-Export enabled */
  1344.       udev->upd_version.data       = (const byte *) rcsid;
  1345.       udev->upd_version.size       = strlen(rcsid);
  1346.       udev->upd_version.persistent = true;
  1347.       error = param_write_string(plist,upd_version,&udev->upd_version);
  1348.       UPD_EXIT_GET(error,udev,plist);
  1349.    }                 /* Version-Export enabled */
  1350.  
  1351. /** Export the Named choices */
  1352.    for(i = 0; i < countof(upd_choice); ++i) {
  1353.       if(!upd_choice[i]) continue; /* Choice-Export disabled */
  1354.       if(upd && upd->choice && upd->choice[i]) {
  1355.          gs_param_string name;
  1356.          name.data       = (const byte *) upd_choice[i][upd->choice[i]];
  1357.          name.size       = strlen((const char *) name.data);
  1358.          name.persistent = true;
  1359.          error = param_write_name(plist,upd_choice[i][0],&name);
  1360.       } else {
  1361.          error = param_write_null(plist,upd_choice[i][0]);
  1362.       }
  1363.       UPD_EXIT_GET(error,udev,plist);
  1364.    }
  1365.  
  1366. /** Export the flags (bool) */
  1367.    for(i = 0; i < countof(upd_flags); ++i) {
  1368.       if(!upd_flags[i]) continue; /* Flag-Export disabled */
  1369.       if(upd) {
  1370.          bool value = upd->flags & ((uint32) 1 << i);
  1371.          error = param_write_bool(plist,upd_flags[i],&value);
  1372.       } else {
  1373.          error = param_write_null(plist,upd_flags[i]);
  1374.       }
  1375.       UPD_EXIT_GET(error,udev,plist);
  1376.    }
  1377.  
  1378. /** Export the ints */
  1379.    for(i = 0; i < countof(upd_ints); ++i) {
  1380.       if(!upd_ints[i]) continue; /* int-Export disabled */
  1381.       if(upd && upd->ints && upd->ints[i]) {
  1382.          int value = upd->ints[i];
  1383.          error = param_write_int( plist,upd_ints[i],&value);
  1384.       } else {
  1385.          error = param_write_null(plist,upd_ints[i]);
  1386.       }
  1387.       UPD_EXIT_GET(error,udev,plist);
  1388.    }
  1389.  
  1390. /** Export the int-arrays */
  1391.    for(i = 0; i < countof(upd_int_a); ++i) {
  1392.       if(!upd_int_a[i]) continue; /* int-Array-Export disabled */
  1393.       if(upd && upd->int_a && upd->int_a[i].size) {
  1394.          error = param_write_int_array( plist,upd_int_a[i],(upd->int_a+i));
  1395.       } else {
  1396.          error = param_write_null(plist,upd_int_a[i]);
  1397.       }
  1398.       UPD_EXIT_GET(error,udev,plist);
  1399.    }
  1400.  
  1401. /** Export the strings */
  1402.    for(i = 0; i < countof(upd_strings); ++i) {
  1403.       if(!upd_strings[i]) continue; /* String-Export disabled */
  1404.       if(upd && upd->strings && upd->strings[i].size) {
  1405.          error = param_write_string( plist,upd_strings[i],(upd->strings+i));
  1406.       } else {
  1407.          error = param_write_null(plist,upd_strings[i]);
  1408.       }
  1409.       UPD_EXIT_GET(error,udev,plist);
  1410.    }
  1411.  
  1412. /** Export the string-Arrays */
  1413.    for(i = 0; i < countof(upd_string_a); ++i) {
  1414.       if(!upd_string_a[i]) continue; /* String-Array-Export disabled */
  1415.       if(upd && upd->string_a && upd->string_a[i].size) {
  1416.          error =
  1417.             param_write_string_array( plist,upd_string_a[i],(upd->string_a+i));
  1418.       } else {
  1419.          error = param_write_null(plist,upd_string_a[i]);
  1420.       }
  1421.       UPD_EXIT_GET(error,udev,plist);
  1422.    }
  1423.  
  1424. /** Export the float-Arrays */
  1425.    for(i = 0; i < countof(upd_float_a); ++i) {
  1426.       if(!upd_float_a[i]) continue; /* Float-Array-Export disabled */
  1427.       if(upd && upd->float_a && upd->float_a[i].size) {
  1428.          error =
  1429.             param_write_float_array( plist,upd_float_a[i],(upd->float_a+i));
  1430.       } else {
  1431.          error = param_write_null(plist,upd_float_a[i]);
  1432.       }
  1433.       UPD_EXIT_GET(error,udev,plist);
  1434.    }
  1435.  
  1436. #if UPD_MESSAGES & UPD_M_TOPCALLS
  1437.    fprintf(stderr,"RETURN: %d = upd_get_params(0x%05lx,0x%05lx)\n",
  1438.        error,(long) udev,(long) plist);
  1439. #endif
  1440.  
  1441.    return error;
  1442. }
  1443.  
  1444. #undef UPD_EXIT_GET
  1445.  
  1446. /* ------------------------------------------------------------------- */
  1447. /* upd_put_params: Load Parameters into the device-structure           */
  1448. /* ------------------------------------------------------------------- */
  1449.  
  1450. private int
  1451. upd_put_params(gx_device *pdev, gs_param_list *plist)
  1452. {
  1453.    upd_device *const      udev       = (upd_device *) pdev;
  1454.    upd_p                  upd        = udev->upd;
  1455.    int                    error      = 0, code,i;
  1456.  
  1457.    float                  MarginsHWResolution[2],Margins[2];
  1458.    gx_device_color_info   color_info;
  1459.    uint32                 flags      = 0;
  1460.    int                   *choice     = NULL;
  1461.    int                   *ints       = NULL;
  1462.    gs_param_int_array    *int_a      = NULL;
  1463.    gs_param_string       *strings    = NULL;
  1464.    gs_param_string_array *string_a   = NULL;
  1465.    gs_param_float_array  *float_a    = NULL, mfa;
  1466.  
  1467. /**
  1468. Error is used for two purposes: either it holds a negative error
  1469. code or it is used as a bitfield, that tells, which parameters
  1470. were actually loaded.  If any of the important parameters changed
  1471. upd_put_params closes the device, since the real parameter-evaluation
  1472. is carried out by upd_open.
  1473. */
  1474.  
  1475. #define UPD_PUT_FLAGS       0x0002
  1476. #define UPD_PUT_CHOICE      0x0004
  1477. #define UPD_PUT_INTS        0x0008
  1478. #define UPD_PUT_INT_A       0x0010
  1479. #define UPD_PUT_STRINGS     0x0020
  1480. #define UPD_PUT_STRING_A    0x0040
  1481. #define UPD_PUT_FLOAT_A     0x0080
  1482. #define UPD_PUT_CHANGEDSIZE 0x0100
  1483.  
  1484. #if UPD_MESSAGES & UPD_M_TOPCALLS
  1485.       fprintf(stderr,"CALL: upd_put_params(0x%05lx,0x%05lx)\n",
  1486.          (long)udev,(long)plist);
  1487. #endif
  1488.  
  1489.  
  1490. /**
  1491. I consider the following part of upd_put_params a bad-nasty-hack-hack
  1492. and i am uncertain, wether it really works in the intended way. I provide it
  1493. just for the case someone is performing nasty-parameter-changes on the
  1494. active device, especially switching the OutputFile. If this happens in
  1495. a situation, where data were written to the file, but the termination
  1496. sequence is required, the driver does it now. (If you want to know, why
  1497. i am writing bad-nasty-hack-hack, visit http://www.zark.com )
  1498. */
  1499.    if(upd && (B_OPEN & udev->upd->flags) && (NULL != udev->file)) {
  1500.  
  1501.       gs_param_string fname = { NULL, 0, false };
  1502.  
  1503.       code = param_read_string(plist,"OutputFile",&fname);
  1504.       if((1 != code) && (0 != code)) {
  1505.          code = param_read_null(plist,"OutputFile");
  1506.          if(0 == code) {
  1507.             fname.data = (const byte *) "";
  1508.             fname.size = 0;
  1509.          }
  1510.       }
  1511.  
  1512.       if((0 == code) && 
  1513.          strncmp((const char *)fname.data,udev->fname,fname.size)) {
  1514.          if(upd->strings && 0 < udev->upd->strings[S_CLOSE].size)
  1515.             fwrite(upd->strings[S_CLOSE].data,1,
  1516.                    upd->strings[S_CLOSE].size,udev->file);
  1517.  
  1518.          upd->flags &= ~B_OPEN;
  1519.       }
  1520.    }
  1521. /* Done with the bad-nasty-hack-hack */
  1522.  
  1523. /**
  1524. The next thing "upd_put_params" does, is a little strange too. It imports
  1525. a readonly-parameter, the version-string. I do not know wether it is still
  1526. required, but some versions of GHOSTSCRIPT disliked it very much, if an
  1527. existing parameter was not touched by the put-operation.
  1528.  
  1529. On the other hand it is the right time to show the basic-outline of the
  1530. parameter-importing flow. Basically the proper "param_read"-procedure
  1531. is called. If it indicated, that the parameter was present, but of the
  1532. wrong type, a read for the null-type is attempted, which is by convention
  1533. somehow an reset to default. This sequence is applied to all the parameters
  1534. and in case of the array-parameters, a succesful null-read is marked by
  1535. setting data and size to 0.
  1536. */
  1537. #if UPD_MESSAGES & UPD_M_SETUP
  1538. #define UPD_PARAM_READ(Param_read,Name,Object)       \
  1539.    code = Param_read(plist,Name,&Object);            \
  1540.    if(0 > code) {                                    \
  1541.       code = param_read_null(plist,Name);            \
  1542.       if(0 == code) memset(&Object,0,sizeof(Object));\
  1543.    }                                                 \
  1544.    if(!code) fprintf(stderr,                         \
  1545.       "upd_put_params: retrieved parameter \"%s\"\n",\
  1546.       Name);                                         \
  1547.    if(0 > code) {                                    \
  1548.       param_signal_error(plist,Name,code);           \
  1549.       if(error > code) error = code;                 \
  1550.    }
  1551. #else
  1552. #define UPD_PARAM_READ(Param_read,Name,Object)       \
  1553.    code = Param_read(plist,Name,&Object);            \
  1554.    if(0 > code) {                                    \
  1555.       code = param_read_null(plist,Name);            \
  1556.       if(0 == code) memset(&Object,0,sizeof(Object));\
  1557.    }                                                 \
  1558.    if(0 > code) {                                    \
  1559.       param_signal_error(plist,Name,code);           \
  1560.       if(error > code) error = code;                 \
  1561.    }
  1562. #endif
  1563.  
  1564.    UPD_PARAM_READ(param_read_string,upd_version,udev->upd_version)
  1565.  
  1566.  
  1567. /**
  1568. upd_put_params begins it's normal work by creating a copy, of
  1569. the data, that it might change, except for color_info that might
  1570. be changed in the device-structure, all manipulations are carried
  1571. out on this copies.
  1572. */
  1573.    MarginsHWResolution[0] = udev->MarginsHWResolution[0];
  1574.    MarginsHWResolution[1] = udev->MarginsHWResolution[1];
  1575.                Margins[0] = udev->Margins[0];
  1576.                Margins[1] = udev->Margins[1];
  1577.  
  1578.    color_info = udev->color_info;
  1579.    if(upd) {
  1580.      flags = upd->flags;
  1581.      UPD_MM_CPY_ARRAY(choice,  upd->choice,  countof(upd_choice),
  1582.         UPD_MM_CPY_VALUE);
  1583.      UPD_MM_CPY_ARRAY(ints,    upd->ints,    countof(upd_ints),
  1584.         UPD_MM_CPY_VALUE);
  1585.      UPD_MM_CPY_ARRAY(int_a,   upd->int_a,   countof(upd_int_a),
  1586.         UPD_MM_CPY_PARAM);
  1587.      UPD_MM_CPY_ARRAY(strings, upd->strings, countof(upd_strings),
  1588.         UPD_MM_CPY_PARAM);
  1589.      UPD_MM_CPY_ARRAY(string_a,upd->string_a,countof(upd_string_a),
  1590.         UPD_MM_CPY_APARAM);
  1591.      UPD_MM_CPY_ARRAY(float_a, upd->float_a, countof(upd_float_a),
  1592.         UPD_MM_CPY_PARAM);
  1593.    } else {
  1594.      flags = 0;
  1595.      UPD_MM_GET_ARRAY(choice,  countof(upd_choice));
  1596.      UPD_MM_GET_ARRAY(ints,    countof(upd_ints));
  1597.      UPD_MM_GET_ARRAY(int_a,   countof(upd_int_a));
  1598.      UPD_MM_GET_ARRAY(strings, countof(upd_strings));
  1599.      UPD_MM_GET_ARRAY(string_a,countof(upd_string_a));
  1600.      UPD_MM_GET_ARRAY(float_a, countof(upd_float_a));
  1601.    }
  1602.  
  1603. /** Import the Multiple-Choices */
  1604.    for(i = 0; countof(upd_choice) > i; ++i) {
  1605.       gs_param_string value = { NULL, 0, false};
  1606.       if(!upd_choice[i][0]) continue;
  1607.       UPD_PARAM_READ(param_read_name,upd_choice[i][0],value);
  1608.       if(0 == code) {
  1609.          if(0 <= error) error |= UPD_PUT_CHOICE;
  1610.          choice[i] = 0;
  1611.          if(0 < value.size) {
  1612.             int j;
  1613.             for(j = 1; upd_choice[i][j]; ++j) {
  1614.                if((strlen(upd_choice[i][j]) == value.size) &&
  1615.                   (0 == strncmp(upd_choice[i][j],
  1616.                                 (char *) value.data,value.size))) {
  1617.                   choice[i] = j;
  1618.                   break;
  1619.                }
  1620.             }
  1621.          }
  1622.       }
  1623.    }
  1624.  
  1625. /** Import the Boolean Values */
  1626.    for(i = 0; countof(upd_flags) > i; ++i) {
  1627.       uint32 bit  = (uint32) 1 << i;
  1628.       bool   flag = flags & bit ? true : false;
  1629.       if(!upd_flags[i]) continue;
  1630.       UPD_PARAM_READ(param_read_bool,upd_flags[i],flag);
  1631.       if(0 == code) {
  1632.          if(0 <= error) error |= UPD_PUT_FLAGS;
  1633.          if(flag) flags |=  bit;
  1634.          else     flags &= ~bit;
  1635.       }
  1636.    }
  1637.  
  1638. /** Import the Integer Values */
  1639.    for(i = 0; countof(upd_ints) > i; ++i) {
  1640.       int value = ints[i];
  1641.       if(!upd_ints[i]) continue;
  1642.       UPD_PARAM_READ(param_read_int,upd_ints[i],value);
  1643.       if(0 == code) {
  1644.          if(0 <= error) error |= UPD_PUT_INTS;
  1645.          ints[i] = value;
  1646.       }
  1647.    }
  1648.  
  1649. /** Import the Integer Arrays */
  1650.    for(i = 0; countof(upd_int_a) > i; ++i) {
  1651.       gs_param_int_array value = int_a[i];
  1652.       if(!upd_int_a[i]) continue;
  1653.       UPD_PARAM_READ(param_read_int_array,upd_int_a[i],value);
  1654.       if(0 == code) {
  1655.          if(0 <= error) error |= UPD_PUT_INT_A;
  1656.          UPD_MM_DEL_PARAM(int_a[i]);
  1657.          if(!value.size) {
  1658.             value.data = NULL;
  1659.             int_a[i]   = value;
  1660.          } else {
  1661.             UPD_MM_CPY_PARAM(int_a[i],value);
  1662.          }
  1663.       }
  1664.    }
  1665.  
  1666. /** Import the Strings */
  1667.    for(i = 0; countof(upd_strings) > i; ++i) {
  1668.       gs_param_string value = strings[i];
  1669.       if(!upd_strings[i]) continue;
  1670.       UPD_PARAM_READ(param_read_string,upd_strings[i],value);
  1671.       if(0 == code) {
  1672.          if(0 <= error) error |= UPD_PUT_STRINGS;
  1673.          UPD_MM_DEL_PARAM(strings[i]);
  1674.          if(!value.size) {
  1675.             value.data = NULL;
  1676.             strings[i]   = value;
  1677.          } else {
  1678.             UPD_MM_CPY_PARAM(strings[i],value);
  1679.          }
  1680.       }
  1681.    }
  1682.  
  1683. /** Import the String Arrays */
  1684.    for(i = 0; countof(upd_string_a) > i; ++i) {
  1685.       gs_param_string_array value = string_a[i];
  1686.       if(!upd_string_a[i]) continue;
  1687.       UPD_PARAM_READ(param_read_string_array,upd_string_a[i],value);
  1688.       if(0 == code) {
  1689.          if(0 <= error) error |= UPD_PUT_STRING_A;
  1690.          UPD_MM_DEL_APARAM(string_a[i]);
  1691.          if(!value.size) {
  1692.             value.data  = NULL;
  1693.             string_a[i] = value;
  1694.          } else {
  1695.             UPD_MM_CPY_APARAM(string_a[i],value);
  1696.          }
  1697.       }
  1698.    }
  1699.  
  1700. /** Import the Float Arrays */
  1701.    for(i = 0; countof(upd_float_a) > i; ++i) {
  1702.       gs_param_float_array value = float_a[i];
  1703.       if(!upd_float_a[i]) continue;
  1704.       UPD_PARAM_READ(param_read_float_array,upd_float_a[i],value);
  1705.       if(0 == code) {
  1706.          if(0 <= error) error |= UPD_PUT_FLOAT_A;
  1707.          UPD_MM_DEL_PARAM(float_a[i]);
  1708.          if(!value.size) {
  1709.             value.data = NULL;
  1710.             float_a[i] = value;
  1711.          } else {
  1712.             UPD_MM_CPY_PARAM(float_a[i],value);
  1713.          }
  1714.       }
  1715.    }
  1716.  
  1717. /**
  1718. Prior to the call to the superclass-put_params, the memory-layout and
  1719. the color-model needs adjustment. This is performed here, if any parameters
  1720. were set.
  1721. In addition to that, Resolution & Margin-Parameters are tested & adjusted.
  1722. */
  1723.    if(0 < error) {
  1724.  
  1725.       int *ip,*ip2,ncomp,nbits;
  1726.  
  1727.       if(6 > int_a[IA_COLOR_INFO].size) {
  1728.          UPD_MM_DEL_PARAM(int_a[IA_COLOR_INFO]);
  1729.          UPD_MM_GET_ARRAY(int_a[IA_COLOR_INFO].data,6);
  1730.          int_a[IA_COLOR_INFO].size = 6;
  1731.       }
  1732.       ip = (int *) int_a[IA_COLOR_INFO].data;
  1733.  
  1734.       if(0 == ip[0]) { /* Try to obtain num_components */
  1735.          switch(choice[C_MAPPER]) {
  1736.             case MAP_GRAY:     ip[0] = 1; break;
  1737.             case MAP_RGBW:     ip[0] = 3; break;
  1738.             case MAP_RGB:      ip[0] = 3; break;
  1739.             case MAP_CMYK:     ip[0] = 4; break;
  1740.             case MAP_CMYKGEN:  ip[0] = 4; break;
  1741.             default:          ip[0] = color_info.num_components; break;
  1742.          }
  1743.       }                /* Try to obtain num_components */
  1744.  
  1745.       switch(choice[C_MAPPER]) {
  1746.          case MAP_GRAY:     ncomp = 1; break;
  1747.          case MAP_RGBW:     ncomp = 4; break;
  1748.          case MAP_RGB:      ncomp = 3; break;
  1749.          case MAP_CMYK:     ncomp = 4; break;
  1750.          case MAP_CMYKGEN:  ncomp = 4; break;
  1751.          default:           ncomp = ip[0]; break;
  1752.       }
  1753.       if(UPD_CMAP_MAX < ncomp) ncomp = UPD_CMAP_MAX;
  1754.  
  1755.       if(ncomp > int_a[IA_COMPBITS].size) { /* Default ComponentBits */
  1756.          UPD_MM_GET_ARRAY(ip2,ncomp);
  1757.          nbits = 32 / ncomp;
  1758.          if(8 < nbits) nbits = 8;
  1759.          for(i = 0; i < ncomp; ++i) ip2[i] = nbits;
  1760.          UPD_MM_DEL_PARAM(int_a[IA_COMPBITS]);
  1761.          int_a[IA_COMPBITS].data = ip2;
  1762.          int_a[IA_COMPBITS].size = ncomp;
  1763.       }                                     /* Default ComponentBits */
  1764.  
  1765.       if(ncomp > int_a[IA_COMPSHIFT].size) {  /* Default ComponentShift */
  1766.          nbits = 0;
  1767.          for(i = 0; i < ncomp; ++i) nbits += int_a[IA_COMPBITS].data[i];
  1768.          UPD_MM_GET_ARRAY(ip2,ncomp);
  1769.          for(i = 0; i < ncomp; ++i) {
  1770.             ip2[i] = nbits - int_a[IA_COMPBITS].data[i];
  1771.             nbits -= int_a[IA_COMPBITS].data[i];
  1772.          }
  1773.          UPD_MM_DEL_PARAM(int_a[IA_COMPSHIFT]);
  1774.          int_a[IA_COMPSHIFT].data = ip2;
  1775.          int_a[IA_COMPSHIFT].size = ncomp;
  1776.       }                                       /* Default ComponentShift */
  1777.  
  1778.       if(0 == ip[1]) { /* Try to compute the depth */
  1779.          nbits = 0;
  1780.          for(i = 0; i < ncomp; ++i) {
  1781.             if(nbits < (int_a[IA_COMPBITS].data[i] +
  1782.                         int_a[IA_COMPSHIFT].data[i]))
  1783.                nbits =  int_a[IA_COMPBITS].data[i] +
  1784.                         int_a[IA_COMPSHIFT].data[i];
  1785.          }
  1786.          if(      1 >= nbits) nbits =  1;
  1787.          else if( 2 >= nbits) nbits =  2;
  1788.          else if( 4 >= nbits) nbits =  4;
  1789.          else if( 8 >= nbits) nbits =  8;
  1790.          else if(16 >= nbits) nbits = 16;
  1791.          else if(24 >= nbits) nbits = 24;
  1792.          else                 nbits = 32;
  1793.  
  1794.          ip[1] = nbits;
  1795.  
  1796.       }                /* Try to compute the depth */
  1797.  
  1798.       if(0 == ip[2]) { /* Number of Gray-Levels */
  1799.          nbits = 0;
  1800.          for(i = 0; i < ncomp; ++i) if(nbits < int_a[IA_COMPBITS].data[i])
  1801.             nbits = int_a[IA_COMPBITS].data[i];
  1802.          if(nbits > 8) nbits = 8;
  1803.          ip[2] = (1 << nbits) - 1;
  1804.       }                /* Number of Gray-Levels */
  1805.  
  1806.       if(0 == ip[3] && 1 < ip[0]) { /* Number of Colors */
  1807.          nbits = 0;
  1808.          for(i = 0; i < ip[0]; ++i) nbits += int_a[IA_COMPBITS].data[i];
  1809.          if(nbits > 8) nbits = 8;
  1810.          ip[3] = (1 << nbits) - 1;
  1811.       }                             /* Number of Colors */
  1812.  
  1813.       if(0 == ip[4]) { /* Gray-Ramp */
  1814.          nbits = 0;
  1815.          for(i = 0; i < ncomp; ++i) if(nbits < int_a[IA_COMPBITS].data[i])
  1816.             nbits = int_a[IA_COMPBITS].data[i];
  1817.          if(2 < nbits) ip[4] = 5;
  1818.          else          ip[4] = 2;
  1819.       }                /* Gray-Ramp */
  1820.  
  1821.       if(0 == ip[5] && 1 < ip[0]) { /* Color-Ramp */
  1822.          nbits = 0;
  1823.          for(i = 0; i < ncomp; ++i) if(nbits < int_a[IA_COMPBITS].data[i])
  1824.             nbits = int_a[IA_COMPBITS].data[i];
  1825.          if(2 < nbits) ip[5] = 5;
  1826.          else          ip[5] = 2;
  1827.       }                             /* Color-Ramp */
  1828.  
  1829.       udev->color_info.num_components = ip[0];
  1830.       udev->color_info.depth          = ip[1];
  1831.       udev->color_info.max_gray       = (gx_color_value) ip[2];
  1832.       udev->color_info.max_color      = (gx_color_value) ip[3];
  1833.       udev->color_info.dither_grays   = (gx_color_value) ip[4];
  1834.       udev->color_info.dither_colors  = (gx_color_value) ip[5];
  1835.  
  1836. /*
  1837.  * Now we're dealing with the Resolution- & Margin-Stuff
  1838.  * (This is close to be a bad-nasty-hack-hack)
  1839.  */
  1840.       if((0 == param_read_float_array(plist,"HWResolution",&mfa)) &&
  1841.          (2 == mfa.size) && (0 != mfa.data)) {
  1842.          udev->MarginsHWResolution[0] = mfa.data[0];
  1843.          udev->MarginsHWResolution[1] = mfa.data[1];
  1844.       } else {
  1845.          udev->MarginsHWResolution[0] = udev->HWResolution[0];
  1846.          udev->MarginsHWResolution[1] = udev->HWResolution[1];
  1847.       }
  1848.  
  1849.       if((0 == param_read_float_array(plist,".HWMargins",&mfa)) &&
  1850.          (4 == mfa.size) && (0 != mfa.data)) {
  1851.          udev->Margins[0] = -mfa.data[0] * udev->MarginsHWResolution[0] / 72.0;
  1852.          udev->Margins[1] = -mfa.data[3] * udev->MarginsHWResolution[1] / 72.0;
  1853.       }
  1854.    }                                       /* Change the color-Info */
  1855.  
  1856. /* Call the superclass-put_params now */
  1857.    code = gdev_prn_put_params((gx_device *)udev,plist);
  1858.    if(0 > code) error = code;
  1859.  
  1860. /**
  1861. If the superclass-"put_params" went o.k. too, then the new parameters are
  1862. transferred into the device-structure. In the case of "uniprint", this may
  1863.  
  1864.  1. Close the device, which might fail.
  1865.  2. Allocate new memory for the upd-specific structure, that might fail too.
  1866.  
  1867. */
  1868. /* *HGS* recognize a changed device geometry */
  1869.    if( udev->upd &&                              /* HGS */
  1870.       ((udev->width  != udev->upd->pdwidth) ||   /* HGS */
  1871.       (udev->height != udev->upd->pdheight)  ))  /* HGS */
  1872.         error |= UPD_PUT_CHANGEDSIZE;            /* HGS */
  1873.  
  1874.    if(0 < error && udev->is_open) {
  1875.       code = gs_closedevice((gx_device *)udev);
  1876.       if(0 > code) error = code;
  1877.    }
  1878.  
  1879.    if(0 < error) { /* Actually something loaded without error */
  1880.  
  1881.       if(!(upd = udev->upd)) {
  1882.         UPD_MM_GET_ARRAY(udev->upd,1);
  1883.         upd = udev->upd;
  1884.       } else {
  1885.         UPD_MM_DEL_ARRAY(upd->choice,  countof(upd_choice),  UPD_MM_DEL_VALUE);
  1886.         UPD_MM_DEL_ARRAY(upd->ints,    countof(upd_ints),    UPD_MM_DEL_VALUE);
  1887.         UPD_MM_DEL_ARRAY(upd->int_a,   countof(upd_int_a),   UPD_MM_DEL_PARAM);
  1888.         UPD_MM_DEL_ARRAY(upd->strings, countof(upd_strings), UPD_MM_DEL_PARAM);
  1889.         UPD_MM_DEL_ARRAY(upd->string_a,countof(upd_string_a),UPD_MM_DEL_APARAM);
  1890.         UPD_MM_DEL_ARRAY(upd->float_a, countof(upd_float_a), UPD_MM_DEL_PARAM);
  1891.       }
  1892.  
  1893.       upd->choice   = choice;
  1894.       upd->flags    = flags;
  1895.       upd->ints     = ints;
  1896.       upd->int_a    = int_a;
  1897.       upd->strings  = strings;
  1898.       upd->string_a = string_a;
  1899.       upd->float_a  = float_a;
  1900.  
  1901.       if(0 < error) error = 0;
  1902.  
  1903.    } else {
  1904.  
  1905.                   udev->Margins[0] =             Margins[0];
  1906.                   udev->Margins[1] =             Margins[1];
  1907.       udev->MarginsHWResolution[0] = MarginsHWResolution[0];
  1908.       udev->MarginsHWResolution[1] = MarginsHWResolution[1];
  1909.  
  1910.       udev->color_info = color_info;
  1911.       UPD_MM_DEL_ARRAY(choice,  countof(upd_choice),  UPD_MM_DEL_VALUE);
  1912.       UPD_MM_DEL_ARRAY(ints,    countof(upd_ints),    UPD_MM_DEL_VALUE);
  1913.       UPD_MM_DEL_ARRAY(int_a,   countof(upd_int_a),   UPD_MM_DEL_PARAM);
  1914.       UPD_MM_DEL_ARRAY(strings, countof(upd_strings), UPD_MM_DEL_PARAM);
  1915.       UPD_MM_DEL_ARRAY(string_a,countof(upd_string_a),UPD_MM_DEL_APARAM);
  1916.       UPD_MM_DEL_ARRAY(float_a, countof(upd_float_a), UPD_MM_DEL_PARAM);
  1917.  
  1918.    }
  1919.  
  1920. /*
  1921.  * upd_put_params keeps the Procedures upd to date
  1922.  */
  1923.  
  1924.    upd_procs_map(udev);
  1925.  
  1926.  
  1927. #if UPD_MESSAGES & UPD_M_TOPCALLS
  1928.       fprintf(stderr,"RETURN: %d = upd_put_params(0x%05lx,0x%05lx)\n",
  1929.          error,(long) udev, (long) plist);
  1930. #endif
  1931.  
  1932.    return error;
  1933. }
  1934.  
  1935. /* ------------------------------------------------------------------- */
  1936. /* upd_cmyk_icolor: KCMY->KCMY-Index Mapping                           */
  1937. /* ------------------------------------------------------------------- */
  1938. /**
  1939. The next Routines, that follow, are the color-mapping routines.
  1940. GHOSTSCRIPT talks about "gx_color_values" and the driver has
  1941. to merge the 1, 3 or four values into up to 32 Bits, that means
  1942. it is necessary to do some truncation and shifting. For the truncation
  1943. "uniprint" uses the internal function "upd_truncate" and "upd_expand"
  1944. reverses this in the reverse-mapping procedures.
  1945. */
  1946.  
  1947. private gx_color_index
  1948. upd_cmyk_icolor(gx_device *pdev,
  1949.    gx_color_value c, gx_color_value m, gx_color_value y,gx_color_value k)
  1950. {
  1951.    const upd_p     upd = ((upd_device *)pdev)->upd;
  1952.    gx_color_index  rv;
  1953.  
  1954. /**
  1955. All 4-Component-Modi have to deal with the Problem, that a value
  1956. with all bits set can be produced, which is treated as an error-return
  1957. from the mapping-functions. But with RGBW or KCMY, there is a neat
  1958. trick: Grayscale are transferred as RGB/CMY=0 and holding Data only
  1959. in the W- or K-Component.
  1960. */
  1961.  
  1962.    if((c == m) && (m == y)) {
  1963.  
  1964.       rv = upd_truncate(upd,0,c > k ? c : k);
  1965.  
  1966.    } else {
  1967.  
  1968.       rv  = upd_truncate(upd,0,k) | upd_truncate(upd,1,c)
  1969.           | upd_truncate(upd,2,m) | upd_truncate(upd,3,y);
  1970.  
  1971.  
  1972. /* It might still become a "gx_no_color_value" due to truncation, thus: */
  1973.  
  1974.       if(rv == gx_no_color_index) rv ^= 1;
  1975.    }
  1976.  
  1977.  
  1978. #if UPD_MESSAGES & UPD_M_MAPCALLS
  1979.   fprintf(stderr,
  1980. "cmyk_icolor: (%5.1f,%5.1f,%5.1f,%5.1f) : (%5.1f,%5.1f,%5.1f,%5.1f) : 0x%0*lx\n",
  1981.    255.0 * (double) c / (double) gx_max_color_value,
  1982.    255.0 * (double) m / (double) gx_max_color_value,
  1983.    255.0 * (double) y / (double) gx_max_color_value,
  1984.    255.0 * (double) k / (double) gx_max_color_value,
  1985.    255.0 * (double) ((rv >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
  1986.                  / (double) upd->cmap[1].bitmsk,
  1987.    255.0 * (double) ((rv >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
  1988.                  / (double) upd->cmap[2].bitmsk,
  1989.    255.0 * (double) ((rv >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
  1990.                  / (double) upd->cmap[3].bitmsk,
  1991.    255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
  1992.                  / (double) upd->cmap[0].bitmsk,
  1993.    (pdev->color_info.depth + 3)>>2,rv);
  1994. #endif
  1995.  
  1996.    return rv;
  1997. }
  1998.  
  1999. /* ------------------------------------------------------------------- */
  2000. /* upd_icolor_rgb: Stored KCMY back to a RGB                           */
  2001. /* ------------------------------------------------------------------- */
  2002.  
  2003. private int
  2004. upd_icolor_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
  2005. {
  2006.    const upd_p     upd = ((upd_device *)pdev)->upd;
  2007.    gx_color_value c,m,y,k;
  2008.  
  2009. /*
  2010.  * Expand to the Component-Values
  2011.  */
  2012.    k = upd_expand(upd,0,color);
  2013.    c = upd_expand(upd,1,color);
  2014.    m = upd_expand(upd,2,color);
  2015.    y = upd_expand(upd,3,color);
  2016.  
  2017. /*
  2018.  * Then Invert and subtract K from the colors
  2019.  */
  2020.    prgb[0] = gx_max_color_value - c;
  2021.    if(prgb[0] > k) prgb[0] -= k;
  2022.    else            prgb[0]  = 0;
  2023.  
  2024.    prgb[1] = gx_max_color_value - m;
  2025.    if(prgb[1] > k) prgb[1] -= k;
  2026.    else            prgb[1]  = 0;
  2027.  
  2028.    prgb[2] = gx_max_color_value - y;
  2029.    if(prgb[2] > k) prgb[2] -= k;
  2030.    else            prgb[2]  = 0;
  2031.  
  2032.  
  2033. #if UPD_MESSAGES & UPD_M_MAPCALLS
  2034.    fprintf(stderr,
  2035.     "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",
  2036.     (pdev->color_info.depth + 3)>>2,color,
  2037.     255.0 * (double) ((color >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
  2038.                      / (double) upd->cmap[1].bitmsk,
  2039.     255.0 * (double) ((color >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
  2040.                      / (double) upd->cmap[2].bitmsk,
  2041.     255.0 * (double) ((color >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
  2042.                      / (double) upd->cmap[3].bitmsk,
  2043.     255.0 * (double) ((color >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
  2044.                      / (double) upd->cmap[0].bitmsk,
  2045.     255.0 * (double)   c     / (double) gx_max_color_value,
  2046.     255.0 * (double)   m     / (double) gx_max_color_value,
  2047.     255.0 * (double)   y     / (double) gx_max_color_value,
  2048.     255.0 * (double)   k     / (double) gx_max_color_value,
  2049.     255.0 * (double) prgb[0] / (double) gx_max_color_value,
  2050.     255.0 * (double) prgb[1] / (double) gx_max_color_value,
  2051.     255.0 * (double) prgb[2] / (double) gx_max_color_value);
  2052. #endif
  2053.  
  2054.    return 0;
  2055. }
  2056.  
  2057. /* ------------------------------------------------------------------- */
  2058. /* upd_rgb_1color: Grayscale-RGB->Grayscale-index-Mapping              */
  2059. /* ------------------------------------------------------------------- */
  2060.  
  2061. private gx_color_index
  2062. upd_rgb_1color(gx_device *pdev,
  2063.    gx_color_value r, gx_color_value g, gx_color_value b)
  2064. {
  2065.    const upd_p     upd = ((upd_device *)pdev)->upd;
  2066.    gx_color_index  rv;
  2067.  
  2068.    rv = upd_truncate(upd,0,r);
  2069.  
  2070. #if UPD_MESSAGES & UPD_M_MAPCALLS
  2071.    fprintf(stderr,
  2072.       "rgb_1color: (%5.1f,%5.1f,%5.1f) : (%5.1f) : 0x%0*lx\n",
  2073.       255.0 * (double) r  / (double) gx_max_color_value,
  2074.       255.0 * (double) g  / (double) gx_max_color_value,
  2075.       255.0 * (double) b  / (double) gx_max_color_value,
  2076.       255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
  2077.                     / (double) upd->cmap[0].bitmsk,
  2078.       (pdev->color_info.depth + 3)>>2,rv);
  2079. #endif
  2080.  
  2081.    return rv;
  2082. }
  2083.  
  2084. /* ------------------------------------------------------------------- */
  2085. /* upd_1color_rgb: reversal of the above                               */
  2086. /* ------------------------------------------------------------------- */
  2087.  
  2088. private int
  2089. upd_1color_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
  2090. {
  2091.    const upd_p     upd = ((upd_device *)pdev)->upd;
  2092. /*
  2093.  * Actual task: expand to full range of gx_color_value
  2094.  */
  2095.    prgb[0] = upd_expand(upd,0,color);
  2096.  
  2097.    prgb[2] = prgb[1] = prgb[0];
  2098.  
  2099. #if UPD_MESSAGES & UPD_M_MAPCALLS
  2100.    fprintf(stderr,"1color_rgb: 0x%0*lx -> %5.1f -> (%5.1f,%5.1f,%5.1f)\n",
  2101.       (pdev->color_info.depth + 3)>>2,color,
  2102.       255.0 * (double) ((color >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
  2103.                        / (double) upd->cmap[0].bitmsk,
  2104.       255.0 * (double) prgb[0] / (double) gx_max_color_value,
  2105.       255.0 * (double) prgb[1] / (double) gx_max_color_value,
  2106.       255.0 * (double) prgb[2] / (double) gx_max_color_value);
  2107. #endif
  2108.  
  2109.    return 0;
  2110. }
  2111.  
  2112. /* ------------------------------------------------------------------- */
  2113. /* upd_rgb_3color: component-wise RGB->RGB-Mapping                     */
  2114. /* ------------------------------------------------------------------- */
  2115.  
  2116. private gx_color_index
  2117. upd_rgb_3color(gx_device *pdev,
  2118.    gx_color_value r, gx_color_value g, gx_color_value b)
  2119. {
  2120.    const upd_p     upd = ((upd_device *)pdev)->upd;
  2121.    gx_color_index  rv;
  2122.  
  2123.    rv = upd_truncate(upd,0,r) | upd_truncate(upd,1,g) | upd_truncate(upd,2,b);
  2124.    if(rv == gx_no_color_index) rv ^= 1;
  2125.  
  2126. #if UPD_MESSAGES & UPD_M_MAPCALLS
  2127.   fprintf(stderr,
  2128.    "rgb_3color: (%5.1f,%5.1f,%5.1f) : (%5.1f,%5.1f,%5.1f) : 0x%0*lx\n",
  2129.    255.0 * (double) r / (double) gx_max_color_value,
  2130.    255.0 * (double) g / (double) gx_max_color_value,
  2131.    255.0 * (double) b / (double) gx_max_color_value,
  2132.    255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
  2133.                  / (double) upd->cmap[0].bitmsk,
  2134.    255.0 * (double) ((rv >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
  2135.                  / (double) upd->cmap[1].bitmsk,
  2136.    255.0 * (double) ((rv >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
  2137.                  / (double) upd->cmap[2].bitmsk,
  2138.    (pdev->color_info.depth + 3)>>2,rv);
  2139. #endif
  2140.  
  2141.    return rv;
  2142. }
  2143.  
  2144. /* ------------------------------------------------------------------- */
  2145. /* upd_3color_rgb: reversal of the above                               */
  2146. /* ------------------------------------------------------------------- */
  2147.  
  2148. private int
  2149. upd_3color_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
  2150. {
  2151.    const upd_p     upd = ((upd_device *)pdev)->upd;
  2152.  
  2153.    prgb[0] = upd_expand(upd,0,color);
  2154.    prgb[1] = upd_expand(upd,1,color);
  2155.    prgb[2] = upd_expand(upd,2,color);
  2156.  
  2157. #if UPD_MESSAGES & UPD_M_MAPCALLS
  2158.    fprintf(stderr,
  2159.      "3color_rgb: 0x%0*lx -> (%5.1f,%5.1f,%5.1f) -> (%5.1f,%5.1f,%5.1f)\n",
  2160.       (pdev->color_info.depth + 3)>>2,color,
  2161.       255.0 * (double) ((color >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
  2162.                        / (double) upd->cmap[0].bitmsk,
  2163.       255.0 * (double) ((color >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
  2164.                        / (double) upd->cmap[1].bitmsk,
  2165.       255.0 * (double) ((color >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
  2166.                        / (double) upd->cmap[2].bitmsk,
  2167.  
  2168.       255.0 * (double) prgb[0] / (double) gx_max_color_value,
  2169.       255.0 * (double) prgb[1] / (double) gx_max_color_value,
  2170.       255.0 * (double) prgb[2] / (double) gx_max_color_value);
  2171. #endif
  2172.  
  2173.    return 0;
  2174. }
  2175.  
  2176. /* ------------------------------------------------------------------- */
  2177. /* upd_rgb_4color: Create an WRGB-Index from RGB                       */
  2178. /* ------------------------------------------------------------------- */
  2179.  
  2180. private gx_color_index
  2181. upd_rgb_4color(gx_device *pdev,
  2182.    gx_color_value r, gx_color_value g, gx_color_value b)
  2183. {
  2184.    const upd_p     upd = ((upd_device *)pdev)->upd;
  2185.    gx_color_index  rv;
  2186.  
  2187.    if((r == g) && (g == b)) {
  2188.  
  2189.       rv = upd_truncate(upd,0,r);
  2190.  
  2191.    } else {
  2192.  
  2193.       gx_color_value w = g < r ? g : r; w = w < b ? w : b; /* Minimum */
  2194.  
  2195.       rv = upd_truncate(upd,0,w) | upd_truncate(upd,1,r) |
  2196.            upd_truncate(upd,2,g) | upd_truncate(upd,3,b);
  2197.  
  2198. /* It might still become a "gx_no_color_value" due to truncation, thus: */
  2199.  
  2200.       if(rv == gx_no_color_index) rv ^= 1;
  2201.    }
  2202.  
  2203. #if UPD_MESSAGES & UPD_M_MAPCALLS
  2204.   fprintf(stderr,
  2205.    "rgb_4color: (%5.1f,%5.1f,%5.1f) : (%5.1f,%5.1f,%5.1f,%5.1f) : 0x%0*lx\n",
  2206.    255.0 * (double) r / (double) gx_max_color_value,
  2207.    255.0 * (double) g / (double) gx_max_color_value,
  2208.    255.0 * (double) b / (double) gx_max_color_value,
  2209.    255.0 * (double) ((rv >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
  2210.                  / (double) upd->cmap[1].bitmsk,
  2211.    255.0 * (double) ((rv >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
  2212.                  / (double) upd->cmap[2].bitmsk,
  2213.    255.0 * (double) ((rv >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
  2214.                  / (double) upd->cmap[3].bitmsk,
  2215.    255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
  2216.                  / (double) upd->cmap[0].bitmsk,
  2217.    (pdev->color_info.depth + 3)>>2,rv);
  2218. #endif
  2219.  
  2220.    return rv;
  2221. }
  2222. /* ------------------------------------------------------------------- */
  2223. /* upd_4color_rgb: Stored WRGB-Index back to a RGB                     */
  2224. /* ------------------------------------------------------------------- */
  2225.  
  2226. private int
  2227. upd_4color_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
  2228. {
  2229.    const upd_p     upd = ((upd_device *)pdev)->upd;
  2230.  
  2231. /*
  2232.  * Expand to the Component-Values
  2233.  */
  2234.    prgb[0] = upd_expand(upd,1,color);
  2235.    prgb[1] = upd_expand(upd,2,color);
  2236.    prgb[2] = upd_expand(upd,3,color);
  2237.  
  2238. /* Revert our Grayscale-Trick: */
  2239.    if(!(prgb[0] || prgb[1] || prgb[2]))
  2240.       prgb[0] = prgb[1] = prgb[2] = upd_expand(upd,0,color);
  2241.  
  2242.  
  2243. #if UPD_MESSAGES & UPD_M_MAPCALLS
  2244.    fprintf(stderr,
  2245.     "4color_rgb: 0x%0*lx -> (%5.1f,%5.1f,%5.1f,%5.1f) -> (%5.1f,%5.1f,%5.1f)\n",
  2246.     (pdev->color_info.depth + 3)>>2,color,
  2247.     255.0 * (double) ((color >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
  2248.                      / (double) upd->cmap[1].bitmsk,
  2249.     255.0 * (double) ((color >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
  2250.                      / (double) upd->cmap[2].bitmsk,
  2251.     255.0 * (double) ((color >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
  2252.                      / (double) upd->cmap[3].bitmsk,
  2253.     255.0 * (double) ((color >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
  2254.                      / (double) upd->cmap[0].bitmsk,
  2255.     255.0 * (double) prgb[0] / (double) gx_max_color_value,
  2256.     255.0 * (double) prgb[1] / (double) gx_max_color_value,
  2257.     255.0 * (double) prgb[2] / (double) gx_max_color_value);
  2258. #endif
  2259.  
  2260.    return 0;
  2261. }
  2262.  
  2263. /* ------------------------------------------------------------------- */
  2264. /* upd_cmyk_kcolor: KCMY->KCMY-Index Mapping with Black Generation     */
  2265. /* ------------------------------------------------------------------- */
  2266.  
  2267. private gx_color_index
  2268. upd_cmyk_kcolor(gx_device *pdev,
  2269.    gx_color_value c, gx_color_value m, gx_color_value y,gx_color_value k)
  2270. {
  2271.    const upd_p     upd = ((upd_device *)pdev)->upd;
  2272.    gx_color_index  rv;
  2273.    gx_color_value  black;
  2274.  
  2275.    if((c == m) && (m == y)) {
  2276.  
  2277.       black = c > k ? c : k;
  2278.       rv = upd_truncate(upd,0,black);
  2279.  
  2280.    } else {
  2281.  
  2282.       if(k) {
  2283.          black = k;
  2284.       } else {
  2285.          black = c     < m ? c     : m;
  2286.          black = black < y ? black : y;
  2287.       }
  2288.  
  2289.       rv  = upd_truncate(upd,0,black) | upd_truncate(upd,1,c)
  2290.           | upd_truncate(upd,2,m)     | upd_truncate(upd,3,y);
  2291.  
  2292. /* It might still become a "gx_no_color_value" due to truncation, thus: */
  2293.  
  2294.       if(rv == gx_no_color_index) rv ^= 1;
  2295.    }
  2296.  
  2297.  
  2298. #if UPD_MESSAGES & UPD_M_MAPCALLS
  2299.   fprintf(stderr,
  2300. "cmyk_kcolor: (%5.1f,%5.1f,%5.1f,%5.1f) : (%5.1f,%5.1f,%5.1f,%5.1f) : 0x%0*lx\n",
  2301.    255.0 * (double) c / (double) gx_max_color_value,
  2302.    255.0 * (double) m / (double) gx_max_color_value,
  2303.    255.0 * (double) y / (double) gx_max_color_value,
  2304.    255.0 * (double) k / (double) gx_max_color_value,
  2305.    255.0 * (double) ((rv >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
  2306.                  / (double) upd->cmap[1].bitmsk,
  2307.    255.0 * (double) ((rv >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
  2308.                  / (double) upd->cmap[2].bitmsk,
  2309.    255.0 * (double) ((rv >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
  2310.                  / (double) upd->cmap[3].bitmsk,
  2311.    255.0 * (double) ((rv >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
  2312.                  / (double) upd->cmap[0].bitmsk,
  2313.    (pdev->color_info.depth + 3)>>2,rv);
  2314. #endif
  2315.  
  2316.    return rv;
  2317. }
  2318.  
  2319. /* ------------------------------------------------------------------- */
  2320. /* upd_kcolor_rgb: Stored CMY+generated K back to a RGB                */
  2321. /* ------------------------------------------------------------------- */
  2322.  
  2323. private int
  2324. upd_kcolor_rgb(gx_device *pdev, gx_color_index color, gx_color_value prgb[3])
  2325. {
  2326.    const upd_p     upd = ((upd_device *)pdev)->upd;
  2327.    gx_color_value c,m,y,k;
  2328.  
  2329. /*
  2330.  * Expand to the Component-Values
  2331.  */
  2332.    k = upd_expand(upd,0,color);
  2333.    c = upd_expand(upd,1,color);
  2334.    m = upd_expand(upd,2,color);
  2335.    y = upd_expand(upd,3,color);
  2336.  
  2337. /*
  2338.  * Check for plain Gray-Values
  2339.  */
  2340.    if(!(c | m | y )) {
  2341.  
  2342.       prgb[2] = prgb[1] = prgb[0] = gx_max_color_value - k;
  2343.  
  2344.    } else {
  2345.       prgb[0] = gx_max_color_value - c;
  2346.       prgb[1] = gx_max_color_value - m;
  2347.       prgb[2] = gx_max_color_value - y;
  2348.    }
  2349.  
  2350. #if UPD_MESSAGES & UPD_M_MAPCALLS
  2351.    fprintf(stderr,
  2352.     "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",
  2353.     (pdev->color_info.depth + 3)>>2,color,
  2354.     255.0 * (double) ((color >> upd->cmap[1].bitshf) & upd->cmap[1].bitmsk)
  2355.                      / (double) upd->cmap[1].bitmsk,
  2356.     255.0 * (double) ((color >> upd->cmap[2].bitshf) & upd->cmap[2].bitmsk)
  2357.                      / (double) upd->cmap[2].bitmsk,
  2358.     255.0 * (double) ((color >> upd->cmap[3].bitshf) & upd->cmap[3].bitmsk)
  2359.                      / (double) upd->cmap[3].bitmsk,
  2360.     255.0 * (double) ((color >> upd->cmap[0].bitshf) & upd->cmap[0].bitmsk)
  2361.                      / (double) upd->cmap[0].bitmsk,
  2362.     255.0 * (double)   c     / (double) gx_max_color_value,
  2363.     255.0 * (double)   m     / (double) gx_max_color_value,
  2364.     255.0 * (double)   y     / (double) gx_max_color_value,
  2365.     255.0 * (double)   k     / (double) gx_max_color_value,
  2366.     255.0 * (double) prgb[0] / (double) gx_max_color_value,
  2367.     255.0 * (double) prgb[1] / (double) gx_max_color_value,
  2368.     255.0 * (double) prgb[2] / (double) gx_max_color_value);
  2369. #endif
  2370.  
  2371.    return 0;
  2372. }
  2373.  
  2374. /* ------------------------------------------------------------------- */
  2375. /* NOTE: Beyond this point only "uniprint"-special-items.              */
  2376. /* ------------------------------------------------------------------- */
  2377.  
  2378. /* ------------------------------------------------------------------- */
  2379. /* Return the gx_color_value for a given component                     */
  2380. /* ------------------------------------------------------------------- */
  2381.  
  2382. private gx_color_value
  2383. upd_expand(upd_pc upd,int i,uint32 ci)
  2384. {
  2385.    const updcmap_pc cmap = upd->cmap + i;    /* Writing-Shortcut */
  2386.  
  2387.    ci = (ci >> cmap->bitshf) & cmap->bitmsk; /* Extract the component */
  2388.    if(!cmap->rise) ci = cmap->bitmsk - ci;   /* Invert, if necessary */
  2389. /* no Truncation/Expansion on full range */
  2390.    if(gx_color_value_bits > cmap->bits) return cmap->code[ci];
  2391.    else                                 return (gx_color_value) ci;
  2392. }
  2393. /* That's simple, isn't it? */
  2394.  
  2395. /* ------------------------------------------------------------------- */
  2396. /* Truncate a gx_color_value to the desired number of bits.            */
  2397. /* ------------------------------------------------------------------- */
  2398.  
  2399. private uint32
  2400. upd_truncate(upd_pc upd,int i,gx_color_value v) {
  2401.    const updcmap_pc cmap = upd->cmap + i;
  2402.    int32           s; /* step size */
  2403.    gx_color_value *p; /* value-pointer */
  2404.  
  2405.    if(0 == cmap->bits) {                          /* trivial case */
  2406.  
  2407.       v = 0;
  2408.  
  2409.    } else if(gx_color_value_bits > cmap->bits) { /* really truncate ? */
  2410.  
  2411.       p = cmap->code + ((cmap->bitmsk + 1) >> 1);
  2412.       s =              ((cmap->bitmsk + 1) >> 2);
  2413. /*
  2414.  * Perform search in monotonic code-array
  2415.  */
  2416.       while(s > 0) {
  2417.          if(v > *p) {           /* we're below */
  2418.             p += s;
  2419.          } else if(v < p[-1]) { /* we're ahead for sure */
  2420.             p -= s;
  2421.          } else {
  2422. /* years ago, i knew what this was good for */
  2423.             if((v-p[-1]) < (p[0]-v)) p -= 1;
  2424.             break;
  2425.          }
  2426.          s >>= 1;
  2427.       }
  2428.       if((v-p[-1]) < (p[0]-v)) p -= 1;
  2429.       v = p - cmap->code;
  2430.    }
  2431.  
  2432.    if(!cmap->rise) v = cmap->bitmsk - v; /* Again reverse, if necessary */
  2433.  
  2434.    return ((uint32) v) << cmap->bitshf;
  2435. }
  2436.  
  2437. /* ------------------------------------------------------------------- */
  2438. /* upd_open_map: install the color-mapping                             */
  2439. /* ------------------------------------------------------------------- */
  2440.  
  2441. private int
  2442. upd_open_map(upd_device *udev)
  2443. {
  2444.    const upd_p      upd   = udev->upd;
  2445.    int imap;
  2446.  
  2447. /** _always_ initialize crucial Values! */
  2448.    for(imap = 0; UPD_CMAP_MAX > imap; ++imap) upd->cmap[imap].code   = NULL;
  2449.    upd->ncomp = 0;
  2450.  
  2451. /** There should not be an error yet */
  2452.    if(B_ERROR & upd->flags)    imap = 0;
  2453.  
  2454. /** Establish the xfer-Indices */
  2455.    if(imap) {
  2456.       for(imap = 0; UPD_CMAP_MAX > imap; ++imap) {
  2457.          upd->cmap[imap].xfer = -1;
  2458.          upd->cmap[imap].bits =  0;
  2459.       }
  2460.       switch(upd->choice[C_MAPPER]) {
  2461.          case MAP_GRAY:
  2462.             upd->cmap[0].xfer = FA_WXFER;
  2463.          break;
  2464.          case MAP_RGBW:
  2465.             upd->cmap[0].xfer = FA_WXFER;
  2466.             upd->cmap[1].xfer = FA_RXFER;
  2467.             upd->cmap[2].xfer = FA_GXFER;
  2468.             upd->cmap[3].xfer = FA_BXFER;
  2469.          break;
  2470.          case MAP_RGB:
  2471.             upd->cmap[0].xfer = FA_RXFER;
  2472.             upd->cmap[1].xfer = FA_GXFER;
  2473.             upd->cmap[2].xfer = FA_BXFER;
  2474.          break;
  2475.          case MAP_CMYK:
  2476.             upd->cmap[0].xfer = FA_KXFER;
  2477.             upd->cmap[1].xfer = FA_CXFER;
  2478.             upd->cmap[2].xfer = FA_MXFER;
  2479.             upd->cmap[3].xfer = FA_YXFER;
  2480.          break;
  2481.          case MAP_CMYKGEN:
  2482.             upd->cmap[0].xfer = FA_KXFER;
  2483.             upd->cmap[1].xfer = FA_CXFER;
  2484.             upd->cmap[2].xfer = FA_MXFER;
  2485.             upd->cmap[3].xfer = FA_YXFER;
  2486.          break;
  2487.          default:
  2488. #if         UPD_MESSAGES & UPD_M_WARNING
  2489.                if(upd_choice[C_MAPPER][0])
  2490.                   fprintf(stderr,
  2491.                      "upd_open_map: unsupported %s=%d\n",
  2492.                      upd_choice[C_MAPPER][0],upd->choice[C_MAPPER]);
  2493.                else
  2494.                   fprintf(stderr,
  2495.                      "upd_open_map: unsupported choce[%d]=%d\n",
  2496.                      C_MAPPER,upd->choice[C_MAPPER]);
  2497. #endif
  2498.             imap = 0;
  2499.          break;
  2500.       }
  2501.    }
  2502.  
  2503.  
  2504. /** The bit number sould be positive & fit into the storage */
  2505.  
  2506.    if(imap) { /* Check number of Bits & Shifts */
  2507.  
  2508. #if      UPD_MESSAGES & UPD_M_WARNING
  2509.       uint32 used = 0,bitmsk;
  2510. #endif
  2511.       bool success = true;
  2512.  
  2513.       for(imap = 0; UPD_CMAP_MAX > imap; ++imap) {
  2514.          if(0 > upd->cmap[imap].xfer) continue;
  2515.  
  2516.          if((0                     > upd->int_a[IA_COMPBITS].data[imap])  ||
  2517.             (gx_color_value_bits   < upd->int_a[IA_COMPBITS].data[imap])  ||
  2518.             (0                     > upd->int_a[IA_COMPSHIFT].data[imap]) ||
  2519.             (upd->int_a[IA_COMPBITS].data[imap] >
  2520.              (udev->color_info.depth - upd->int_a[IA_COMPSHIFT].data[imap]))) {
  2521. #if         UPD_MESSAGES & UPD_M_WARNING
  2522.                fprintf(stderr,
  2523.                   "upd_open_map: %d Bits << %d is illegal for %d. Component\n",
  2524.                   upd->int_a[IA_COMPBITS].data[imap],
  2525.                   upd->int_a[IA_COMPSHIFT].data[imap],imap+1);
  2526. #endif
  2527.  
  2528.             success = false;
  2529.  
  2530.  
  2531.          } else {
  2532.  
  2533.             int         n;
  2534.             const float *now;
  2535.             float       last;
  2536.  
  2537.             if((NULL == upd->float_a[upd->cmap[imap].xfer].data) ||
  2538.                (2    >  upd->float_a[upd->cmap[imap].xfer].size)   ) {
  2539.                float *fp;
  2540.                UPD_MM_DEL_PARAM(upd->float_a[upd->cmap[imap].xfer]);
  2541.                UPD_MM_GET_ARRAY(fp,2);
  2542.                fp[0] = 0.0;
  2543.                fp[1] = 1.0;
  2544.                upd->float_a[upd->cmap[imap].xfer].data = fp;
  2545.                upd->float_a[upd->cmap[imap].xfer].size = 2;
  2546.             }
  2547.             n    = upd->float_a[upd->cmap[imap].xfer].size-1;
  2548.             now  = upd->float_a[upd->cmap[imap].xfer].data;
  2549.             last = now[n];
  2550.  
  2551.             if(     *now < last) { /* Rising */
  2552.                last = *now++;
  2553.                while(n--) {
  2554.                  if(last >= *now) break;
  2555.                  last = *now++;
  2556.                }
  2557.             } else if(*now > last) { /* Falling */
  2558.                last = *now++;
  2559.                while(n--) {
  2560.                  if(last <= *now) break;
  2561.                  last = *now++;
  2562.                }
  2563.             }                      /* Monotony-check */
  2564.  
  2565.             if(0 <= n) {
  2566. #if            UPD_MESSAGES & UPD_M_WARNING
  2567.                fprintf(stderr,
  2568.                   "upd_open_map: %d. Component has non monoton Xfer\n",imap+1);
  2569. #endif
  2570.                success = false;
  2571.  
  2572.             } else {
  2573.  
  2574. #if            UPD_MESSAGES & UPD_M_WARNING
  2575.  
  2576.                bitmsk   = ((uint32) 1 << upd->int_a[IA_COMPBITS].data[imap]) -1;
  2577.                bitmsk <<= upd->int_a[IA_COMPSHIFT].data[imap];
  2578.  
  2579.                if(used & bitmsk) fprintf(stderr,
  2580.                   "upd_open_map: %d. Component overlaps with others\n",imap+1);
  2581.  
  2582.                used |= bitmsk;
  2583. #endif
  2584.             }
  2585.          }
  2586.       }
  2587.  
  2588.       if(!success) imap = 0;
  2589.  
  2590.    }             /* Check number of Bits */
  2591.  
  2592. /** Do the allocation */
  2593.  
  2594.    if(imap) {
  2595.  
  2596.       for(imap = 0; UPD_CMAP_MAX > imap; ++imap) {
  2597.          if(0 > upd->cmap[imap].xfer) continue;
  2598.  
  2599.          upd->cmap[imap].bits     = upd->int_a[IA_COMPBITS].data[imap];
  2600.          upd->cmap[imap].bitshf   = upd->int_a[IA_COMPSHIFT].data[imap];
  2601.          upd->cmap[imap].bitmsk   = 1;
  2602.          upd->cmap[imap].bitmsk <<= upd->cmap[imap].bits;
  2603.          upd->cmap[imap].bitmsk  -= 1;
  2604.          upd->cmap[imap].rise     =
  2605.             upd->float_a[upd->cmap[imap].xfer].data[0] <
  2606.             upd->float_a[upd->cmap[imap].xfer].data[
  2607.                upd->float_a[upd->cmap[imap].xfer].size-1] ?
  2608.             true : false;
  2609.          upd->cmap[imap].code     = gs_malloc(sizeof(upd->cmap[imap].code[0]),
  2610.              upd->cmap[imap].bitmsk+1,"upd/code");
  2611.          if(!upd->cmap[imap].code) break;
  2612.       }
  2613.  
  2614.       if(UPD_CMAP_MAX > imap) {
  2615.  
  2616.          imap = 0;
  2617.  
  2618. #if      UPD_MESSAGES & UPD_M_ERROR
  2619.             fprintf(stderr,"upd_open_map: could not allocate code-arrays\n");
  2620. #        endif
  2621.  
  2622.       }
  2623.    }
  2624.  
  2625. /** then fill the code-arrays */
  2626.  
  2627.    if(imap) {
  2628. /*
  2629.  * Try making things easier: (than with stcolor)
  2630.  *     normalize values to 0.0/1.0-Range
  2631.  *     X-Axis:   Color-Values (implied)
  2632.  *     Y-Values: Indices      (given)
  2633.  */
  2634.  
  2635.       for(imap = 0; UPD_CMAP_MAX > imap; ++imap) {
  2636.  
  2637.          const updcmap_p cmap = upd->cmap + imap;
  2638.          uint32 ly,iy;
  2639.          float ystep,xstep,fx,fy;
  2640.  
  2641. /*       Variables & Macro for Range-Normalization */
  2642.          double offset,scale;
  2643. #define  XFVAL(I) ((upd->float_a[cmap->xfer].data[I]-offset)*scale)
  2644.  
  2645.          if(0 > cmap->xfer) continue;
  2646.  
  2647.          cmap->code[cmap->bitmsk] = gx_max_color_value;
  2648.  
  2649.          if(!cmap->bits) continue;
  2650.  
  2651.          offset = upd->float_a[cmap->xfer].data[0];
  2652.          if(     0.0 > offset) offset = 0.0;
  2653.          else if(1.0 < offset) offset = 1.0;
  2654.  
  2655.          scale  = upd->float_a[cmap->xfer].data[upd->float_a[cmap->xfer].size-1];
  2656.          if(     0.0 > scale ) scale  = 0.0;
  2657.          else if(1.0 < scale ) scale  = 1.0;
  2658.  
  2659.          if(scale != offset) scale = 1.0 / (scale - offset);
  2660.          else                scale = 0.0;
  2661.  
  2662. /*       interpolate */
  2663.          ystep = (float) 1.0 / (float) cmap->bitmsk;
  2664.          xstep = (float) 1.0 / (float)(upd->float_a[cmap->xfer].size - 1);
  2665.  
  2666.          iy = 0;
  2667.          for(ly = 0; ly <= cmap->bitmsk; ++ly) {
  2668.  
  2669.             fy = ystep * ly; /* Target-Value */
  2670.  
  2671.             while(((iy+1) < upd->float_a[cmap->xfer].size) &&
  2672.                   (fy > XFVAL(iy+1))) ++iy;
  2673.  
  2674.             fx  = iy + (fy - XFVAL(iy))/(XFVAL(iy+1) - XFVAL(iy));
  2675.  
  2676.             fx *= xstep * gx_max_color_value;
  2677.  
  2678.             fx  = fx < 0.0 ? 0.0 :
  2679.                  (fx > gx_max_color_value ? gx_max_color_value : fx);
  2680.  
  2681.             cmap->code[ly] = fx;
  2682.             if((fx - cmap->code[ly]) >= 0.5) cmap->code[ly] += 1;
  2683.          }
  2684.  
  2685. #undef   XFVAL
  2686.  
  2687.       }
  2688.    }
  2689.  
  2690. /** If we're ok, massage upd->ncomp */
  2691.  
  2692.    if(imap) {
  2693.       switch(upd->choice[C_MAPPER]) {
  2694.          case MAP_GRAY:
  2695.            if(1 > imap) imap = 0;
  2696.            upd->ncomp = 1;
  2697.          break;
  2698.          case MAP_RGBW: /* RGB->RGBW */
  2699.            if(4 > imap) imap = 0;
  2700.            upd->ncomp = 4;
  2701.          break;
  2702.          case MAP_RGB: /* Plain RGB */
  2703.            if(3 > imap) imap = 0;
  2704.            upd->ncomp = 3;
  2705.          break;
  2706.          case MAP_CMYK: /* Plain KCMY */
  2707.            if(4 > imap) imap = 0;
  2708.             upd->ncomp = 4;
  2709.          break;
  2710.          case MAP_CMYKGEN: /* KCMY with black-generation */
  2711.            if(4 > imap) imap = 0;
  2712.            upd->ncomp = 4;
  2713.          break;
  2714.  
  2715.          default:
  2716.            imap = 0;
  2717. #if        UPD_MESSAGES & UPD_M_WARNING
  2718.               fprintf(stderr,
  2719.                  "upd_open: Mapping %d unknown\n",upd->choice[C_MAPPER]);
  2720. #endif
  2721.  
  2722.          break;
  2723.       }
  2724.    }
  2725.  
  2726.  
  2727. /** If unsuccesful, install the default routines */
  2728.  
  2729.    if(!imap) {
  2730.       upd_close_map(udev);
  2731.    } else {
  2732.       upd->flags |= B_MAP;
  2733.       upd_procs_map(udev);
  2734.    }
  2735.  
  2736.    return imap ? 1 : -1;
  2737. }
  2738.  
  2739. /* ------------------------------------------------------------------- */
  2740. /* upd_procs_map: (de-) install the color-mapping-procedures           */
  2741. /* ------------------------------------------------------------------- */
  2742.  
  2743. private int
  2744. upd_procs_map(upd_device *udev)
  2745. {
  2746.    int imap;
  2747.  
  2748.    if( udev->upd &&
  2749.       (udev->upd->flags & B_MAP)) imap = udev->upd->choice[C_MAPPER];
  2750.    else                           imap = 0;
  2751.  
  2752.    switch(imap) {
  2753.      case 1: /* Grayscale -> Grayscale */
  2754.        set_dev_proc(udev,map_rgb_color, upd_rgb_1color);
  2755.        set_dev_proc(udev,map_cmyk_color,gx_default_map_cmyk_color);
  2756.        set_dev_proc(udev,map_color_rgb, upd_1color_rgb);
  2757.      break;
  2758.      case 2: /* RGB->RGBW */
  2759.        set_dev_proc(udev,map_rgb_color, upd_rgb_4color);
  2760.        set_dev_proc(udev,map_cmyk_color,gx_default_map_cmyk_color);
  2761.        set_dev_proc(udev,map_color_rgb, upd_4color_rgb);
  2762.      break;
  2763.      case 3: /* Plain RGB */
  2764.        set_dev_proc(udev,map_rgb_color, upd_rgb_3color);
  2765.        set_dev_proc(udev,map_cmyk_color,gx_default_map_cmyk_color);
  2766.        set_dev_proc(udev,map_color_rgb, upd_3color_rgb);
  2767.      break;
  2768.      case 4: /* Plain KCMY */
  2769.        set_dev_proc(udev,map_rgb_color, gx_default_map_rgb_color);
  2770.        set_dev_proc(udev,map_cmyk_color,upd_cmyk_icolor);
  2771.        set_dev_proc(udev,map_color_rgb, upd_icolor_rgb);
  2772.      break;
  2773.      case 5: /* KCMY with black-generation */
  2774.        set_dev_proc(udev,map_rgb_color, gx_default_map_rgb_color);
  2775.        set_dev_proc(udev,map_cmyk_color,upd_cmyk_kcolor);
  2776.        set_dev_proc(udev,map_color_rgb, upd_kcolor_rgb);
  2777.     break;
  2778.     default:
  2779.        set_dev_proc(udev,map_rgb_color, gx_default_map_rgb_color);
  2780.        set_dev_proc(udev,map_cmyk_color,gx_default_map_cmyk_color);
  2781.        set_dev_proc(udev,map_color_rgb, gx_default_map_color_rgb);
  2782.     break;
  2783.   }
  2784.   return 0;
  2785.  
  2786. }
  2787.  
  2788. /* ------------------------------------------------------------------- */
  2789. /* upd_close_map: remove color mapping                                 */
  2790. /* ------------------------------------------------------------------- */
  2791.  
  2792. private int
  2793. upd_close_map(upd_device *udev)
  2794. {
  2795.    const upd_p      upd   = udev->upd;
  2796.    int imap;
  2797.  
  2798.    if(upd) {
  2799.  
  2800.       for(imap = 0; UPD_CMAP_MAX > imap; ++imap) {
  2801.  
  2802.          if(upd->cmap[imap].code)
  2803.             gs_free(upd->cmap[imap].code,sizeof(upd->cmap[imap].code[0]),
  2804.                 upd->cmap[imap].bitmsk+1,"upd/code");
  2805.          upd->cmap[imap].code   = NULL;
  2806.  
  2807.          upd->cmap[imap].bitmsk = 0;
  2808.          upd->cmap[imap].bitshf = 0;
  2809.          upd->cmap[imap].bits   = 0;
  2810.          upd->cmap[imap].rise   = false;
  2811.       }
  2812.       upd->flags &= ~B_MAP;
  2813.    }
  2814.  
  2815.    upd_procs_map(udev);
  2816.  
  2817.    return 0;
  2818. }
  2819.  
  2820. /* ------------------------------------------------------------------- */
  2821. /* Functions for the rendering of data                                 */
  2822. /* ------------------------------------------------------------------- */
  2823.  
  2824. /**
  2825. Inside the main-upd-type are a "valbuf" and some unidentified
  2826. pointers. This stuff is used in conjunction with the rendering,
  2827. which is the process of converting gx_color_indices into something
  2828. suitable for the device.
  2829.  
  2830. */
  2831.  
  2832. /* ------------------------------------------------------------------- */
  2833. /* upd_open_render: Initialize rendering                               */
  2834. /* ------------------------------------------------------------------- */
  2835.  
  2836. private void
  2837. upd_open_render(upd_device *udev)
  2838. {
  2839.    const upd_p upd = udev->upd;
  2840.    int  icomp;
  2841.  
  2842. /** Reset everything related to rendering */
  2843.    upd->flags       &= ~B_RENDER;
  2844.    upd->valbuf       = NULL;
  2845.    upd->nvalbuf      = 0;
  2846.    upd->render       = NULL;
  2847.    upd->start_render = NULL;
  2848.    for(icomp = 0; UPD_VALPTR_MAX > icomp; ++icomp) upd->valptr[icomp] = NULL;
  2849.  
  2850.    if( (B_BUF | B_MAP) ==
  2851.       ((B_BUF | B_MAP | B_ERROR) & upd->flags)) {
  2852.  
  2853. /** Establish the renderingwidth in upd */
  2854.       upd->rwidth = upd->gswidth;
  2855.       if((0            < upd->ints[I_PWIDTH]) &&
  2856.          (upd->gswidth > upd->ints[I_PWIDTH])   )
  2857.           upd->rwidth  = upd->ints[I_PWIDTH];
  2858.  
  2859. /** Call the Render-specific Open-Function */
  2860.       switch(upd->choice[C_RENDER]) {
  2861.          case RND_FSCOMP:
  2862.             upd_open_fscomp(udev);
  2863.          break;
  2864.          case RND_FSCMYK:
  2865.             upd_open_fscmyk(udev);
  2866.          break;
  2867.          default:
  2868. #if UPD_MESSAGES & UPD_M_WARNING
  2869.             fprintf(stderr,"upd_open_render: Unknown rendering type %d\n",
  2870.                 upd->choice[C_RENDER]);
  2871. #endif
  2872.          break;
  2873.       }
  2874.    }
  2875.  
  2876.    if(B_RENDER != ((B_ERROR | B_RENDER) & upd->flags))
  2877.       upd_close_render(udev);
  2878.  
  2879.    return;
  2880. }
  2881.  
  2882.  
  2883. /* ------------------------------------------------------------------- */
  2884. /* upd_close_render: Deinitialize rendering                            */
  2885. /* ------------------------------------------------------------------- */
  2886.  
  2887. private void
  2888. upd_close_render(upd_device *udev)
  2889. {
  2890.    const upd_p upd = udev->upd;
  2891.  
  2892.    if(upd) {
  2893.       int icomp;
  2894.  
  2895.       if((upd->render == upd_fscomp) ||
  2896.          (upd->render == upd_fscmyk)   )  upd_close_fscomp(udev);
  2897.  
  2898.       if((0 < upd->nvalbuf) && upd->valbuf)
  2899.          gs_free(upd->valbuf,upd->nvalbuf,sizeof(upd->valbuf[0]),"upd/valbuf");
  2900.       upd->valbuf  = NULL;
  2901.       upd->nvalbuf = 0;
  2902.  
  2903.       upd->flags       &= ~B_RENDER;
  2904.       upd->render       = NULL;
  2905.       upd->start_render = NULL;
  2906.       for(icomp = 0; UPD_VALPTR_MAX > icomp; ++icomp) upd->valptr[icomp] = NULL;
  2907.  
  2908.    }
  2909.    return;
  2910. }
  2911.  
  2912. /* ------------------------------------------------------------------- */
  2913. /* upd_open_fscomp: Initialize Component-Floyd-Steinberg               */
  2914. /* ------------------------------------------------------------------- */
  2915. #if UPD_MESSAGES & UPD_M_FSBUF
  2916. static int32 fs_emin[UPD_VALPTR_MAX],fs_emax[UPD_VALPTR_MAX];
  2917. #endif
  2918. private void
  2919. upd_open_fscomp(upd_device *udev)
  2920. {
  2921.    const upd_p upd = udev->upd;
  2922.    int icomp,order[UPD_CMAP_MAX];
  2923.  
  2924. #if UPD_MESSAGES & UPD_M_FSBUF
  2925.    for(icomp = 0; UPD_VALPTR_MAX < icomp; ++icomp)
  2926.       fs_emin[icomp] = fs_emax[icomp] = 0;
  2927. #endif
  2928.  
  2929.    icomp = upd->ncomp;
  2930.    if(0 < upd->ints[I_NCOMP]) icomp = upd->ints[I_NCOMP];
  2931.  
  2932.    if((0              >= icomp) ||
  2933.       (UPD_VALPTR_MAX <  icomp) ||
  2934.       (UPD_CMAP_MAX   <  icomp)   ) icomp      = 0;
  2935.    else                             upd->ncomp = icomp;
  2936.  
  2937. /**
  2938. This Version of the FS-algorithm works on the mapped components, but
  2939. the printing-order might be different from the order dictated by the
  2940. mapping-routines. The optional RNDCOMP-Array is used for that. The
  2941. initial test checks it's integrity.
  2942. */
  2943.    if(icomp) {
  2944.       if(upd->ncomp <= upd->int_a[IA_COMPORDER].size) { /* Reordering */
  2945.          bool success = true;
  2946.          for(icomp = 0; upd->ncomp > icomp; ++icomp) {
  2947.             order[icomp] = upd->int_a[IA_COMPORDER].data[icomp];
  2948.             if((0            >  order[icomp]) ||
  2949.                (UPD_CMAP_MAX <= order[icomp])   ) {
  2950.                success = false;
  2951. #if UPD_MESSAGES & UPD_M_WARNING
  2952.                   fprintf(stderr,
  2953.                    "upd_open_fscomp: %d is illegal component-index\n",
  2954.                    order[icomp]);
  2955. #endif
  2956.             }
  2957.          }
  2958.          if(!success) icomp = 0;
  2959.       } else {                                          /* Default-Ordering */
  2960.          for(icomp = 0; UPD_CMAP_MAX > icomp; ++icomp) order[icomp] = icomp;
  2961.       }                                                 /* Ordering defined */
  2962.    }
  2963.  
  2964. /**
  2965. If anything was ok. up to now, memory get's allocated.
  2966. */
  2967.    if(icomp) {
  2968.  
  2969.       for(icomp = 0; upd->ncomp > icomp; ++icomp) {
  2970.          upd->valptr[icomp] = gs_malloc(1,sizeof(updcomp_t),"upd/fscomp");
  2971.          if(NULL == upd->valptr[icomp]) {
  2972. #if UPD_MESSAGES & UPD_M_ERROR
  2973.             fprintf(stderr,
  2974.                "upd_open_fscomp: could not allocate %d. updcomp\n",
  2975.                icomp);
  2976. #endif
  2977.             icomp = 0;
  2978.             break;
  2979.          }
  2980.       }
  2981.    }
  2982.  
  2983.    if(icomp) {
  2984.       uint need;
  2985.  
  2986.       need  = (2 + upd->rwidth) * upd->ncomp;
  2987.       upd->valbuf = gs_malloc(need,sizeof(upd->valbuf[0]),"upd/valbuf");
  2988.  
  2989.       if(upd->valbuf) {
  2990.          upd->nvalbuf = need;
  2991.          memset(upd->valbuf,0,need*sizeof(upd->valbuf[0]));
  2992.       } else {
  2993. #if UPD_MESSAGES & UPD_M_ERROR
  2994.          fprintf(stderr,
  2995.             "upd_open_fscomp: could not allocate %u words for valbuf\n",need);
  2996. #endif
  2997.          icomp = 0;
  2998.       }
  2999.    }
  3000.  
  3001. /* Still happy? then compute component-values */
  3002.  
  3003.    if(icomp) {
  3004.       for(icomp = 0; upd->ncomp > icomp; ++icomp) {
  3005.  
  3006.          const updcomp_p comp   = upd->valptr[icomp];
  3007.          const int32     nsteps = upd->cmap[order[icomp]].bitmsk;
  3008.          float ymin,ymax;
  3009.          int32 highmod,highval;
  3010.          int i;
  3011.  
  3012.          comp->threshold = nsteps;
  3013.          comp->spotsize  = nsteps;
  3014.          comp->offset    = 0;
  3015.          comp->scale     = 1;
  3016.          comp->cmap      = order[icomp];
  3017.          upd->cmap[comp->cmap].comp = icomp;
  3018.          comp->bits      = upd->cmap[comp->cmap].bits;
  3019.          comp->bitshf    = upd->cmap[comp->cmap].bitshf;
  3020.          comp->bitmsk    = upd->cmap[comp->cmap].bitmsk;
  3021.  
  3022.          if(!nsteps) continue; /* A 0-Bit component is legal! */
  3023.  
  3024.          if(upd->cmap[comp->cmap].rise) {
  3025.             ymin = upd->float_a[upd->cmap[comp->cmap].xfer].data[0];
  3026.             ymax = upd->float_a[upd->cmap[comp->cmap].xfer].data[
  3027.                       upd->float_a[upd->cmap[comp->cmap].xfer].size-1];
  3028.          } else {
  3029.             ymax = upd->float_a[upd->cmap[comp->cmap].xfer].data[0];
  3030.             ymin = upd->float_a[upd->cmap[comp->cmap].xfer].data[
  3031.                       upd->float_a[upd->cmap[comp->cmap].xfer].size-1];
  3032.          }
  3033.  
  3034.          if(0.0 > ymin) {
  3035.             ymin = 0.0;
  3036.             if(0.0 > ymax) ymax = 1.0 / (float) (nsteps+1);
  3037.          }
  3038.          if(1.0 < ymax) ymax = 1.0;
  3039.  
  3040.          comp->spotsize = ((int32) 1 << 28) - 1;
  3041.  
  3042.          for(i = 0; i < 32; ++i) { /* Attempt Ideal */
  3043.  
  3044.             highval = (ymax-ymin) * (double) comp->spotsize + 0.5;
  3045.  
  3046.             if(!(highmod = highval % nsteps)) break; /* Gotcha */
  3047.  
  3048.             highval += nsteps - highmod;
  3049.             comp->spotsize = (double) highval / (ymax-ymin) + 0.5;
  3050.  
  3051.             if(!(comp->spotsize % 2)) comp->spotsize++;
  3052.  
  3053.          }                         /* Attempt Ideal */
  3054.  
  3055.          comp->offset    = ymin * (double) comp->spotsize + (double) 0.5;
  3056.          comp->scale     = highval / nsteps;
  3057.          comp->threshold = comp->spotsize / 2;
  3058.  
  3059. #if UPD_MESSAGES & UPD_M_SETUP
  3060.          fprintf(stderr,
  3061.              "Values for %d. Component after %d iterations\n",comp->cmap+1,i);
  3062.          fprintf(stderr,
  3063.              "steps:     %10ld, Bits: %d\n",(long) comp->bitmsk,comp->bits);
  3064.          fprintf(stderr,
  3065.              "xfer:      %10d Points, %s\n",
  3066.              upd->float_a[upd->cmap[comp->cmap].xfer].size,
  3067.              upd->cmap[comp->cmap].rise ? "rising" : "falling");
  3068.          fprintf(stderr,
  3069.              "offset:    %10d 0x%08x\n",comp->offset,comp->offset);
  3070.          fprintf(stderr,
  3071.              "scale:     %10d 0x%08x\n",comp->scale,comp->scale);
  3072.          fprintf(stderr,
  3073.              "threshold: %10d 0x%08x\n",comp->threshold,comp->threshold);
  3074.          fprintf(stderr,
  3075.              "spotsize:  %10d 0x%08x\n",comp->spotsize,comp->spotsize);
  3076. #endif
  3077.       }
  3078.    }
  3079. /**
  3080. Optional Random Initialization of the value-Buffer
  3081. */
  3082.    if(icomp && !(B_FSZERO & upd->flags)) {
  3083.       for(icomp = 0; icomp < upd->ncomp; ++icomp) {
  3084.          const updcomp_p comp = upd->valptr[icomp];
  3085.          int i;
  3086.          int32 lv = INT32_MAX, hv = INT32_MIN, v;
  3087.          float scale;
  3088.          for(i = icomp; i < upd->nvalbuf; i += upd->ncomp) {
  3089.             v = rand();
  3090.             if(lv > v) lv = v;
  3091.             if(hv < v) hv = v;
  3092.             upd->valbuf[i] = v;
  3093.          }
  3094.          scale = (float) comp->threshold / (float) (hv - lv);
  3095.          lv   += comp->threshold / (2*scale);
  3096.          for(i = icomp; i < upd->nvalbuf; i += upd->ncomp)
  3097.             upd->valbuf[i] = scale * (upd->valbuf[i] - lv);
  3098.       }
  3099.    }
  3100.  
  3101. /**
  3102. The render-Routine acts as an indicator, which render-close is to use!
  3103. */
  3104.    upd->render = upd_fscomp;
  3105.  
  3106.    if(icomp) upd->flags |=  B_RENDER;
  3107.    else      upd->flags &= ~B_RENDER;
  3108.  
  3109.    return;
  3110. }
  3111.  
  3112. /* ------------------------------------------------------------------- */
  3113. /* upd_close_fscomp: Deinitialize Component-Floyd-Steinberg            */
  3114. /* ------------------------------------------------------------------- */
  3115.  
  3116. private void
  3117. upd_close_fscomp(upd_device *udev)
  3118. {
  3119.    const upd_p upd = udev->upd;
  3120.    int icomp;
  3121.  
  3122. #if UPD_MESSAGES & UPD_M_FSBUF
  3123.    if(upd && (upd->flags & B_RENDER)) {
  3124.  
  3125.       for(icomp = 0; icomp < upd->ncomp; ++icomp) {
  3126.          updcomp_p comp = upd->valptr[icomp];
  3127.          if(!comp) continue;
  3128.          if(!comp->spotsize) continue;
  3129.          fprintf(stderr,"%d. Component: %6.3f <= error <= %6.3f\n",
  3130.              icomp+1,
  3131.              (double) fs_emin[icomp] / (double) comp->spotsize,
  3132.              (double) fs_emax[icomp] / (double) comp->spotsize);
  3133.       }
  3134.  
  3135.    }
  3136. #endif
  3137.  
  3138.    for(icomp = 0; UPD_VALPTR_MAX > icomp; ++icomp) {
  3139.       if(!upd->valptr[icomp]) continue;
  3140.       gs_free(upd->valptr[icomp],1,sizeof(updcomp_t),"upd/fscomp");
  3141.       upd->valptr[icomp] = NULL;
  3142.    }
  3143. }
  3144.  
  3145. /* ------------------------------------------------------------------- */
  3146. /* upd_fscomp: Apply Floyd-Steinberg to each component                 */
  3147. /* ------------------------------------------------------------------- */
  3148.  
  3149. /**
  3150.    With UPD_M_FSBUF Max/Min-Values for the Errors are computed
  3151. */
  3152. #if   UPD_MESSAGES & UPD_M_FSBUF
  3153. #define FS_M_ROWERR(I)                                        \
  3154.            if(fs_emin[I] > rowerr[I]) fs_emin[I] = rowerr[I]; \
  3155.            if(fs_emax[I] < rowerr[I]) fs_emax[I] = rowerr[I];
  3156. #else
  3157. #define FS_M_ROWERR(I) ;
  3158. #endif
  3159. /**
  3160.    FS_GOAL computes the desired Pixel-Value
  3161. */
  3162. #define FS_GOAL(Raw,I)                                                     \
  3163.    pixel[I] = (int32)(Raw) * comp[I]->scale +    comp[I]->offset           \
  3164.             + rowerr[I]  + colerr[I] -       ((colerr[I]+4)>>3);           \
  3165.    if(         pixel[I] < 0)                    pixel[I] = 0;              \
  3166.    else if(    pixel[I] >    comp[I]->spotsize) pixel[I] = comp[I]->spotsize;
  3167.  
  3168. /*
  3169.  *    Distribute the error:   prev  now   next
  3170.  *                                   X    7/16 Y
  3171.  *                            3/16  5/16  1/16 Y+1
  3172.  */
  3173. #define FS_DIST(I)                                                    \
  3174.    if(!first) rowerr[I-dir] += ((3*pixel[I]+8)>>4); /* 3/16 */        \
  3175.               rowerr[I    ]  = ((5*pixel[I]  )>>4)  /* 5/16 */        \
  3176.                              + (( colerr[I]+4)>>3); /* 1/16 (rest) */ \
  3177.               colerr[I    ]  = pixel[I]             /* 8/16 (neu) */  \
  3178.                              - ((5*pixel[I]  )>>4)                    \
  3179.                              - ((3*pixel[I]+8)>>4);
  3180. /**
  3181.    S_FSTEP   adjusts the Indices (rowerr, bit and iword)
  3182. */
  3183. #define S_FSTEP                                \
  3184.    rowerr += dir;                              \
  3185.    first   = false;                            \
  3186.    if(0 > dir) { /* Reverse */                 \
  3187.       if(!(bit <<= 1)) { bit = 0x01; ibyte--; }\
  3188.    } else {      /* Forward */                 \
  3189.       if(!(bit >>= 1)) { bit = 0x80; ibyte++; }\
  3190.    }             /* Inc/Dec Bit */
  3191.  
  3192. private int
  3193. upd_fscomp(upd_p upd)
  3194. {
  3195.    const updscan_p  scan    = upd->scnbuf[upd->yscnbuf & upd->scnmsk];
  3196.    const updcomp_p *comp    = (updcomp_p *) upd->valptr;
  3197.    int32 *const     pixel  = upd->valbuf;
  3198.    int32 *const     colerr = pixel  + upd->ncomp;
  3199.    int32           *rowerr = colerr + upd->ncomp;
  3200.    int              pwidth = upd->rwidth;
  3201.    int              dir,ibyte;
  3202.    uint32       ci;
  3203.    byte         bit;
  3204.    bool         first = true;
  3205. /*
  3206.  * Erase the component-Data
  3207.  */
  3208.    switch(upd->ncomp) {
  3209.      case 4:  memset(scan[3].bytes,0,upd->nbytes);
  3210.      case 3:  memset(scan[2].bytes,0,upd->nbytes);
  3211.               memset(scan[1].bytes,0,upd->nbytes);
  3212.      default: memset(scan[0].bytes,0,upd->nbytes);
  3213.    }
  3214. /*
  3215.  * determine the direction
  3216.  */
  3217.    if(upd->flags &   B_REVDIR) { /* This one reverse */
  3218.  
  3219.       if(upd->flags & B_YFLIP) {
  3220.          dir     = upd->ncomp;
  3221.          bit     = 0x80;
  3222.          ibyte   = 0;
  3223.       } else {
  3224.          dir     =  -upd->ncomp;
  3225.          rowerr +=   upd->ncomp * (pwidth-1);
  3226.          bit     =   0x80 >>     ((pwidth-1) & 7);
  3227.          ibyte   =                (pwidth-1) >> 3;
  3228.       }
  3229.  
  3230.       if(!(upd->flags & B_FSWHITE)) {
  3231.          upd_pxlfwd(upd);
  3232.          while((0 < pwidth) && !upd_pxlget(upd)) pwidth--;
  3233.       }
  3234.  
  3235.       upd_pxlrev(upd);
  3236.  
  3237.    } else {                       /* This one forward */
  3238.  
  3239.       if(upd->flags & B_YFLIP) {
  3240.          dir     =  -upd->ncomp;
  3241.          rowerr +=   upd->ncomp * (pwidth-1);
  3242.          bit     =   0x80 >>     ((pwidth-1) & 7);
  3243.          ibyte   =                (pwidth-1) >> 3;
  3244.       } else {
  3245.          dir     = upd->ncomp;
  3246.          bit     = 0x80;
  3247.          ibyte   = 0;
  3248.       }
  3249.  
  3250.       if(!(upd->flags & B_FSWHITE)) {
  3251.          upd_pxlrev(upd);
  3252.          while((0 < pwidth) && !upd_pxlget(upd)) pwidth--;
  3253.       }
  3254.  
  3255.       upd_pxlfwd(upd);
  3256.  
  3257.    }                              /* reverse or forward */
  3258. /*
  3259.  * Toggle Direction, if not fixed
  3260.  */
  3261.    if(!(upd->flags & B_FIXDIR)) upd->flags ^= B_REVDIR;
  3262. /*
  3263.  * Skip over leading white-space
  3264.  */
  3265.    if(!(upd->flags & B_FSWHITE)) {
  3266.       upd_proc_pxlget((*fun)) = upd->pxlget;
  3267.       byte             *ptr   = upd->pxlptr;
  3268.       while((0 < pwidth) && !upd_pxlget(upd)) {
  3269.          pwidth--;
  3270.          fun = upd->pxlget;
  3271.          ptr = upd->pxlptr;
  3272.          S_FSTEP
  3273.       }
  3274.       upd->pxlget = fun;
  3275.       upd->pxlptr = ptr;
  3276.    }
  3277. /*
  3278.  * Process all Pixels
  3279.  */
  3280.    first = true;
  3281.    while(0 < pwidth--) {
  3282. /*
  3283.  *    Execute FS-Algorithm for each active component
  3284.  */
  3285.       ci = upd_pxlget(upd);
  3286.       switch(upd->ncomp) {
  3287.          case 4:  FS_M_ROWERR(3)
  3288.                   FS_GOAL(comp[3]->bitmsk & (ci >> comp[3]->bitshf),3)
  3289.                   if(pixel[3] >  comp[3]->threshold) { /* "Fire" */
  3290.                      pixel[3] -= comp[3]->spotsize;
  3291.                       scan[3].bytes[ibyte] |= bit;
  3292.                   }                                    /* "Fire" */
  3293.                   FS_DIST(3)
  3294.  
  3295.          case 3:  FS_M_ROWERR(2)
  3296.                   FS_GOAL(comp[2]->bitmsk & (ci >> comp[2]->bitshf),2)
  3297.                   if(pixel[2] >  comp[2]->threshold) { /* "Fire" */
  3298.                      pixel[2] -= comp[2]->spotsize;
  3299.                       scan[2].bytes[ibyte] |= bit;
  3300.                   }                                    /* "Fire" */
  3301.                   FS_DIST(2)
  3302.  
  3303.                   FS_M_ROWERR(1)
  3304.                   FS_GOAL(comp[1]->bitmsk & (ci >> comp[1]->bitshf),1)
  3305.                   if(pixel[1] >  comp[1]->threshold) { /* "Fire" */
  3306.                      pixel[1] -= comp[1]->spotsize;
  3307.                       scan[1].bytes[ibyte] |= bit;
  3308.                   }                                    /* "Fire" */
  3309.                   FS_DIST(1)
  3310.  
  3311.          default: FS_M_ROWERR(0)
  3312.                   FS_GOAL(comp[0]->bitmsk & (ci >> comp[0]->bitshf),0)
  3313.                   if(pixel[0] >  comp[0]->threshold) { /* "Fire" */
  3314.                      pixel[0] -= comp[0]->spotsize;
  3315.                       scan[0].bytes[ibyte] |= bit;
  3316.                   }                                    /* "Fire" */
  3317.                   FS_DIST(0)
  3318.       }
  3319. /*
  3320.  *    Adjust rowerr, bit & iword, depending on direction
  3321.  */
  3322.       S_FSTEP
  3323.    }
  3324. /*
  3325.  * Finally call the limits-Routine
  3326.  */
  3327.    if(0 < upd->nlimits) upd_limits(upd,true);
  3328.    return 0;
  3329. }
  3330.  
  3331. /* ------------------------------------------------------------------- */
  3332. /* upd_open_fscmyk: Initialize Component-Floyd-Steinberg               */
  3333. /* ------------------------------------------------------------------- */
  3334.  
  3335. private void
  3336. upd_open_fscmyk(upd_device *udev)
  3337. {
  3338.    const upd_p upd = udev->upd;
  3339.  
  3340.    upd_open_fscomp(udev);
  3341.  
  3342.    if((B_RENDER & upd->flags) &&
  3343.       (4 == upd->ncomp) &&
  3344.       (8 <= upd->cmap[0].bits) && (24 == upd->cmap[0].bitshf) &&
  3345.       (8 <= upd->cmap[1].bits) && (16 == upd->cmap[1].bitshf) &&
  3346.       (8 <= upd->cmap[2].bits) && ( 8 == upd->cmap[2].bitshf) &&
  3347.       (8 <= upd->cmap[3].bits) && ( 0 == upd->cmap[3].bitshf)   ) {
  3348.       upd->render = upd_fscmyk;
  3349.    } else {
  3350.       upd->flags &= ~B_RENDER;
  3351.    }
  3352.  
  3353. }
  3354.  
  3355. /* ------------------------------------------------------------------- */
  3356. /* upd_fscmyk: 32 Bit, K-CMY-Order Dithering                           */
  3357. /* ------------------------------------------------------------------- */
  3358.  
  3359. private int
  3360. upd_fscmyk(upd_p upd)
  3361. {
  3362.    const updscan_p  scan   = upd->scnbuf[upd->yscnbuf & upd->scnmsk];
  3363.    int32 *const     pixel  = upd->valbuf;
  3364.    const updcomp_p *comp   = (updcomp_p *) upd->valptr;
  3365.    int32 *const     colerr = pixel  + 4;
  3366.    int32           *rowerr = colerr + 4;
  3367.    int32            pwidth = upd->rwidth;
  3368.    int              dir,ibyte;
  3369.    byte             bit,*data;
  3370.    bool             first = false;
  3371. /*
  3372.  * Erase the component-Data
  3373.  */
  3374.    memset(scan[0].bytes,0,upd->nbytes);
  3375.    memset(scan[1].bytes,0,upd->nbytes);
  3376.    memset(scan[2].bytes,0,upd->nbytes);
  3377.    memset(scan[3].bytes,0,upd->nbytes);
  3378.  
  3379. /*
  3380.  * determine the direction
  3381.  */
  3382.    if(upd->flags &   B_REVDIR) { /* This one reverse */
  3383.  
  3384.       if(!(upd->flags & B_FSWHITE)) {
  3385.          data = upd->gsscan;
  3386.          while(0 < pwidth && !*(uint32 *)data) pwidth--, data += 4;
  3387.          if(0 >= pwidth) {
  3388.             if(0 < upd->nlimits) upd_limits(upd,false);
  3389.             return 0;
  3390.          }
  3391.       }
  3392.       
  3393.       data        = upd->gsscan + 4 * (upd->rwidth-1);
  3394.  
  3395.    } else {                          /* This one forward */
  3396.  
  3397.       if(!(upd->flags & B_FSWHITE)) {
  3398.          data = upd->gsscan + 4 * (upd->rwidth-1);
  3399.          while(0 < pwidth && !*(uint32 *)data) pwidth--, data -= 4;
  3400.          if(0 >= pwidth) {
  3401.             if(0 < upd->nlimits) upd_limits(upd,false);
  3402.             return 0;
  3403.          }
  3404.       }
  3405.  
  3406.       data        = upd->gsscan;
  3407.  
  3408.    }                              /* reverse or forward */
  3409. /*
  3410.  * Bits depend on FLIP & Direction
  3411.  */
  3412.    if(!(B_REVDIR & upd->flags) == !(B_YFLIP  & upd->flags)) {
  3413.       dir         = 4;
  3414.       bit         = 0x80;
  3415.       ibyte       = 0;
  3416.    } else {
  3417.       dir         =  -4;
  3418.       rowerr     +=   4 *             (upd->rwidth-1);
  3419.       bit         =   0x80 >>        ((upd->rwidth-1) & 7);
  3420.       ibyte       =                   (upd->rwidth-1) >> 3;
  3421.    }
  3422.  
  3423. /*
  3424.  * Toggle Direction, if not fixed
  3425.  */
  3426.    if(!(upd->flags & B_FIXDIR)) upd->flags ^= B_REVDIR;
  3427. /*
  3428.  * Skip over leading white-space
  3429.  */
  3430.    if(!(upd->flags & B_FSWHITE)) {
  3431.       while(0 < pwidth && !*((uint32 *)data)) {
  3432.          pwidth--;
  3433.          if(B_YFLIP  & upd->flags) data -= dir;
  3434.          else                      data += dir;
  3435.          S_FSTEP
  3436.       }
  3437.    }
  3438. /*
  3439.  * Process all Pixels
  3440.  */
  3441.    first = true;
  3442.    while(0 < pwidth--) {
  3443. /*
  3444.  *    Compute the Black-Value first
  3445.  */
  3446.       FS_M_ROWERR(upd->cmap[0].comp) FS_GOAL(data[0],upd->cmap[0].comp);
  3447.  
  3448. /*
  3449.  *    Decide wether this is a color value
  3450.  */
  3451.       if(data[1] || data[2] || data[3]) {
  3452.  
  3453.          FS_M_ROWERR(upd->cmap[1].comp) FS_GOAL(data[1],upd->cmap[1].comp)
  3454.          FS_M_ROWERR(upd->cmap[2].comp) FS_GOAL(data[2],upd->cmap[2].comp)
  3455.          FS_M_ROWERR(upd->cmap[3].comp) FS_GOAL(data[3],upd->cmap[3].comp)
  3456. /*
  3457.  *       if black fires, then all other components fire logically too
  3458.  */
  3459.          if(pixel[upd->cmap[0].comp] > comp[upd->cmap[0].comp]->threshold) {
  3460.  
  3461.             pixel[0] -= comp[0]->spotsize;
  3462.             pixel[1] -= comp[1]->spotsize;
  3463.             pixel[2] -= comp[2]->spotsize;
  3464.             pixel[3] -= comp[3]->spotsize;
  3465.             scan[upd->cmap[0].comp].bytes[ibyte] |= bit;
  3466.  
  3467. /*
  3468.  *       if black is below threshold, only components with larger data-values
  3469.  *       are allowed to fire
  3470.  */
  3471.          } else {                                 /* Restricted firing */
  3472.  
  3473.             if(( data[0] < data[1]) &&
  3474.                (pixel[upd->cmap[1].comp] >
  3475.                  comp[upd->cmap[1].comp]->threshold)) { /* "Fire" */
  3476.                 pixel[upd->cmap[1].comp] -= comp[upd->cmap[1].comp]->spotsize;
  3477.                  scan[upd->cmap[1].comp].bytes[ibyte] |= bit;
  3478.             }                                           /* "Fire" */
  3479.  
  3480.             if(( data[0] < data[2]) &&
  3481.                (pixel[upd->cmap[2].comp] >
  3482.                  comp[upd->cmap[2].comp]->threshold)) { /* "Fire" */
  3483.                 pixel[upd->cmap[2].comp] -= comp[upd->cmap[2].comp]->spotsize;
  3484.                  scan[upd->cmap[2].comp].bytes[ibyte] |= bit;
  3485.             }                                           /* "Fire" */
  3486.  
  3487.             if(( data[0] < data[3]) &&
  3488.                (pixel[upd->cmap[3].comp] >
  3489.                  comp[upd->cmap[3].comp]->threshold)) { /* "Fire" */
  3490.                 pixel[upd->cmap[3].comp] -= comp[upd->cmap[3].comp]->spotsize;
  3491.                  scan[upd->cmap[3].comp].bytes[ibyte] |= bit;
  3492.             }                                           /* "Fire" */
  3493.  
  3494.          }                                        /* Fire-Mode */
  3495.  
  3496. /*
  3497.  * Handle Color-Errors
  3498.  */
  3499.          FS_DIST(upd->cmap[3].comp)
  3500.          FS_DIST(upd->cmap[2].comp)
  3501.          FS_DIST(upd->cmap[1].comp)
  3502.  
  3503.       } else if(pixel[upd->cmap[0].comp] > comp[upd->cmap[0].comp]->threshold) {
  3504.                  scan[upd->cmap[0].comp].bytes[ibyte] |= bit;
  3505.                 pixel[upd->cmap[0].comp] -= comp[upd->cmap[0].comp]->spotsize;
  3506.       }
  3507.  
  3508.       FS_DIST(upd->cmap[0].comp)
  3509. /*
  3510.  *    Adjust bit & iword, depending on direction
  3511.  */
  3512.       S_FSTEP
  3513.       if(upd->flags & B_YFLIP) data -= dir;
  3514.       else                     data += dir;
  3515.    }
  3516. /*
  3517.  * Finally call the limits-Routine
  3518.  */
  3519.    if(0 < upd->nlimits) upd_limits(upd,true);
  3520.    return 0;
  3521. }
  3522.  
  3523.  
  3524. /* ------------------------------------------------------------------- */
  3525. /* upd_open_writer: Initialize rendering                               */
  3526. /* ------------------------------------------------------------------- */
  3527.  
  3528. private int
  3529. upd_open_writer(upd_device *udev)
  3530. {
  3531.    const upd_p upd                 = udev->upd;
  3532.    bool        success             = true;
  3533.  
  3534.  
  3535. /** Reset the crucial values */
  3536.    upd->start_writer = NULL;
  3537.    upd->writer       = NULL;
  3538.    upd->scnbuf       = NULL;
  3539.    upd->nscnbuf      = 0;
  3540.    upd->nbytes       = 0;
  3541.    upd->nlimits      = 0;
  3542.    upd->outbuf       = NULL;
  3543.    upd->noutbuf      = 0;
  3544.  
  3545. /** Rendering should be succesfully initialized */
  3546.    if(B_RENDER != ((B_RENDER | B_ERROR) & upd->flags))
  3547.       success = false;
  3548.  
  3549. /** Massage some Parameters */
  3550.    if(success) {
  3551.  
  3552. /*    Make sure, that Pass & Pin-Numbers are at least 1 */
  3553.       if(1 >  upd->ints[I_NYPASS]) upd->ints[I_NYPASS] = 1;
  3554.       if(1 >  upd->ints[I_NXPASS]) upd->ints[I_NXPASS] = 1;
  3555.       if(1 >  upd->ints[I_PINS2WRITE]) upd->ints[I_PINS2WRITE] = 1;
  3556.  
  3557.       if((upd->ints[I_NXPASS] * upd->ints[I_NYPASS]) > upd->ints[I_NPASS])
  3558.          upd->ints[I_NPASS] = upd->ints[I_NXPASS] * upd->ints[I_NYPASS];
  3559.  
  3560. /*    Create Default noWeave-Feeds */
  3561.  
  3562.       if(upd->ints[I_NPASS] > upd->int_a[IA_STD_DY].size) {
  3563.          int ix,iy,*ip;
  3564.          UPD_MM_DEL_PARAM(upd->int_a[IA_STD_DY]);
  3565.          UPD_MM_GET_ARRAY(ip,upd->ints[I_NPASS]);
  3566.          upd->int_a[IA_STD_DY].data = ip;
  3567.          upd->int_a[IA_STD_DY].size = upd->ints[I_NPASS];
  3568.  
  3569.          for(iy = 1; iy < upd->ints[I_NYPASS]; ++iy) {
  3570.             for(ix = 1; ix < upd->ints[I_NXPASS]; ++ix) *ip++ = 0;
  3571.             *ip++ = 1;
  3572.          }
  3573.          for(ix = 1; ix < upd->ints[I_NXPASS]; ++ix) *ip++ = 0;
  3574.          *ip = upd->ints[I_NYPASS] * upd->ints[I_PINS2WRITE]
  3575.              - upd->ints[I_NYPASS] + 1;
  3576.  
  3577.          upd->ints[I_BEG_Y] = 0;
  3578.          upd->ints[I_END_Y] = upd->ints[I_PHEIGHT] ? 
  3579.                               upd->ints[I_PHEIGHT] : upd->gsheight;
  3580.       }
  3581.  
  3582. /*    Adjust BEG_Y */
  3583.       if(0 >= upd->ints[I_BEG_Y]) {
  3584.          if(0 <  upd->int_a[IA_BEG_DY].size) {
  3585.             int i,sum = 0;
  3586.             for(i = 0; i < upd->int_a[IA_BEG_DY].size; ++i)
  3587.                sum +=  upd->int_a[IA_BEG_DY].data[i];
  3588.             upd->ints[I_BEG_Y] = sum;
  3589.          } else {
  3590.             upd->ints[I_BEG_Y] = 0;
  3591.          }
  3592.       }
  3593.  
  3594. /*    Adjust END_Y */
  3595. /*    Arrgh, I knew, why I refused to provide defaults for crucial */
  3596. /*    parameters in uniprint. But o.k. it's nice for size-changing */
  3597. /*    PostScript-Code. Nevertheless, it's still not perfect.       */
  3598.  
  3599.       if(0 >= upd->int_a[IA_ENDTOP].size ||
  3600.          0 >= upd->int_a[IA_END_DY].size   ) upd->ints[I_END_Y] =
  3601.          upd->ints[I_PHEIGHT] ? upd->ints[I_PHEIGHT] : upd->gsheight;
  3602.  
  3603.       if(0 >= upd->ints[I_END_Y]) upd->ints[I_END_Y] = upd->ints[I_PHEIGHT] ?
  3604.         upd->ints[I_PHEIGHT] : upd->gsheight;
  3605.  
  3606.  
  3607. /*    Create Default X-Passes */
  3608.  
  3609.       if(0 >= upd->int_a[IA_STD_IX].size) {
  3610.          int ix,i,*ip;
  3611.          UPD_MM_DEL_PARAM(upd->int_a[IA_STD_IX]);
  3612.          UPD_MM_GET_ARRAY(ip,upd->int_a[IA_STD_DY].size);
  3613.          upd->int_a[IA_STD_IX].data = ip;
  3614.          upd->int_a[IA_STD_IX].size = upd->int_a[IA_STD_DY].size;
  3615.  
  3616.          for(i = 0, ix = 0; i < upd->int_a[IA_STD_IX].size; ++i) {
  3617.             *ip++ = ix++;
  3618.             if(ix == upd->ints[I_NXPASS]) ix = 0;
  3619.          }
  3620.       }
  3621.  
  3622.       if((0 >= upd->int_a[IA_BEG_IX].size) &&
  3623.          (0 <  upd->int_a[IA_BEG_DY].size)   ) {
  3624.          int ix,i,*ip;
  3625.          UPD_MM_DEL_PARAM(upd->int_a[IA_BEG_IX]);
  3626.          UPD_MM_GET_ARRAY(ip,upd->int_a[IA_BEG_DY].size);
  3627.          upd->int_a[IA_BEG_IX].data = ip;
  3628.          upd->int_a[IA_BEG_IX].size = upd->int_a[IA_BEG_DY].size;
  3629.  
  3630.          for(i = 0, ix = 0; i < upd->int_a[IA_BEG_IX].size; ++i) {
  3631.             *ip++ = ix++;
  3632.             if(ix == upd->ints[I_NXPASS]) ix = 0;
  3633.          }
  3634.       }
  3635.  
  3636.       if((0 >= upd->int_a[IA_END_IX].size) &&
  3637.          (0 <  upd->int_a[IA_END_DY].size)   ) {
  3638.          int ix,i,*ip;
  3639.          UPD_MM_DEL_PARAM(upd->int_a[IA_END_IX]);
  3640.          UPD_MM_GET_ARRAY(ip,upd->int_a[IA_END_DY].size);
  3641.          upd->int_a[IA_END_IX].data = ip;
  3642.          upd->int_a[IA_END_IX].size = upd->int_a[IA_END_DY].size;
  3643.  
  3644.          for(i = 0, ix = 0; i < upd->int_a[IA_END_IX].size; ++i) {
  3645.             *ip++ = ix++;
  3646.             if(ix == upd->ints[I_NXPASS]) ix = 0;
  3647.          }
  3648.       }
  3649.    }
  3650.  
  3651.    if(upd->ints[I_NPASS] > upd->int_a[IA_STD_DY].size) {
  3652. #if UPD_MESSAGES & UPD_M_WARNING
  3653.       fprintf(stderr,
  3654.         "upd_open_writer: Only %d instead of %d normal Feeds\n",
  3655.         (int) upd->int_a[IA_STD_DY].size,upd->ints[I_NPASS]);
  3656. #endif
  3657.       success = false;
  3658.  
  3659.    } else if(upd->int_a[IA_STD_IX].size < upd->int_a[IA_STD_DY].size) {
  3660. #if UPD_MESSAGES & UPD_M_WARNING
  3661.       fprintf(stderr,
  3662.         "upd_open_writer: Only %d instead of %d normal Xstarts\n",
  3663.         (int) upd->int_a[IA_STD_IX].size,
  3664.         (int) upd->int_a[IA_STD_DY].size);
  3665. #endif
  3666.       success = false;
  3667.    }
  3668.  
  3669. /** The sum of Values in STD_DY should equal NYPASS * PINS2WRITE (diagnostic) */
  3670.  
  3671. #if UPD_MESSAGES & UPD_M_WARNING
  3672.    if(success) {
  3673.       int i,sum = 0;
  3674.       for(i = 0; upd->ints[I_NPASS] > i; ++i)
  3675.          sum += upd->int_a[IA_STD_DY].data[i];
  3676.       if((upd->ints[I_NYPASS]*upd->ints[I_PINS2WRITE]) != sum)
  3677.          fprintf(stderr,
  3678.          "upd_open_writer: Sum of normal Feeds is %d rather than %d\n",
  3679.          sum,upd->ints[I_NYPASS]*upd->ints[I_PINS2WRITE]);
  3680.    }
  3681. #endif
  3682.  
  3683.    if(upd->int_a[IA_BEG_IX].size < upd->int_a[IA_BEG_DY].size) {
  3684. #if UPD_MESSAGES & UPD_M_WARNING
  3685.       fprintf(stderr,
  3686.         "upd_open_writer: Only %d instead of %d initial Xstarts\n",
  3687.         (int) upd->int_a[IA_BEG_IX].size,
  3688.         (int) upd->int_a[IA_BEG_DY].size);
  3689. #endif
  3690.       success = false;
  3691.    }
  3692.  
  3693.    if(upd->int_a[IA_BEGBOT].size < upd->int_a[IA_BEG_DY].size) {
  3694. #if UPD_MESSAGES & UPD_M_WARNING
  3695.       fprintf(stderr,
  3696.         "upd_open_writer: Only %d instead of %d initial Pins\n",
  3697.         (int) upd->int_a[IA_BEGBOT].size,
  3698.         (int) upd->int_a[IA_BEG_DY].size);
  3699. #endif
  3700.       success = false;
  3701.  
  3702.    } else {
  3703.  
  3704.       int i;
  3705.       for(i = 0; i < upd->int_a[IA_BEG_DY].size; ++i)
  3706.          if((upd->int_a[IA_BEGBOT].data[i] > upd->ints[I_PINS2WRITE]) ||
  3707.             (upd->int_a[IA_BEGBOT].data[i] < 0                      )   ) break;
  3708.  
  3709.       if(i < upd->int_a[IA_BEG_DY].size) {
  3710. #if UPD_MESSAGES & UPD_M_WARNING
  3711.          fprintf(stderr,
  3712.            "upd_open_writer: Only %d is invalid initial Pins\n",
  3713.            upd->int_a[IA_BEGBOT].data[i]);
  3714. #endif
  3715.          success = false;
  3716.       }
  3717.    }
  3718.  
  3719.  
  3720. /** The sum of Values in BEG_DY should equal BEG_Y */
  3721.  
  3722. #if UPD_MESSAGES & UPD_M_WARNING
  3723.    if(success) {
  3724.       int i,sum = 0;
  3725.       for(i = 0;  upd->int_a[IA_BEG_DY].size > i; ++i)
  3726.          sum += upd->int_a[IA_BEG_DY].data[i];
  3727.       if(upd->ints[I_BEG_Y] != sum)
  3728.          fprintf(stderr,
  3729.          "upd_open_writer: Sum of initial Feeds is %d rather than %d\n",
  3730.          sum,upd->ints[I_BEG_Y]);
  3731.    }
  3732. #endif
  3733.  
  3734.    if(upd->int_a[IA_END_IX].size < upd->int_a[IA_END_DY].size) {
  3735. #if UPD_MESSAGES & UPD_M_WARNING
  3736.       fprintf(stderr,
  3737.         "upd_open_writer: Only %d instead of %d final Xstarts\n",
  3738.         (int) upd->int_a[IA_END_IX].size,
  3739.         (int) upd->int_a[IA_END_DY].size);
  3740. #endif
  3741.       success = false;
  3742.    }
  3743.  
  3744.    if(upd->int_a[IA_ENDTOP].size < upd->int_a[IA_END_DY].size) {
  3745. #if UPD_MESSAGES & UPD_M_WARNING
  3746.       fprintf(stderr,
  3747.         "upd_open_writer: Only %d instead of %d Final Pins\n",
  3748.         (int) upd->int_a[IA_ENDTOP].size,
  3749.         (int) upd->int_a[IA_END_DY].size);
  3750. #endif
  3751.       success = false;
  3752.  
  3753.    } else {
  3754.  
  3755.       int i;
  3756.       for(i = 0; i < upd->int_a[IA_END_DY].size; ++i)
  3757.          if((upd->int_a[IA_ENDTOP].data[i] > upd->ints[I_PINS2WRITE]) ||
  3758.             (upd->int_a[IA_ENDTOP].data[i] < 0                      )   ) break;
  3759.  
  3760.       if(i < upd->int_a[IA_END_DY].size) {
  3761. #if UPD_MESSAGES & UPD_M_WARNING
  3762.          fprintf(stderr,
  3763.            "upd_open_writer: Only %d is invalid initial Pins\n",
  3764.            upd->int_a[IA_ENDTOP].data[i]);
  3765. #endif
  3766.          success = false;
  3767.       }
  3768.    }
  3769.  
  3770. /** SA_SETCOMP must be valid, if present */
  3771.    if((0 < upd->string_a[SA_SETCOMP].size) &&
  3772.       (upd->ncomp > upd->string_a[SA_SETCOMP].size)) {
  3773. #if UPD_MESSAGES & UPD_M_WARNING
  3774.       fprintf(stderr,
  3775.          "upd_open_writer: Only %d SETCOMP-Commands (%d required)\n",
  3776.          (int) upd->string_a[SA_SETCOMP].size,upd->ncomp);
  3777. #endif
  3778.       success = false;
  3779.    }
  3780.  
  3781. /** Determine required number of scan-Buffers */
  3782.  
  3783.    if(success) { /* Compute nscnbuf */
  3784.       int32 want,use;
  3785.  
  3786.       want  = upd->ints[I_NYPASS];
  3787.       want *= upd->ints[I_PINS2WRITE];
  3788.  
  3789.       if(upd->ints[I_NSCNBUF] > want) want = upd->ints[I_NSCNBUF];
  3790.  
  3791.       if(1 > want)                         want = 1;
  3792.  
  3793.       for(use = 1; 0 < use; use <<= 1) if(use > want) break;
  3794.  
  3795.       if(use <= INT_MAX) upd->nscnbuf = upd->ints[I_NSCNBUF] = use;
  3796.       else               success      = false;
  3797.  
  3798.    }                /* Compute nscnbuf */
  3799.  
  3800. /** Determine number of words in scan-buffers */
  3801.  
  3802.    if(success) { /* Compute pwidth, scnmsk, nbytes, pheight */
  3803.  
  3804.       if(0 < upd->ints[I_PWIDTH]) upd->pwidth = upd->ints[I_PWIDTH];
  3805.       else                        upd->pwidth = upd->gswidth;
  3806.  
  3807.       upd->nbytes  = (upd->pwidth+CHAR_BIT*sizeof(upd->scnbuf[0]->bytes[0]) - 1)
  3808.             /                   (CHAR_BIT*sizeof(upd->scnbuf[0]->bytes[0]));
  3809.  
  3810.       upd->scnmsk  = upd->nscnbuf - 1;
  3811.  
  3812.       if(0 < upd->ints[I_PHEIGHT]) upd->pheight = upd->ints[I_PHEIGHT];
  3813.       else                         upd->pheight = upd->gsheight;
  3814.  
  3815.    }             /* Compute pwidth, scnmsk, nbytes */
  3816.  
  3817. /** Call the writer-specific open-function */
  3818.  
  3819.    if(success) { /* Determine sizes */
  3820.       switch(upd->choice[C_FORMAT]) {
  3821.          case FMT_RAS:
  3822.             if(0 > upd_open_rascomp(udev)) success = false;
  3823.          break;
  3824.          case FMT_EPSON:
  3825.             if(0 > upd_open_wrtescp(udev)) success = false;
  3826.          break;
  3827.          case FMT_ESCP2Y:
  3828.          case FMT_ESCP2XY:
  3829.             if(0 > upd_open_wrtescp2(udev)) success = false;
  3830.          break;
  3831.          case FMT_RTL:
  3832.             if(0 > upd_open_wrtrtl(udev))   success = false;
  3833.          break;
  3834.          case FMT_CANON: /* (hr) */
  3835.             if(0 > upd_open_wrtcanon(udev)) success = false;
  3836.          break;
  3837.          default:
  3838.             success = false;
  3839. #if UPD_MESSAGES & UPD_M_WARNING
  3840.             fprintf(stderr,"upd_open_writer: Unknown writer-type %d\n",
  3841.                 upd->choice[C_FORMAT]);
  3842. #endif
  3843.          break;
  3844.       }
  3845.    }             /* Determine sizes*/
  3846.  
  3847. /** Allocate the Outputbuffer */
  3848.    if(success && (0 < upd->noutbuf)) { /* Allocate outbuf */
  3849.       upd->outbuf = gs_malloc(upd->noutbuf,sizeof(upd->outbuf[0]),"upd/outbuf");
  3850.       if(!upd->outbuf) success = false;
  3851.    }                                   /* Allocate outbuf */
  3852.  
  3853. /** Allocate the desired scan-buffer-pointers */
  3854.    if(success) {
  3855.       upd->scnbuf = gs_malloc(upd->nscnbuf,sizeof(upd->scnbuf[0]),"upd/scnbuf");
  3856.       if(NULL == upd->scnbuf) {
  3857.          success = false;
  3858.       } else {
  3859.          int ibuf;
  3860.          for(ibuf = 0; ibuf < upd->nscnbuf; ++ibuf) {
  3861.             if(success) upd->scnbuf[ibuf] =
  3862.                gs_malloc(upd->ncomp,sizeof(upd->scnbuf[0][0]),"upd/scnbuf[]");
  3863.             else upd->scnbuf[ibuf] = NULL;
  3864.  
  3865.             if(!upd->scnbuf[ibuf]) {
  3866.                success = false;
  3867.             } else {
  3868.                int icomp;
  3869.                for(icomp = 0; icomp < upd->ncomp; ++icomp) {
  3870.                   if(success) upd->scnbuf[ibuf][icomp].bytes =
  3871.                     gs_malloc(upd->nbytes,sizeof(upd->scnbuf[0][0].bytes[0]),
  3872.                     "upd/bytes");
  3873.                   else        upd->scnbuf[ibuf][icomp].bytes = NULL;
  3874.                   if(!upd->scnbuf[ibuf][icomp].bytes) success = false;
  3875.  
  3876.                   if(0 < upd->nlimits) {
  3877.  
  3878.                      upd->scnbuf[ibuf][icomp].xbegin = gs_malloc(upd->nlimits,
  3879.                         sizeof(upd->scnbuf[0][0].xbegin[0]),"upd/xbegin");
  3880.                      if(!upd->scnbuf[ibuf][icomp].xbegin) success = false;
  3881.  
  3882.                      upd->scnbuf[ibuf][icomp].xend   = gs_malloc(upd->nlimits,
  3883.                         sizeof(upd->scnbuf[0][0].xend[0]),"upd/xend");
  3884.                      if(!upd->scnbuf[ibuf][icomp].xbegin) success = false;
  3885.  
  3886.                   } else {
  3887.  
  3888.                      upd->scnbuf[ibuf][icomp].xbegin = NULL;
  3889.                      upd->scnbuf[ibuf][icomp].xend   = NULL;
  3890.  
  3891.                   }
  3892.                }
  3893.             }
  3894.          }
  3895.       }
  3896.    }
  3897.  
  3898.    if(success) upd->flags |= B_FORMAT;
  3899.    else        upd_close_writer(udev);
  3900.  
  3901.    return success ? 1 : -1;
  3902. }
  3903.  
  3904. /* ------------------------------------------------------------------- */
  3905. /* upd_close_writer: Deinitialize rendering                            */
  3906. /* ------------------------------------------------------------------- */
  3907.  
  3908. private void
  3909. upd_close_writer(upd_device *udev)
  3910. {
  3911.    const upd_p upd = udev->upd;
  3912.  
  3913.    if(upd) {
  3914.       int ibuf,icomp;
  3915.  
  3916.       if((0 < upd->noutbuf) && upd->outbuf)
  3917.          gs_free(upd->outbuf,upd->noutbuf,sizeof(upd->outbuf[0]),"upd/outbuf");
  3918.       upd->noutbuf = 0;
  3919.       upd->outbuf  = NULL;
  3920.  
  3921.       if((0 < upd->nscnbuf) && upd->scnbuf) {
  3922.          for(ibuf = 0; upd->nscnbuf > ibuf; ++ibuf) {
  3923.  
  3924.             if(!upd->scnbuf[ibuf]) continue;
  3925.  
  3926.             for(icomp = 0; icomp < upd->ncomp; ++icomp) {
  3927.  
  3928.                if((0 < upd->nbytes) && upd->scnbuf[ibuf][icomp].bytes)
  3929.                   gs_free(upd->scnbuf[ibuf][icomp].bytes,upd->nbytes,
  3930.                      sizeof(upd->scnbuf[ibuf][icomp].words[0]),"upd/bytes");
  3931.                upd->scnbuf[ibuf][icomp].bytes = NULL;
  3932.  
  3933.                if((0 < upd->nlimits) && upd->scnbuf[ibuf][icomp].xbegin)
  3934.                   gs_free(upd->scnbuf[ibuf][icomp].xbegin,upd->nlimits,
  3935.                      sizeof(upd->scnbuf[ibuf][icomp].xbegin[0]),"upd/xbegin");
  3936.                upd->scnbuf[ibuf][icomp].xbegin = NULL;
  3937.  
  3938.                if((0 < upd->nlimits) && upd->scnbuf[ibuf][icomp].xend)
  3939.                   gs_free(upd->scnbuf[ibuf][icomp].xend,upd->nlimits,
  3940.                      sizeof(upd->scnbuf[ibuf][icomp].xend[0]),"upd/xend");
  3941.                upd->scnbuf[ibuf][icomp].xend = NULL;
  3942.             }
  3943.  
  3944.             if(icomp)
  3945.                gs_free(upd->scnbuf[ibuf],upd->ncomp,sizeof(upd->scnbuf[0][0]),
  3946.                   "upd/scnbuf[]");
  3947.             upd->scnbuf[ibuf] = NULL;
  3948.  
  3949.          }
  3950.          gs_free(upd->scnbuf,upd->nscnbuf,sizeof(upd->scnbuf[0]),"upd/scnbuf");
  3951.       }
  3952.  
  3953.  
  3954.       upd->flags &= ~B_FORMAT;
  3955.    }
  3956. }
  3957.  
  3958.  
  3959. /* ------------------------------------------------------------------- */
  3960. /* upd_limits: Establish passwise limits, after rendering              */
  3961. /* ------------------------------------------------------------------- */
  3962.  
  3963. private void
  3964. upd_limits(upd_p upd, bool check)
  3965. {
  3966.    updscan_p  scans = upd->scnbuf[upd->yscnbuf & upd->scnmsk], scan;
  3967.    int   xs,x,xe,icomp,pass;
  3968.    byte *bytes,bit;
  3969.  
  3970.    for(icomp = 0; icomp < upd->ncomp; ++icomp) {
  3971.       scan = scans + icomp;
  3972.       for(pass = 0; pass < upd->nlimits; ++pass) {
  3973.          scan->xbegin[pass] = upd->pwidth;
  3974.          scan->xend[  pass] = -1;
  3975.       }
  3976.    }
  3977.  
  3978.    if(check) { /* Really check */
  3979.       for(icomp = 0; icomp < upd->ncomp; ++icomp) { /* Check Components */
  3980.          scan  = scans + icomp;
  3981.          bytes = scan->bytes;
  3982.  
  3983.          for(xs = 0; xs < upd->nbytes  && !bytes[xs];   ++xs);
  3984.  
  3985.          if(xs < upd->nbytes) { /* Has Data */
  3986.             for(xe = upd->nbytes; xs < xe && !bytes[xe-1]; --xe);
  3987.  
  3988.             for(pass = 0; pass < upd->nlimits; ++pass) { /* limit (pass) loop */
  3989.  
  3990.                x = ((xs<<3)/upd->nlimits)*upd->nlimits + pass;
  3991.                while((x >> 3) < xs) x += upd->nlimits;
  3992.  
  3993.                bit = 0x80 >> (x & 7);
  3994.                while(x < scan->xbegin[pass]) {
  3995.                   if(bytes[x>>3] & bit) scan->xbegin[pass] = x;
  3996.                   x  += upd->nlimits;
  3997.                   bit = 0x80 >> (x & 7);
  3998.                }
  3999.  
  4000.                x = (((xe<<3)|7)/upd->nlimits)*upd->nlimits + pass;
  4001.  
  4002.                while((x >> 3) < xe) x += upd->nlimits;
  4003.                while((x >> 3) > xe) x -= upd->nlimits;
  4004.  
  4005.                bit = 0x80 >> (xs & 7);
  4006.                while(x > scan->xend[pass]) {
  4007.                   if(bytes[x>>3] & bit) scan->xend[pass] = x;
  4008.                   x -= upd->nlimits;
  4009.                   bit = 0x80 >> (x & 7);
  4010.                }
  4011.  
  4012.             }                                            /* limit (pass) loop */
  4013.  
  4014.          }                      /* Has Data */
  4015.  
  4016.       }                                             /* Check Components */
  4017.  
  4018.    }           /* Really check */
  4019.  
  4020. }
  4021.  
  4022. /* ------------------------------------------------------------------- */
  4023. /* upd_open_rascomp: ncomp * 1Bit Raster-Writer                        */
  4024. /* ------------------------------------------------------------------- */
  4025.  
  4026. private int
  4027. upd_open_rascomp(upd_device *udev)
  4028. {
  4029.    const upd_p upd = udev->upd;
  4030.    int32 noutbuf;
  4031.    int error = 0;
  4032.  
  4033.    noutbuf = upd->pwidth;
  4034.  
  4035.    if(1 < upd->ncomp) noutbuf *= 8;
  4036.  
  4037.    noutbuf = ((noutbuf+15)>>4)<<1;
  4038.  
  4039.    if(INT_MAX >= noutbuf) {
  4040.       upd->noutbuf = noutbuf;
  4041.       upd->start_writer = upd_start_rascomp;
  4042.       upd->writer       = upd_rascomp;
  4043.    } else {
  4044.       error = -1;
  4045.    }
  4046.  
  4047.    return error;
  4048. }
  4049.  
  4050. /* ------------------------------------------------------------------- */
  4051. /* upd_start_rascomp: write appropiate raster-header                   */
  4052. /* ------------------------------------------------------------------- */
  4053. #if arch_is_big_endian
  4054. #define put32(I32,Out)       \
  4055.    fwrite(&I32,1,4,Out)
  4056. #else
  4057. #define put32(I32,Out)       \
  4058.    putc(((I32)>>24)&255,Out),\
  4059.    putc(((I32)>>16)&255,Out),\
  4060.    putc(((I32)>> 8)&255,Out),\
  4061.    putc( (I32)     &255,Out)
  4062. #endif
  4063.  
  4064. private int
  4065. upd_start_rascomp(upd_p upd, FILE *out) {
  4066.  
  4067. /** if no begin-sequence externally set */
  4068.    if(0 == upd->strings[S_BEGIN].size) {
  4069.       int32 val;
  4070.  
  4071. /**   ras_magic */
  4072.       val = 0x59a66a95;
  4073.       put32(val,out);
  4074.  
  4075. /**   ras_width */
  4076.       val = upd->pwidth;
  4077.       put32(val,out);
  4078.  
  4079. /**   ras_height */
  4080.       val = upd->pheight;
  4081.       put32(val,out);
  4082.  
  4083. /**   ras_depth */
  4084.       if(1 < upd->ncomp) val = 8;
  4085.       else               val = 1;
  4086.       put32(val,out);
  4087.  
  4088. /**   ras_length */
  4089.       val *= upd->pwidth;
  4090.       val = ((val+15)>>4)<<1;
  4091.       val *= upd->pheight;
  4092.       put32(val,out);
  4093.  
  4094. /**   ras_type */
  4095.       val = 1;
  4096.       put32(val,out);
  4097.  
  4098. /**   ras_maptype */
  4099.       val = 1;
  4100.       put32(val,out);
  4101.  
  4102. /**   ras_maplength */
  4103.       val = 3 * (1 << upd->ncomp);
  4104.       put32(val,out);
  4105.  
  4106. /**   R,G,B-Map */
  4107.       if(1 == upd->ncomp) {
  4108.          const updcomp_p comp = upd->valptr[0];
  4109.  
  4110.          if(upd->cmap[comp->cmap].rise) {
  4111.             putc((char) 0x00,out); putc((char) 0xff,out);
  4112.             putc((char) 0x00,out); putc((char) 0xff,out);
  4113.             putc((char) 0x00,out); putc((char) 0xff,out);
  4114.          } else {
  4115.             putc((char) 0xff,out); putc((char) 0x00,out);
  4116.             putc((char) 0xff,out); putc((char) 0x00,out);
  4117.             putc((char) 0xff,out); putc((char) 0x00,out);
  4118.          }
  4119.  
  4120.       } else if(3 == upd->ncomp) {
  4121.          int rgb;
  4122.  
  4123.          for( rgb = 0; rgb < 3; ++rgb) {
  4124.             int entry;
  4125.             for(entry = 0; entry < 8; ++entry) {
  4126.                byte xval = upd->cmap[rgb].rise ? 0x00 : 0xff;
  4127.                if(entry & (1<<upd->cmap[rgb].comp)) xval ^= 0xff;
  4128.                putc(xval,out);
  4129.             }
  4130.          }
  4131.       } else { /* we have 4 components */
  4132.          int rgb;
  4133.  
  4134.          for(rgb = 16; 0 <= rgb; rgb -= 8) {
  4135.             int entry;
  4136.             for(entry = 0; entry < 16; ++entry) {
  4137.                uint32 rgbval = 0;
  4138.  
  4139.                if(entry & (1<<upd->cmap[0].comp)) {
  4140.  
  4141.                   rgbval = 0xffffff;
  4142.  
  4143.                } else {
  4144.  
  4145.                   if(entry & (1<<upd->cmap[1].comp)) rgbval |= 0xff0000;
  4146.                   if(entry & (1<<upd->cmap[2].comp)) rgbval |= 0x00ff00;
  4147.                   if(entry & (1<<upd->cmap[3].comp)) rgbval |= 0x0000ff;
  4148.                }
  4149.  
  4150.                if(!upd->cmap[1].rise) rgbval ^= 0xff0000;
  4151.                if(!upd->cmap[2].rise) rgbval ^= 0x00ff00;
  4152.                if(!upd->cmap[3].rise) rgbval ^= 0x0000ff;
  4153.  
  4154.                if(!(upd->choice[C_MAPPER] == MAP_RGBW)) rgbval ^= 0xffffff;
  4155.  
  4156.                putc((rgbval>>rgb)&255,out);
  4157.             }
  4158.          }
  4159.       }
  4160.    }
  4161.    memset(upd->outbuf,0,upd->noutbuf);
  4162.  
  4163.    return 0;
  4164. }
  4165.  
  4166. /* ------------------------------------------------------------------- */
  4167. /* upd_rascomp: assemble & write a scanline                            */
  4168. /* ------------------------------------------------------------------- */
  4169. private int
  4170. upd_rascomp(upd_p upd, FILE *out) {
  4171.    updscan_p scan = upd->scnbuf[upd->yscan & upd->scnmsk];
  4172.    uint bits = upd->pwidth;
  4173.  
  4174.    if(1 == upd->ncomp) {
  4175.       uint nbytes;
  4176.  
  4177.       nbytes = (bits+7)>>3;
  4178.       memcpy(upd->outbuf,scan->bytes,nbytes);
  4179.       if((bits &= 7)) upd->outbuf[nbytes-1] &= ((byte) 0xff) << (8-bits);
  4180.  
  4181.    } else {
  4182.  
  4183.       byte  *buf   = upd->outbuf, bit = 0x80;
  4184.       int    ibyte = 0;
  4185.  
  4186.       while(0 < bits--) {
  4187.          byte val = 0;
  4188.          switch(upd->ncomp) {
  4189.             case 4:  if(scan[3].bytes[ibyte] & bit) val |= 8;
  4190.             case 3:  if(scan[2].bytes[ibyte] & bit) val |= 4;
  4191.                      if(scan[1].bytes[ibyte] & bit) val |= 2;
  4192.             case 1:  if(scan[0].bytes[ibyte] & bit) val |= 1;
  4193.          }
  4194.          *buf++ = val;
  4195.          if(!(bit >>= 1)) {
  4196.             bit    = 0x80;
  4197.             ibyte += 1;
  4198.          }
  4199.       }
  4200.    }
  4201.  
  4202.    fwrite(upd->outbuf,1,upd->noutbuf,out);
  4203.    upd->yscan += 1;
  4204.  
  4205.    return 0;
  4206. }
  4207.  
  4208. /* ------------------------------------------------------------------- */
  4209. /* upd_open_wrtescp: ESC/P Writer intended for ESC * m commands        */
  4210. /* ------------------------------------------------------------------- */
  4211.  
  4212. private int
  4213. upd_open_wrtescp(upd_device *udev)
  4214. {
  4215.    const upd_p      upd  = udev->upd;
  4216.    int              error = 0;
  4217.  
  4218. /** Adjust the PageLength, If Requested */
  4219.    if((B_PAGELENGTH & upd->flags) &&
  4220.       (0 < upd->strings[S_BEGIN].size)) { /* BOP-Checker */
  4221.      int   i,state = 0,value = 0;
  4222.      byte *bp = (byte *) upd->strings[S_BEGIN].data;
  4223.      for(i = 0; i < upd->strings[S_BEGIN].size; ++i) {
  4224.         switch(state) {
  4225.            case  0:
  4226.               if(0x1b == bp[i]) state = 1;
  4227.            break;
  4228.            case  1:
  4229.               if('C'  == bp[i]) state = 2;
  4230.               else              state = 0;
  4231.            break;
  4232.            case  2:
  4233.               if(bp[i]) {
  4234.                  value = 0.5 + udev->height * (float) bp[i]
  4235.                                / udev->y_pixels_per_inch;
  4236.                  if(       0 >= value) bp[i] = 1;
  4237.                  else if(128 >  value) bp[i] = value;
  4238.                  else                  bp[i] = 127;
  4239.                  state = 0;
  4240.               } else {
  4241.                  state = 3;
  4242.               }
  4243.            break;
  4244.            case  3:
  4245.               value = 0.5 + udev->height / udev->y_pixels_per_inch;
  4246.               if(       0 >= value) bp[i] = 1;
  4247.               else if( 22 >  value) bp[i] = value;
  4248.               else                  bp[i] = 22;
  4249.               state = 0;
  4250.            break;
  4251.         }
  4252.      }
  4253.    }                                    /* BOP-Checker */
  4254.  
  4255.  
  4256. /** Either SETLF or YMOVE must be set */
  4257.    if((0 == upd->strings[S_SETLF].size) &&
  4258.       (0 == upd->strings[S_YMOVE].size)   ) {
  4259. #if UPD_MESSAGES & UPD_M_WARNING
  4260.       fprintf(stderr,
  4261.         "ESC/P-Open: Either SETLF- or YMOVE-Command must be present\n");
  4262. #endif
  4263.       error = -1;
  4264.    }
  4265.  
  4266. /** X-Positioning must be set too */
  4267.    if(((1 <  upd->ints[I_XSTEP]        ) &&
  4268.        (0 == upd->strings[S_XSTEP].size)   ) ||
  4269.       ((1 < upd->ints[I_NXPASS]        ) &&
  4270.        (0 == upd->strings[S_XMOVE].size) &&
  4271.        (0 == upd->strings[S_XSTEP].size)   )   ) {
  4272. #if UPD_MESSAGES & UPD_M_WARNING
  4273.       fprintf(stderr,
  4274.          "ESC/P-Open: Missing XSTEP- and/or XMOVE-Command\n");
  4275. #endif
  4276.       error = -1;
  4277.    }
  4278.  
  4279. /** SA_WRITECOMP must be valid */
  4280.    if(upd->ncomp > upd->string_a[SA_WRITECOMP].size) {
  4281. #if UPD_MESSAGES & UPD_M_WARNING
  4282.       fprintf(stderr,
  4283.          "ESC/P-Open: WRITECOMP-Commands must be given\n");
  4284. #endif
  4285.       error = -1;
  4286.    }
  4287.  
  4288. /**
  4289. If all this is correct, it's time to coumput the size of the output-buffer.
  4290. It must hold:
  4291.   1. Y-Positioning
  4292.   2. X-Positioning
  4293.   3. Component-Selection
  4294.   4. The Raster-Command
  4295.   5. The Data
  4296. */
  4297.    if(0 <= error) {
  4298.       int32 i,noutbuf,need;
  4299.  
  4300.       if(0 < upd->strings[S_YMOVE].size) {
  4301.          noutbuf = upd->strings[S_YMOVE].size + 2;
  4302.       } else {
  4303.          int nmax = upd->pheight;
  4304.          if(      1 < upd->ints[I_YSTEP]) nmax /=  upd->ints[I_YSTEP];
  4305.          else if(-1 > upd->ints[I_YSTEP]) nmax *= -upd->ints[I_YSTEP];
  4306.          noutbuf  = 2 * upd->strings[S_SETLF].size + 2;
  4307.          noutbuf += nmax/255 + 1;
  4308.       }
  4309.  
  4310.       if(1 < upd->ints[I_YSTEP])
  4311.          noutbuf += (upd->ints[I_YSTEP]-1) * upd->strings[S_YSTEP].size;
  4312.  
  4313.       noutbuf +=  upd->strings[S_XMOVE].size + 2;
  4314.  
  4315.       if(1 < upd->ints[I_XSTEP])
  4316.          noutbuf += (upd->ints[I_XSTEP]-1) * upd->strings[S_XSTEP].size;
  4317.  
  4318.       if(0 < upd->string_a[SA_SETCOMP].size) {
  4319.          need = 0;
  4320.          for(i = 0; i < upd->ncomp; ++i)
  4321.             if(need < upd->string_a[SA_SETCOMP].data[i].size)
  4322.                need = upd->string_a[SA_SETCOMP].data[i].size;
  4323.          noutbuf += need;
  4324.       }
  4325.  
  4326.       need = 0;
  4327.       for(i = 0; i < upd->ncomp; ++i)
  4328.          if(need < upd->string_a[SA_WRITECOMP].data[i].size)
  4329.             need = upd->string_a[SA_WRITECOMP].data[i].size;
  4330.       noutbuf += need + 2;
  4331.  
  4332.       noutbuf += ((upd->ints[I_PINS2WRITE] + 7) / 8)
  4333.                * ((upd->pwidth + upd->ints[I_NXPASS] - 1)/upd->ints[I_NXPASS]);
  4334.  
  4335.       if((0 < noutbuf) && (noutbuf <= INT_MAX)) {
  4336.          upd->noutbuf      = noutbuf;
  4337.          upd->writer       = upd_wrtescp;
  4338.          upd->nlimits      = upd->ints[I_NXPASS];
  4339.          error             = 1;
  4340.       } else {
  4341.          error = -1;
  4342. #if      UPD_MESSAGES & UPD_M_WARNING
  4343.             fprintf(stderr,
  4344.               "ESC/P-Open: %ld is unreasonable size of Outputbuffer\n",
  4345.               (long) noutbuf);
  4346. #endif
  4347.       }
  4348.    }
  4349.  
  4350.    return error;
  4351. }
  4352.  
  4353. /* ------------------------------------------------------------------- */
  4354. /* upd_wrtescp: Write a pass                                           */
  4355. /* ------------------------------------------------------------------- */
  4356.  
  4357. private int
  4358. upd_wrtescp(upd_p upd, FILE *out)
  4359. {
  4360.    int  pinbot,pin,pintop,xbegin,x,xend,icomp,ybegin,yend,y,ioutbuf,n,ixpass;
  4361.    byte *obytes,bit;
  4362.    updscan_p scan;
  4363.  
  4364. /** Determine the number of pins to write */
  4365.  
  4366.    if(upd->yscan < upd->ints[I_BEG_Y]) {
  4367.       ixpass = upd->int_a[IA_BEG_IX].data[upd->ipass];
  4368.       pintop = 0;
  4369.       pinbot = upd->int_a[IA_BEGBOT].data[upd->ipass];
  4370.    } else if(upd->yscan >= upd->ints[I_END_Y]) {
  4371.       ixpass = upd->int_a[IA_END_IX].data[upd->ipass];
  4372.       pinbot = upd->ints[I_PINS2WRITE];
  4373.       pintop = pinbot - upd->int_a[IA_ENDTOP].data[upd->ipass];
  4374.    } else {
  4375.       ixpass = upd->int_a[IA_STD_IX].data[upd->ipass];
  4376.       pintop = 0;
  4377.       pinbot = upd->ints[I_PINS2WRITE];
  4378.    }
  4379.  
  4380.    ybegin =  pintop * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
  4381.    yend   =  pinbot * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
  4382.  
  4383. /** Determine Width of this scan */
  4384.  
  4385.    xbegin = upd->pwidth;
  4386.    xend   = -1;
  4387.  
  4388.    for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Pin-testloop */
  4389.  
  4390.       if(0 > y) continue; /* Inserted Scanlines */
  4391.  
  4392.       scan = upd->scnbuf[y & upd->scnmsk];
  4393.  
  4394.       for(icomp = 0; icomp < upd->ncomp; ++icomp) { /* Compwise test */
  4395.          if(xbegin > scan[icomp].xbegin[ixpass])
  4396.             xbegin = scan[icomp].xbegin[ixpass];
  4397.          if(xend   < scan[icomp].xend[  ixpass])
  4398.             xend   = scan[icomp].xend[  ixpass];
  4399.       }                                             /* Compwise test */
  4400.  
  4401.    }                                                     /* Pin-testloop */
  4402.  
  4403.    if(xbegin <= xend) { /* Some data to write */
  4404.  
  4405.       ioutbuf = 0;
  4406.  
  4407.       if(0 == upd->strings[S_XMOVE].size) xbegin = ixpass;
  4408.  
  4409. /*
  4410.  *    Adjust the Printers Y-Position
  4411.  */
  4412.       if(upd->yscan != upd->yprinter) { /* Adjust Y-Position */
  4413.          if(B_YABS & upd->flags) y = upd->yscan + upd->ints[I_YOFS];
  4414.          else                    y = upd->yscan - upd->yprinter;
  4415.  
  4416.          if(      1 < upd->ints[I_YSTEP]) {
  4417.             n      =  y / upd->ints[I_YSTEP];  /* Major-Steps */
  4418.             y     -=  n * upd->ints[I_YSTEP];  /* Minor-Steps */
  4419.          } else if(-1 > upd->ints[I_YSTEP]) {
  4420.             n      = y * -upd->ints[I_YSTEP];  /* May this work? */
  4421.             y      = 0;
  4422.          } else {
  4423.             n      = y;
  4424.             y      = 0;
  4425.          }
  4426.  
  4427.          if(n) { /* Coarse Positioning */
  4428.             if(0 < upd->strings[S_YMOVE].size) {
  4429.  
  4430.                memcpy(upd->outbuf+ioutbuf,
  4431.                           upd->strings[S_YMOVE].data,
  4432.                           upd->strings[S_YMOVE].size);
  4433.                ioutbuf += upd->strings[S_YMOVE].size;
  4434.  
  4435.                upd->outbuf[ioutbuf++] =  n     & 0xff;
  4436.                upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
  4437.  
  4438.             } else {
  4439.  
  4440.                while(n) {
  4441.                   int n2do = n > 255 ? 255 : n;
  4442.                   if(upd->lf != n2do) {
  4443.                      memcpy(upd->outbuf+ioutbuf,
  4444.                                 upd->strings[S_SETLF].data,
  4445.                                 upd->strings[S_SETLF].size);
  4446.                      ioutbuf += upd->strings[S_SETLF].size;
  4447.                      upd->outbuf[ioutbuf++] = n2do;
  4448.                      upd->lf                = n2do;
  4449.                   }
  4450.                   upd->outbuf[ioutbuf++] = '\n';
  4451.                   n -= n2do;
  4452.                }
  4453.             }
  4454.          }       /* Coarse Positioning */
  4455.  
  4456.          if(0 < upd->strings[S_YSTEP].size) {
  4457.             while(y--) {
  4458.                memcpy(upd->outbuf+ioutbuf,
  4459.                           upd->strings[S_YSTEP].data,
  4460.                           upd->strings[S_YSTEP].size);
  4461.                ioutbuf += upd->strings[S_YSTEP].size;
  4462.             }
  4463.          }
  4464.  
  4465.          upd->yprinter = upd->yscan;
  4466.       }                                 /* Adjust Y-Position */
  4467.  
  4468. /*
  4469.  * Now write the required components
  4470.  */
  4471.       for(icomp = 0; icomp < upd->ncomp; ++icomp) { /* Component-Print */
  4472. /*
  4473.  *       First check, wether this Component needs printing
  4474.  */
  4475.          for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Comp-Test */
  4476.             if(0 > y) continue;
  4477.             scan = upd->scnbuf[y & upd->scnmsk]+icomp;
  4478.             if(0 <= scan->xend[ixpass]) break;
  4479.          }                                                     /* Comp-Test */
  4480.          if(y >= yend) continue; /* Component not required */
  4481. /*
  4482.  *       Select the Component
  4483.  */
  4484.          if((0 < upd->string_a[SA_SETCOMP].size) &&
  4485.             (upd->icomp != icomp               )   ) { /* Selection enabled */
  4486.             upd->icomp = icomp;
  4487.             if(0 < upd->string_a[SA_SETCOMP].data[icomp].size) {
  4488.                memcpy(upd->outbuf+ioutbuf,
  4489.                           upd->string_a[SA_SETCOMP].data[icomp].data,
  4490.                           upd->string_a[SA_SETCOMP].data[icomp].size);
  4491.                ioutbuf += upd->string_a[SA_SETCOMP].data[icomp].size;
  4492.             }
  4493.          }                                      /* Selection enabled */
  4494. /*
  4495.  *       Establish the X-Position
  4496.  */
  4497.          if(xbegin != upd->xprinter) {
  4498.  
  4499.             if(0 == upd->strings[S_XMOVE].size) {
  4500.  
  4501.                upd->outbuf[ioutbuf++] = '\r';
  4502.                upd->xprinter          =  0;
  4503.                n = 0;
  4504.                x = ixpass;
  4505.  
  4506.             } else {
  4507.  
  4508.                if(B_XABS & upd->flags) n = x = xbegin + upd->ints[I_XOFS];
  4509.                else                    n = x = xbegin - upd->xprinter;
  4510.  
  4511.                if(        1 < upd->ints[I_XSTEP]) {
  4512.                   if(0 > n) {
  4513.                      n  -= upd->ints[I_XSTEP];
  4514.                      x  -= n;
  4515.                   }
  4516.                   if(n) n  /= upd->ints[I_XSTEP]; /* Major-Steps */
  4517.                   if(x) x  %= upd->ints[I_XSTEP]; /* Minor-Steps */
  4518.  
  4519.                } else if(-1 > upd->ints[I_XSTEP]) {
  4520.                   n *= -upd->ints[I_XSTEP]; /* May this work? */
  4521.                   x  = 0;
  4522.                }
  4523.  
  4524.                if(n) { /* Adjust X-Position */
  4525.  
  4526.                  memcpy(upd->outbuf+ioutbuf,
  4527.                              upd->strings[S_XMOVE].data,
  4528.                              upd->strings[S_XMOVE].size);
  4529.                   ioutbuf += upd->strings[S_XMOVE].size;
  4530.  
  4531.                   upd->outbuf[ioutbuf++] =  n     & 0xff;
  4532.                   upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
  4533.  
  4534.                }       /* Adjust X-Position */
  4535.  
  4536.             }
  4537.  
  4538.             if(x && 0 < upd->strings[S_XSTEP].size) { /* Fine-Adjust X */
  4539.                while(x--) {
  4540.                   memcpy(upd->outbuf+ioutbuf,
  4541.                              upd->strings[S_XSTEP].data,
  4542.                              upd->strings[S_XSTEP].size);
  4543.                   ioutbuf += upd->strings[S_XSTEP].size;
  4544.                }
  4545.             }                                         /* Fine-Adjust X */
  4546.          }
  4547.          upd->xprinter = xend+1;
  4548. /*
  4549.  *       Send the Write-Command
  4550.  */
  4551.          if(0 < upd->string_a[SA_WRITECOMP].data[icomp].size) {
  4552.             memcpy(upd->outbuf+ioutbuf,
  4553.                        upd->string_a[SA_WRITECOMP].data[icomp].data,
  4554.                        upd->string_a[SA_WRITECOMP].data[icomp].size);
  4555.             ioutbuf += upd->string_a[SA_WRITECOMP].data[icomp].size;
  4556.          }
  4557.          n = (xend - xbegin) / upd->ints[I_NXPASS] + 1;;
  4558.          upd->outbuf[ioutbuf++] =  n     & 255;
  4559.          upd->outbuf[ioutbuf++] = (n>>8) & 255;
  4560. /*
  4561.  *       Clear the data-Part
  4562.  */
  4563.          obytes   =  upd->outbuf+ioutbuf;
  4564.          n       *= (upd->ints[I_PINS2WRITE]+7)>>3;
  4565.          memset(obytes,0,n);
  4566.          ioutbuf += n;
  4567. /*
  4568.  *       Set the Pixels
  4569.  */
  4570.          for(x = xbegin; x <= xend; x += upd->ints[I_NXPASS]) {
  4571.  
  4572.             bit     = 0x80 >> (pintop & 7);
  4573.             obytes += pintop>>3;
  4574.  
  4575.             for(pin = pintop, y = ybegin; pin < pinbot;
  4576.                 pin++,        y += upd->ints[I_NYPASS]) {
  4577.                if(0 <= y) {
  4578.                   scan = upd->scnbuf[y & upd->scnmsk]+icomp;
  4579.                   if(scan->bytes[x>>3] & (0x80 >> (x & 7))) *obytes |= bit;
  4580.                }
  4581.                if(!(bit >>= 1)) { obytes++; bit = 0x80; }
  4582.             }
  4583.  
  4584.             obytes += (upd->ints[I_PINS2WRITE]-pinbot+7)>>3;
  4585.          }
  4586. /*
  4587.  *       Send this Component to the Printer
  4588.  */
  4589.          fwrite(upd->outbuf,1,ioutbuf,out);
  4590.          ioutbuf = 0;
  4591.       }                                             /* Component-Print */
  4592.    }                    /* Some data to write */
  4593.  
  4594. /** Advance counters in upd, change modi */
  4595.  
  4596.    if(upd->yscan < upd->ints[I_BEG_Y]) {
  4597.       upd->yscan += upd->int_a[IA_BEG_DY].data[upd->ipass++];
  4598.       if(     upd->ints[I_BEG_Y] <= upd->yscan) upd->ipass = 0;
  4599.       else if(upd->int_a[IA_BEG_DY].size <= upd->ipass) upd->ipass = 0;
  4600.    } else if(upd->yscan >= upd->ints[I_END_Y]) {
  4601.       upd->yscan += upd->int_a[IA_END_DY].data[upd->ipass++];
  4602.       if(upd->int_a[IA_END_DY].size <= upd->ipass) upd->ipass = 0;
  4603.    } else {
  4604.       upd->yscan += upd->int_a[IA_STD_DY].data[upd->ipass++];
  4605.       if(upd->int_a[IA_STD_DY].size <= upd->ipass) upd->ipass = 0;
  4606.       if(upd->yscan >= upd->ints[I_END_Y])         upd->ipass = 0;
  4607.    }
  4608.  
  4609.    return 0;
  4610. }
  4611.  
  4612. /* ------------------------------------------------------------------- */
  4613. /* upd_open_wrtescp2: ESC/P2 Writer intended for ESC . 1  commands     */
  4614. /* ------------------------------------------------------------------- */
  4615.  
  4616. private int
  4617. upd_open_wrtescp2(upd_device *udev)
  4618. {
  4619.    const upd_p      upd             = udev->upd;
  4620.    int              error           = 0;
  4621.    float            pixels_per_inch = 360.0;
  4622.  
  4623. /** Analyze (and optionally adjust) the BOP-Sequence */
  4624.    if(0 < upd->strings[S_BEGIN].size) { /* BOP-Checker */
  4625.      int   i,state = 0,value = 0;
  4626.      byte *bp = (byte *) upd->strings[S_BEGIN].data;
  4627.      for(i = 0; i < upd->strings[S_BEGIN].size; ++i) {
  4628.         switch(state) {
  4629.            case  0:
  4630.               if(0x1b == bp[i]) state = 1;
  4631.            break;
  4632.            case  1:
  4633.               if('('  == bp[i]) state = 2;
  4634.               else              state = 0;
  4635.            break;
  4636.            case  2:
  4637.               switch(bp[i]) {
  4638.                  case 'U': state =  3; break; /* Printer-Resolution */
  4639.                  case 'C': state =  6; break; /* Page-Length */
  4640.                  case 'c': state = 10; break; /* Top/Bottom Margin */
  4641.                  default:  state =  0; break;
  4642.               }
  4643.            break;
  4644.            case  3:
  4645.               if(1 == bp[i]) state = 4;
  4646.               else           state = 0;
  4647.            break;
  4648.            case  4:
  4649.               if(0 == bp[i]) state = 5;
  4650.               else           state = 0;
  4651.            break;
  4652.            case  5:
  4653.               pixels_per_inch = 3600.0 / (float) bp[i];
  4654.               state = 0;
  4655.            break;
  4656.            case  6:
  4657.               if(2 == bp[i]) state = 7;
  4658.               else           state = 0;
  4659.            break;
  4660.            case  7:
  4661.               if(0 == bp[i]) state = 8;
  4662.               else           state = 0;
  4663.            break;
  4664.            case  8:
  4665.               if(B_PAGELENGTH & upd->flags) {
  4666.                  value = 0.5 + udev->height
  4667.                                * pixels_per_inch / udev->y_pixels_per_inch;
  4668.                  bp[i] =  value     & 0xff;
  4669.               }
  4670.               state = 9;
  4671.            break;
  4672.            case  9:
  4673.               if(B_PAGELENGTH & upd->flags) {
  4674.                  bp[i] = (value>>8) & 0xff;
  4675.               }
  4676.               state = 0;
  4677.            break;
  4678.            case 10:
  4679.               if(4 == bp[i]) state = 11;
  4680.               else           state =  0;
  4681.            break;
  4682.            case 11:
  4683.               if(0 == bp[i]) state = 12;
  4684.               else           state =  0;
  4685.            break;
  4686.            case  12:
  4687.               if(B_TOPMARGIN & upd->flags) {
  4688.                  value =  dev_t_margin(udev) * pixels_per_inch;
  4689.                  bp[i] =  value     & 0xff;
  4690.               }
  4691.               state = 13;
  4692.            break;
  4693.            case  13:
  4694.               if(B_TOPMARGIN & upd->flags) {
  4695.                  bp[i] = (value>>8) & 0xff;
  4696.               }
  4697.               state = 14;
  4698.            break;
  4699.            case  14:
  4700.               if(B_BOTTOMMARGIN & upd->flags) {
  4701.                  value = 0.5 + udev->height
  4702.                                * pixels_per_inch / udev->y_pixels_per_inch
  4703.                        - dev_b_margin(udev) * pixels_per_inch;
  4704.                  bp[i] =  value     & 0xff;
  4705.               }
  4706.               state = 15;
  4707.            break;
  4708.            case  15:
  4709.               if(B_BOTTOMMARGIN & upd->flags) {
  4710.                  bp[i] = (value>>8) & 0xff;
  4711.               }
  4712.               state =  0;
  4713.            break;
  4714.         }
  4715.      }
  4716.    }                                    /* BOP-Checker */
  4717.  
  4718. /** Create Y-Move-Command, if not given */
  4719.    if(0 == upd->strings[S_YMOVE].size) {
  4720.       byte *bp;
  4721.       UPD_MM_DEL_PARAM(upd->strings[S_YMOVE]);
  4722.       UPD_MM_GET_ARRAY(bp,5);
  4723.       upd->strings[S_YMOVE].data = bp;
  4724.       upd->strings[S_YMOVE].size = 5;
  4725.       *bp++ = 0x1b; /* ESC */
  4726.       *bp++ = '(';
  4727.       *bp++ = upd->flags & B_YABS ? 'V' : 'v';
  4728.       *bp++ =  2;
  4729.       *bp++ =  0;
  4730.    }
  4731.  
  4732. /** X-Positioning must be set too, sometimes */
  4733.    if((1 < upd->ints[I_XSTEP]) && (0 == upd->strings[S_XSTEP].size)) {
  4734.  
  4735. #if UPD_MESSAGES & UPD_M_WARNING
  4736.       fprintf(stderr,
  4737.          "ESC/P2-Open: XSTEP-Command required for XSTEP=%d\n",
  4738.          upd->ints[I_XSTEP]);
  4739. #endif
  4740.       error = -1;
  4741.  
  4742.    } else if((1 <  upd->ints[I_NXPASS]       ) &&
  4743.              (0 == upd->strings[S_XMOVE].size) &&
  4744.              (0 == upd->strings[S_XSTEP].size)   ) {
  4745.       byte *bp;
  4746.       int ratio;
  4747.  
  4748.       ratio = (udev->y_pixels_per_inch + .5) / udev->x_pixels_per_inch;
  4749.  
  4750.       if(0 == upd->ints[I_XSTEP]) { /* Adjust scale-factor too! */
  4751.          if(ratio > 1) upd->ints[I_XSTEP] = -ratio;
  4752.       } else {                     /* Adjust scale-factor too! */
  4753.          ratio = -upd->ints[I_XSTEP];
  4754.       }
  4755.  
  4756.       if(2 == upd->ints[I_NXPASS]) { /* Use a relative Step */
  4757.  
  4758.          UPD_MM_DEL_PARAM(upd->strings[S_XSTEP]);
  4759.          UPD_MM_GET_ARRAY(bp,4);
  4760.          upd->strings[S_XSTEP].size = 4;
  4761.          upd->strings[S_XSTEP].data = bp;
  4762.          *bp++ = 0x1b;
  4763.          *bp++ = '\\';
  4764.          *bp++ =  ratio     & 0xff;
  4765.          *bp++ = (ratio>>8) & 0xff;
  4766.  
  4767.       } else {                      /* Use relative or absolute Move */
  4768.  
  4769.          UPD_MM_DEL_PARAM(upd->strings[S_XMOVE]);
  4770.          UPD_MM_GET_ARRAY(bp,2);
  4771.          upd->strings[S_XMOVE].size = 2;
  4772.          upd->strings[S_XMOVE].data = bp;
  4773.          *bp++  = 0x1b;
  4774.          *bp++  = upd->flags & B_XABS ? '$' : '\\';
  4775.  
  4776.       }
  4777.    }
  4778.  
  4779. /** If there is neither a writecomp nor a setcomp-command, generate both */
  4780.    if((0 == upd->string_a[SA_WRITECOMP].size) &&
  4781.       (0 == upd->string_a[SA_SETCOMP].size  )   ) { /* Default-commands */
  4782.       byte *bp;
  4783.       gs_param_string *ap;
  4784.       int   i;
  4785.  
  4786.       if(4 == upd->ncomp) { /* Establish Component-Selection */
  4787.          UPD_MM_DEL_APARAM(upd->string_a[SA_SETCOMP]);
  4788.          UPD_MM_GET_ARRAY(ap,4);
  4789.          upd->string_a[SA_SETCOMP].data = ap;
  4790.          upd->string_a[SA_SETCOMP].size = 4;
  4791.          for(i = 0; i < 4; ++i) {
  4792.             UPD_MM_GET_ARRAY(bp,3);
  4793.             ap[i].size = 3;
  4794.             ap[i].data = bp;
  4795.             *bp++ = 0x1b;
  4796.             *bp++ = 'r';
  4797.             switch(((updcomp_p)upd->valptr[i])->cmap) { /* use COMPORDER! */
  4798.                case 0: *bp++ = 0; break; /* Black */
  4799.                case 1: *bp++ = 2; break; /* Cyan */
  4800.                case 2: *bp++ = 1; break; /* Magenta */
  4801.                case 3: *bp++ = 4; break; /* Yellow */
  4802.             }                                           /* use COMPORDER! */
  4803.          }
  4804.       }                     /* Establish Component-Selection */
  4805.  
  4806.       UPD_MM_DEL_APARAM(upd->string_a[SA_WRITECOMP]);
  4807.       UPD_MM_GET_ARRAY(ap,upd->ncomp);
  4808.       upd->string_a[SA_WRITECOMP].data = ap;
  4809.       upd->string_a[SA_WRITECOMP].size = upd->ncomp;
  4810.       for(i = 0; i < upd->ncomp; ++i) {
  4811.          UPD_MM_GET_ARRAY(bp,6);
  4812.          ap[i].size = 6;
  4813.          ap[i].data = bp;
  4814.          *bp++ = 0x1b;
  4815.          *bp++ = '.';
  4816.          *bp++ =  1;  /* RLE */
  4817.          *bp++ = 3600.0 * upd->ints[I_NYPASS] / udev->y_pixels_per_inch + 0.5;
  4818.          *bp++ = 3600.0 * upd->ints[I_NXPASS] / udev->x_pixels_per_inch + 0.5;
  4819.          *bp++ = upd->ints[I_PINS2WRITE];
  4820.       }
  4821.    }                                                /* Default-commands */
  4822.  
  4823. /** SA_WRITECOMP must be valid */
  4824.    if(upd->ncomp > upd->string_a[SA_WRITECOMP].size) {
  4825. #if UPD_MESSAGES & UPD_M_WARNING
  4826.       fprintf(stderr,
  4827.          "ESC/P2-Open: WRITECOMP-Commands must be given\n");
  4828. #endif
  4829.       error = -1;
  4830.    }
  4831.  
  4832. /** Check Validity of X-Pass */
  4833.    switch(upd->choice[C_FORMAT]) {
  4834.       case FMT_ESCP2Y:
  4835.          if(1 < upd->ints[I_NXPASS]) {
  4836. #if         UPD_MESSAGES & UPD_M_WARNING
  4837.                fprintf(stderr,
  4838.                   "ESC/P2-Open: FMT_ESCP2Y cannot handle multiple X-Passes\n");
  4839. #endif
  4840.             error = -1;
  4841.          } else {
  4842.             upd->writer = upd_wrtescp2;
  4843.          }
  4844.       break;
  4845.       case FMT_ESCP2XY:
  4846.          upd->writer  = upd_wrtescp2x;
  4847.          upd->nlimits = upd->ints[I_NXPASS];
  4848. #if      UPD_MESSAGES & UPD_M_WARNING
  4849.             if(1 == upd->ints[I_NXPASS])
  4850.                fprintf(stderr,
  4851.                   "ESC/P2-Open: FMT_ESCP2XY should not be used with 1X-Pass\n");
  4852. #endif
  4853.       break;
  4854.       default:
  4855. #if      UPD_MESSAGES & UPD_M_WARNING
  4856.             fprintf(stderr,
  4857.                "ESC/P2-Open: %d is not a ESC/P2-Format\n",
  4858.                upd->choice[C_FORMAT]);
  4859. #endif
  4860.          error = - 1;
  4861.       break;
  4862.    }
  4863.  
  4864.  
  4865. /**
  4866. If all this is correct, it's time to compute the size of the output-buffer.
  4867. It must hold:
  4868.   1. Y-Positioning
  4869.   2. X-Positioning
  4870.   3. Component-Selection
  4871.   4. The Raster-Command
  4872.   5. The Data
  4873. */
  4874.    if(0 <= error) {
  4875.       int32 i,noutbuf,need;
  4876.  
  4877.       if(0 < upd->strings[S_YMOVE].size) {
  4878.          noutbuf = upd->strings[S_YMOVE].size + 2;
  4879.       } else {
  4880.          int nmax = upd->pheight;
  4881.          if(      1 < upd->ints[I_YSTEP]) nmax /=  upd->ints[I_YSTEP];
  4882.          else if(-1 > upd->ints[I_YSTEP]) nmax *= -upd->ints[I_YSTEP];
  4883.          noutbuf  = 2 * upd->strings[S_SETLF].size + 2;
  4884.          noutbuf += nmax/255 + 1;
  4885.       }
  4886.  
  4887.       if(1 < upd->ints[I_YSTEP])
  4888.          noutbuf += (upd->ints[I_YSTEP]-1) * upd->strings[S_YSTEP].size;
  4889.  
  4890.       if(0 == upd->strings[S_XMOVE].size) {
  4891.          noutbuf += 1; /* The CR */
  4892.          noutbuf += (upd->ints[I_NXPASS]-1) * upd->strings[S_XSTEP].size;
  4893.       } else {
  4894.          noutbuf +=  upd->strings[S_XMOVE].size + 2;
  4895.  
  4896.          if(1 < upd->ints[I_XSTEP])
  4897.             noutbuf += (upd->ints[I_XSTEP]-1) * upd->strings[S_XSTEP].size;
  4898.       }
  4899.  
  4900.       if(0 < upd->string_a[SA_SETCOMP].size) {
  4901.          need = 0;
  4902.          for(i = 0; i < upd->ncomp; ++i)
  4903.             if(need < upd->string_a[SA_SETCOMP].data[i].size)
  4904.                need = upd->string_a[SA_SETCOMP].data[i].size;
  4905.          noutbuf += need;
  4906.       }
  4907.  
  4908.       need = 0;
  4909.       for(i = 0; i < upd->ncomp; ++i)
  4910.          if(need < upd->string_a[SA_WRITECOMP].data[i].size)
  4911.             need = upd->string_a[SA_WRITECOMP].data[i].size;
  4912.       noutbuf += need + 2;
  4913.  
  4914.       noutbuf += 2*upd->nbytes + (upd->nbytes + 127) / 128;
  4915.  
  4916.       upd->noutbuf      = noutbuf;
  4917.       error             = 1;
  4918.  
  4919.    }
  4920.  
  4921.    return error;
  4922. }
  4923.  
  4924. /* ------------------------------------------------------------------- */
  4925. /* upd_wrtescp2: Write a pass                                          */
  4926. /* ------------------------------------------------------------------- */
  4927.  
  4928. private int
  4929. upd_wrtescp2(upd_p upd, FILE *out)
  4930. {
  4931.    int  pinbot,pin,pintop,xbegin,x,xend,icomp,ybegin,yend,y,ioutbuf,n;
  4932.    byte *obytes;
  4933.    updscan_p scan;
  4934.  
  4935. /** Determine the number of pins to write */
  4936.  
  4937.    if(upd->yscan < upd->ints[I_BEG_Y]) {
  4938.       pintop = 0;
  4939.       pinbot = upd->int_a[IA_BEGBOT].data[upd->ipass];
  4940.    } else if(upd->yscan >= upd->ints[I_END_Y]) {
  4941.       pinbot = upd->ints[I_PINS2WRITE];
  4942.       pintop = pinbot - upd->int_a[IA_ENDTOP].data[upd->ipass];
  4943.    } else {
  4944.       pintop = 0;
  4945.       pinbot = upd->ints[I_PINS2WRITE];
  4946.    }
  4947.  
  4948.    ybegin =  pintop * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
  4949.    yend   =  pinbot * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
  4950.  
  4951. /** Determine Width of this scan */
  4952.  
  4953.    xbegin = upd->nbytes;
  4954.    xend   = -1;
  4955.  
  4956.    for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Pin-testloop */
  4957.  
  4958.       if(0 > y) continue; /* Inserted Scanlines */
  4959.  
  4960.       scan = upd->scnbuf[y & upd->scnmsk];
  4961.  
  4962.       for(icomp = 0; icomp < upd->ncomp; ++icomp) { /* Compwise test */
  4963.          obytes = scan[icomp].bytes;
  4964.  
  4965.          for(x = 0; x < xbegin && !obytes[x]; x++);
  4966.          if(x < xbegin) xbegin = x;
  4967.  
  4968.          if(x < upd->nbytes) {
  4969.             for(x = upd->nbytes-1; x > xend && !obytes[x]; x--);
  4970.             if(x > xend) xend = x;
  4971.          }
  4972.       }                                             /* Compwise test */
  4973.  
  4974.    }                                                     /* Pin-testloop */
  4975.  
  4976.    if(xbegin <= xend) { /* Some data to write */
  4977.  
  4978.       ioutbuf = 0;
  4979.  
  4980.       if(0 == upd->strings[S_XMOVE].size) xbegin = 0;
  4981.  
  4982. /*
  4983.  *    Adjust the Printers Y-Position
  4984.  */
  4985.       if(upd->yscan != upd->yprinter) { /* Adjust Y-Position */
  4986.          if(B_YABS & upd->flags) y = upd->yscan + upd->ints[I_YOFS];
  4987.          else                    y = upd->yscan - upd->yprinter;
  4988.  
  4989.          if(      1 < upd->ints[I_YSTEP]) {
  4990.             n      =  y / upd->ints[I_YSTEP];  /* Major-Steps */
  4991.             y     -=  n * upd->ints[I_YSTEP];  /* Minor-Steps */
  4992.          } else if(-1 > upd->ints[I_YSTEP]) {
  4993.             n      = y * -upd->ints[I_YSTEP];  /* May this work? */
  4994.             y      = 0;
  4995.          } else {
  4996.             n      = y;
  4997.             y      = 0;
  4998.          }
  4999.  
  5000.          if(n) { /* Coarse Positioning */
  5001.             memcpy(upd->outbuf+ioutbuf,
  5002.                        upd->strings[S_YMOVE].data,upd->strings[S_YMOVE].size);
  5003.             ioutbuf += upd->strings[S_YMOVE].size;
  5004.  
  5005.             upd->outbuf[ioutbuf++] =  n     & 0xff;
  5006.             upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
  5007.  
  5008.          }       /* Coarse Positioning */
  5009.  
  5010.          if(0 < upd->strings[S_YSTEP].size) {
  5011.             while(y--) {
  5012.                memcpy(upd->outbuf+ioutbuf,
  5013.                           upd->strings[S_YSTEP].data,
  5014.                           upd->strings[S_YSTEP].size);
  5015.                ioutbuf += upd->strings[S_YSTEP].size;
  5016.             }
  5017.          }
  5018.  
  5019.          upd->yprinter = upd->yscan;
  5020.       }                                 /* Adjust Y-Position */
  5021. /*
  5022.  * Now write the required components
  5023.  */
  5024.       for(icomp = 0; icomp < upd->ncomp; ++icomp) { /* Component-Print */
  5025. /*
  5026.  *       First check, wether this Component needs printing
  5027.  */
  5028.          for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Comp-Test */
  5029.             if(0 > y) continue;
  5030.             obytes = upd->scnbuf[y & upd->scnmsk][icomp].bytes;
  5031.             for(x = xbegin; x <= xend && !obytes[x]; ++x);
  5032.             if(             x <= xend) break;
  5033.          }                                                     /* Comp-Test */
  5034.          if(y >= yend) continue; /* Component not required */
  5035. /*
  5036.  *       Select the Component
  5037.  */
  5038.          if((0 < upd->string_a[SA_SETCOMP].size) &&
  5039.             (upd->icomp != icomp               )   ) { /* Selection enabled */
  5040.             upd->icomp = icomp;
  5041.             if(0 < upd->string_a[SA_SETCOMP].data[icomp].size) {
  5042.                memcpy(upd->outbuf+ioutbuf,
  5043.                           upd->string_a[SA_SETCOMP].data[icomp].data,
  5044.                           upd->string_a[SA_SETCOMP].data[icomp].size);
  5045.                ioutbuf += upd->string_a[SA_SETCOMP].data[icomp].size;
  5046.             }
  5047.          }                                      /* Selection enabled */
  5048. /*
  5049.  *       Establish the X-Position
  5050.  */
  5051.          if(xbegin != upd->xprinter) {
  5052.  
  5053.             if(0 == upd->strings[S_XMOVE].size) {
  5054.  
  5055.                upd->outbuf[ioutbuf++] = '\r';
  5056.                upd->xprinter          =  0;
  5057.                n = 0;
  5058.                x = 0;
  5059.  
  5060.             } else {
  5061.  
  5062.                if(B_XABS & upd->flags) n = x = xbegin + upd->ints[I_XOFS];
  5063.                else                    n = x = xbegin - upd->xprinter;
  5064.  
  5065.                if(        1 < upd->ints[I_XSTEP]) {
  5066.                   if(0 > n) {
  5067.                      n  -= upd->ints[I_XSTEP];
  5068.                      x  -= n;
  5069.                   }
  5070.                   if(n) n  /= upd->ints[I_XSTEP]; /* Major-Steps */
  5071.                   if(x) x  %= upd->ints[I_XSTEP]; /* Minor-Steps */
  5072.  
  5073.                } else if(-1 > upd->ints[I_XSTEP]) {
  5074.                   n *= -upd->ints[I_XSTEP]; /* May this work? */
  5075.                   x  = 0;
  5076.                }
  5077.  
  5078.                if(n) { /* Adjust X-Position */
  5079.  
  5080.                  memcpy(upd->outbuf+ioutbuf,
  5081.                              upd->strings[S_XMOVE].data,
  5082.                              upd->strings[S_XMOVE].size);
  5083.                   ioutbuf += upd->strings[S_XMOVE].size;
  5084.  
  5085.                   upd->outbuf[ioutbuf++] =  n     & 0xff;
  5086.                   upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
  5087.  
  5088.                }       /* Adjust X-Position */
  5089.  
  5090.             }
  5091.  
  5092.             if(x && 0 < upd->strings[S_XSTEP].size) { /* Fine-Adjust X */
  5093.                while(x--) {
  5094.                   memcpy(upd->outbuf+ioutbuf,
  5095.                              upd->strings[S_XSTEP].data,
  5096.                              upd->strings[S_XSTEP].size);
  5097.                   ioutbuf += upd->strings[S_XSTEP].size;
  5098.                }
  5099.             }                                         /* Fine-Adjust X */
  5100.          }
  5101.          upd->xprinter = xend+1;
  5102.  
  5103. /*
  5104.  *       Send the Write-Command
  5105.  */
  5106.          if(0 < upd->string_a[SA_WRITECOMP].data[icomp].size) {
  5107.             memcpy(upd->outbuf+ioutbuf,
  5108.                        upd->string_a[SA_WRITECOMP].data[icomp].data,
  5109.                        upd->string_a[SA_WRITECOMP].data[icomp].size);
  5110.             ioutbuf += upd->string_a[SA_WRITECOMP].data[icomp].size;
  5111.          }
  5112.          n = xend + 1 - xbegin;
  5113.          upd->outbuf[ioutbuf++] = (n<<3) & 255;
  5114.          upd->outbuf[ioutbuf++] = (n>>5) & 255;
  5115. /*
  5116.  *       Set the Pixels
  5117.  */
  5118.          for(pin = 0; pin < pintop; ++pin) {
  5119.             ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
  5120.             fwrite(upd->outbuf,1,ioutbuf,out);
  5121.             ioutbuf = 0;
  5122.          }
  5123.  
  5124.          for(y = ybegin; 0 > y;    y += upd->ints[I_NYPASS]) {
  5125.             ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
  5126.             fwrite(upd->outbuf,1,ioutbuf,out);
  5127.             ioutbuf = 0;
  5128.          }
  5129.  
  5130.          for(; y < yend; y += upd->ints[I_NYPASS]) {
  5131.             ioutbuf += upd_rle(upd->outbuf+ioutbuf,
  5132.                upd->scnbuf[y & upd->scnmsk][icomp].bytes+xbegin,n);
  5133.             fwrite(upd->outbuf,1,ioutbuf,out);
  5134.             ioutbuf = 0;
  5135.          }
  5136.  
  5137.          for(pin = pinbot; pin < upd->ints[I_PINS2WRITE]; ++pin) {
  5138.             ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
  5139.             fwrite(upd->outbuf,1,ioutbuf,out);
  5140.             ioutbuf = 0;
  5141.          }
  5142.       }                                             /* Component-Print */
  5143.    }                    /* Some data to write */
  5144.  
  5145. /** Advance counters in upd, change modi */
  5146.    if(upd->yscan < upd->ints[I_BEG_Y]) {
  5147.       upd->yscan += upd->int_a[IA_BEG_DY].data[upd->ipass++];
  5148.       if(     upd->ints[I_BEG_Y] <= upd->yscan) upd->ipass = 0;
  5149.       else if(upd->int_a[IA_BEG_DY].size <= upd->ipass) upd->ipass = 0;
  5150.    } else if(upd->yscan >= upd->ints[I_END_Y]) {
  5151.       upd->yscan += upd->int_a[IA_END_DY].data[upd->ipass++];
  5152.       if(upd->int_a[IA_END_DY].size <= upd->ipass) upd->ipass = 0;
  5153.    } else {
  5154.       upd->yscan += upd->int_a[IA_STD_DY].data[upd->ipass++];
  5155.       if(upd->int_a[IA_STD_DY].size <= upd->ipass) upd->ipass = 0;
  5156.       if(upd->yscan >= upd->ints[I_END_Y])         upd->ipass = 0;
  5157.    }
  5158.  
  5159.    return 0;
  5160. }
  5161.  
  5162. /* ------------------------------------------------------------------- */
  5163. /* upd_wrtescp2x: Write an ESC/P2-pass with X-Weaving                  */
  5164. /* ------------------------------------------------------------------- */
  5165.  
  5166. private int
  5167. upd_wrtescp2x(upd_p upd, FILE *out)
  5168. {
  5169.    int  pinbot,pin,pintop,xbegin,x,xend,icomp,ybegin,yend,y,ioutbuf,n,ixpass;
  5170.    byte *obytes,bit;
  5171.    updscan_p scan;
  5172.  
  5173. /** Determine the number of pins to write */
  5174.  
  5175.    if(upd->yscan < upd->ints[I_BEG_Y]) {
  5176.       ixpass = upd->int_a[IA_BEG_IX].data[upd->ipass];
  5177.       pintop = 0;
  5178.       pinbot = upd->int_a[IA_BEGBOT].data[upd->ipass];
  5179.    } else if(upd->yscan >= upd->ints[I_END_Y]) {
  5180.       ixpass = upd->int_a[IA_END_IX].data[upd->ipass];
  5181.       pinbot = upd->ints[I_PINS2WRITE];
  5182.       pintop = pinbot - upd->int_a[IA_ENDTOP].data[upd->ipass];
  5183.    } else {
  5184.       ixpass = upd->int_a[IA_STD_IX].data[upd->ipass];
  5185.       pintop = 0;
  5186.       pinbot = upd->ints[I_PINS2WRITE];
  5187.    }
  5188.  
  5189.    ybegin =  pintop * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
  5190.    yend   =  pinbot * upd->ints[I_NYPASS] + upd->yscan - upd->ints[I_BEGSKIP];
  5191.  
  5192. /** Determine Width of this scan */
  5193.  
  5194.    xbegin = upd->pwidth;
  5195.    xend   = -1;
  5196.  
  5197.    for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Pin-testloop */
  5198.  
  5199.       if(0 > y) continue; /* Inserted Scanlines */
  5200.  
  5201.       scan = upd->scnbuf[y & upd->scnmsk];
  5202.  
  5203.       for(icomp = 0; icomp < upd->ncomp; ++icomp) { /* Compwise test */
  5204.          if(xbegin > scan[icomp].xbegin[ixpass])
  5205.             xbegin = scan[icomp].xbegin[ixpass];
  5206.          if(xend   < scan[icomp].xend[  ixpass])
  5207.             xend   = scan[icomp].xend[  ixpass];
  5208.       }                                             /* Compwise test */
  5209.  
  5210.    }                                                     /* Pin-testloop */
  5211.  
  5212.    if(xbegin <= xend) { /* Some data to write */
  5213.  
  5214.       ioutbuf = upd->nbytes;
  5215.  
  5216.       if(0 == upd->strings[S_XMOVE].size) xbegin = ixpass;
  5217.  
  5218. /*
  5219.  *    Adjust the Printers Y-Position
  5220.  */
  5221.       if(upd->yscan != upd->yprinter) { /* Adjust Y-Position */
  5222.          if(B_YABS & upd->flags) y = upd->yscan + upd->ints[I_YOFS];
  5223.          else                    y = upd->yscan - upd->yprinter;
  5224.  
  5225.          if(      1 < upd->ints[I_YSTEP]) {
  5226.             n      =  y / upd->ints[I_YSTEP];  /* Major-Steps */
  5227.             y     -=  n * upd->ints[I_YSTEP];  /* Minor-Steps */
  5228.          } else if(-1 > upd->ints[I_YSTEP]) {
  5229.             n      = y * -upd->ints[I_YSTEP];  /* May this work? */
  5230.             y      = 0;
  5231.          } else {
  5232.             n      = y;
  5233.             y      = 0;
  5234.          }
  5235.  
  5236.          if(n) { /* Coarse Positioning */
  5237.             memcpy(upd->outbuf+ioutbuf,
  5238.                        upd->strings[S_YMOVE].data,upd->strings[S_YMOVE].size);
  5239.             ioutbuf += upd->strings[S_YMOVE].size;
  5240.  
  5241.             upd->outbuf[ioutbuf++] =  n     & 0xff;
  5242.             upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
  5243.  
  5244.          }       /* Coarse Positioning */
  5245.  
  5246.          if(0 < upd->strings[S_YSTEP].size) {
  5247.             while(y--) {
  5248.                memcpy(upd->outbuf+ioutbuf,
  5249.                           upd->strings[S_YSTEP].data,
  5250.                           upd->strings[S_YSTEP].size);
  5251.                ioutbuf += upd->strings[S_YSTEP].size;
  5252.             }
  5253.          }
  5254.  
  5255.          upd->yprinter = upd->yscan;
  5256.       }                                 /* Adjust Y-Position */
  5257.  
  5258. /*
  5259.  * Now write the required components
  5260.  */
  5261.       for(icomp = 0; icomp < upd->ncomp; ++icomp) { /* Component-Print */
  5262. /*
  5263.  *       First check, wether this Component needs printing
  5264.  */
  5265.          for(y = ybegin; y < yend; y += upd->ints[I_NYPASS]) { /* Comp-Test */
  5266.             if(0 > y) continue;
  5267.             scan = upd->scnbuf[y & upd->scnmsk]+icomp;
  5268.             if(0 <= scan->xend[ixpass]) break;
  5269.          }                                                     /* Comp-Test */
  5270.          if(y >= yend) continue; /* Component not required */
  5271. /*
  5272.  *       Select the Component
  5273.  */
  5274.          if((0 < upd->string_a[SA_SETCOMP].size) &&
  5275.             (upd->icomp != icomp               )   ) { /* Selection enabled */
  5276.             upd->icomp = icomp;
  5277.             if(0 < upd->string_a[SA_SETCOMP].data[icomp].size) {
  5278.                memcpy(upd->outbuf+ioutbuf,
  5279.                           upd->string_a[SA_SETCOMP].data[icomp].data,
  5280.                           upd->string_a[SA_SETCOMP].data[icomp].size);
  5281.                ioutbuf += upd->string_a[SA_SETCOMP].data[icomp].size;
  5282.             }
  5283.          }                                      /* Selection enabled */
  5284. /*
  5285.  *       Establish the X-Position
  5286.  */
  5287.          if(xbegin != upd->xprinter) {
  5288.  
  5289.             if(0 == upd->strings[S_XMOVE].size) {
  5290.  
  5291.                upd->outbuf[ioutbuf++] = '\r';
  5292.                upd->xprinter          =  0;
  5293.                n = 0;
  5294.                x = ixpass;
  5295.  
  5296.             } else {
  5297.  
  5298.                if(B_XABS & upd->flags) n = x = xbegin + upd->ints[I_XOFS];
  5299.                else                    n = x = xbegin - upd->xprinter;
  5300.  
  5301.                if(        1 < upd->ints[I_XSTEP]) {
  5302.                   if(0 > n) {
  5303.                      n  -= upd->ints[I_XSTEP];
  5304.                      x  -= n;
  5305.                   }
  5306.                   if(n) n  /= upd->ints[I_XSTEP]; /* Major-Steps */
  5307.                   if(x) x  %= upd->ints[I_XSTEP]; /* Minor-Steps */
  5308.  
  5309.                } else if(-1 > upd->ints[I_XSTEP]) {
  5310.                   n *= -upd->ints[I_XSTEP]; /* May this work? */
  5311.                   x  = 0;
  5312.                }
  5313.  
  5314.                if(n) { /* Adjust X-Position */
  5315.  
  5316.                  memcpy(upd->outbuf+ioutbuf,
  5317.                              upd->strings[S_XMOVE].data,
  5318.                              upd->strings[S_XMOVE].size);
  5319.                   ioutbuf += upd->strings[S_XMOVE].size;
  5320.  
  5321.                   upd->outbuf[ioutbuf++] =  n     & 0xff;
  5322.                   upd->outbuf[ioutbuf++] = (n>>8) & 0xff;
  5323.  
  5324.                }       /* Adjust X-Position */
  5325.  
  5326.             }
  5327.  
  5328.             if(x && 0 < upd->strings[S_XSTEP].size) { /* Fine-Adjust X */
  5329.                while(x--) {
  5330.                   memcpy(upd->outbuf+ioutbuf,
  5331.                              upd->strings[S_XSTEP].data,
  5332.                              upd->strings[S_XSTEP].size);
  5333.                   ioutbuf += upd->strings[S_XSTEP].size;
  5334.                }
  5335.             }                                         /* Fine-Adjust X */
  5336.          }
  5337.          upd->xprinter = xend+1;
  5338.  
  5339. /*
  5340.  *       Send the Write-Command
  5341.  */
  5342.          if(0 < upd->string_a[SA_WRITECOMP].data[icomp].size) {
  5343.             memcpy(upd->outbuf+ioutbuf,
  5344.                        upd->string_a[SA_WRITECOMP].data[icomp].data,
  5345.                        upd->string_a[SA_WRITECOMP].data[icomp].size);
  5346.             ioutbuf += upd->string_a[SA_WRITECOMP].data[icomp].size;
  5347.          }
  5348.          n = ((xend - xbegin) / upd->ints[I_NXPASS] + 8) & ~7;
  5349.          upd->outbuf[ioutbuf++] =  n     & 255;
  5350.          upd->outbuf[ioutbuf++] = (n>>8) & 255;
  5351.          n >>= 3;
  5352. /*
  5353.  *       Set the Pixels
  5354.  */
  5355.          for(pin = 0; pin < pintop; ++pin) {
  5356.             ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
  5357.             fwrite(upd->outbuf+upd->nbytes,1,ioutbuf-upd->nbytes,out);
  5358.             ioutbuf = upd->nbytes;
  5359.          }
  5360.  
  5361.          for(y = ybegin; 0 > y;    y += upd->ints[I_NYPASS]) {
  5362.             ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
  5363.             fwrite(upd->outbuf+upd->nbytes,1,ioutbuf-upd->nbytes,out);
  5364.             ioutbuf = upd->nbytes;
  5365.          }
  5366.  
  5367.          for(;           y < yend; y += upd->ints[I_NYPASS]) {
  5368.             byte * ibytes = upd->scnbuf[y & upd->scnmsk][icomp].bytes;
  5369.             obytes = upd->outbuf;
  5370.             memset(obytes,0,upd->nbytes);
  5371.             bit = 0x80;
  5372.             for(x = xbegin; x <= xend; x += upd->ints[I_NXPASS]) {
  5373.                if(ibytes[x>>3] & (0x80 >> (x & 7))) *obytes |= bit;
  5374.                if(!(bit >>= 1)) { obytes++; bit = 0x80; }
  5375.             }
  5376.             ioutbuf += upd_rle(upd->outbuf+ioutbuf,upd->outbuf,n);
  5377.             fwrite(upd->outbuf+upd->nbytes,1,ioutbuf-upd->nbytes,out);
  5378.             ioutbuf = upd->nbytes;
  5379.          }
  5380.  
  5381.          for(pin = pinbot; pin < upd->ints[I_PINS2WRITE]; ++pin) {
  5382.             ioutbuf += upd_rle(upd->outbuf+ioutbuf,NULL,n);
  5383.             fwrite(upd->outbuf+upd->nbytes,1,ioutbuf-upd->nbytes,out);
  5384.             ioutbuf = upd->nbytes;
  5385.          }
  5386.       }                                             /* Component-Print */
  5387.    }                    /* Some data to write */
  5388.  
  5389. /** Advance counters in upd, change modi */
  5390.  
  5391.    if(upd->yscan < upd->ints[I_BEG_Y]) {
  5392.       upd->yscan += upd->int_a[IA_BEG_DY].data[upd->ipass++];
  5393.       if(     upd->ints[I_BEG_Y] <= upd->yscan) upd->ipass = 0;
  5394.       else if(upd->int_a[IA_BEG_DY].size <= upd->ipass) upd->ipass = 0;
  5395.    } else if(upd->yscan >= upd->ints[I_END_Y]) {
  5396.       upd->yscan += upd->int_a[IA_END_DY].data[upd->ipass++];
  5397.       if(upd->int_a[IA_END_DY].size <= upd->ipass) upd->ipass = 0;
  5398.    } else {
  5399.       upd->yscan += upd->int_a[IA_STD_DY].data[upd->ipass++];
  5400.       if(upd->int_a[IA_STD_DY].size <= upd->ipass) upd->ipass = 0;
  5401.       if(upd->yscan >= upd->ints[I_END_Y])         upd->ipass = 0;
  5402.    }
  5403.  
  5404.    return 0;
  5405. }
  5406.  
  5407. /* ------------------------------------------------------------------- */
  5408. /* upd_rle: The Runlength-Compressor                                   */
  5409. /* ------------------------------------------------------------------- */
  5410.  
  5411. private int
  5412. upd_rle(byte *out,const byte *in,int nbytes)
  5413. {
  5414.  
  5415.    int used = 0;
  5416.    int crun,cdata;
  5417.    byte run;
  5418.  
  5419.    if(in != NULL) { /* Data present */
  5420.  
  5421.       crun = 1;
  5422.  
  5423.       while(nbytes > 0) { /* something to compress */
  5424.  
  5425.          run = in[0];
  5426.  
  5427.          while((nbytes > crun) && (run == in[crun])) if(++crun == 128) break;
  5428.  
  5429.          if((crun > 2) || (crun == nbytes)) { /* use this run */
  5430.  
  5431.             *out++  = (257 - crun) & 0xff; *out++ = run; used += 2;
  5432.  
  5433.             nbytes -= crun; in    += crun;
  5434.             crun = 1;
  5435.  
  5436.          } else {                            /* ignore this run */
  5437.  
  5438.             for(cdata = crun; (nbytes > cdata) && (crun < 4);) {
  5439.                if(run  == in[cdata]) crun += 1;
  5440.                else run = in[cdata], crun  = 1;
  5441.                if(++cdata == 128) break;
  5442.             }
  5443.  
  5444.             if(crun < 3) crun   = 0;    /* ignore trailing run */
  5445.             else         cdata -= crun;
  5446.  
  5447.             *out++ = cdata-1;     used++;
  5448.             memcpy(out,in,cdata); used += cdata; out   += cdata;
  5449.  
  5450.             nbytes -= cdata; in    += cdata;
  5451.  
  5452.          }              /* use/ignore run */
  5453.  
  5454.       }                  /* something to compress */
  5455.  
  5456.    } else {         /* Empty scans to fill bands */
  5457.  
  5458.       while(nbytes > 0) {
  5459.          crun    = nbytes > 128 ? 128 : nbytes;
  5460.          nbytes -= crun;
  5461.          *out++  = (257 - crun) & 0xff;
  5462.          *out++  = 0;
  5463.          used   += 2;
  5464.       }
  5465.    }                /* Data present or empty */
  5466.    return used;
  5467. }
  5468.  
  5469. /* ------------------------------------------------------------------- */
  5470. /* upd_open_wrtrtl: Basic HP-RTL Writer                                */
  5471. /* ------------------------------------------------------------------- */
  5472.  
  5473. private int
  5474. upd_open_wrtrtl(upd_device *udev)
  5475. {
  5476.    const upd_p      upd  = udev->upd;
  5477.    int              error = 0;
  5478.  
  5479. /** Adjust the Raster-Width */
  5480.  
  5481.    if(0 < upd->strings[S_BEGIN].size) { /* BOP-Checker */
  5482.  
  5483.      int   i,j,state = 0;
  5484.      char  cv[16];
  5485.      byte  *bp;
  5486.      uint  ncv,nbp;
  5487.  
  5488.      j = -1;
  5489.      for(i = 0; i < upd->strings[S_BEGIN].size; ++i) {
  5490.  
  5491.         switch(state) {
  5492.            case  0:
  5493.               if(0x1b == upd->strings[S_BEGIN].data[i]) state = 1;
  5494.            break;
  5495.            case  1:
  5496.               if('*'  == upd->strings[S_BEGIN].data[i]) state = 2;
  5497.               else                                      state = 0;
  5498.            break;
  5499.            case  2:
  5500.               if('r'  == upd->strings[S_BEGIN].data[i])     state = 3;
  5501.               else if('t' == upd->strings[S_BEGIN].data[i]) state = 4;
  5502.               else                                          state = 0;          
  5503.            break;
  5504.  
  5505.            case  3:
  5506.  
  5507.               if((B_PAGEWIDTH & upd->flags) &&
  5508.                  (('s' == upd->strings[S_BEGIN].data[i]) ||
  5509.                   ('S' == upd->strings[S_BEGIN].data[i])   )) {
  5510.  
  5511.                  sprintf(cv,"%d",upd->pwidth);
  5512.                  ncv = strlen(cv);
  5513.  
  5514.                  nbp = (j+1) + ncv + (upd->strings[S_BEGIN].size-i);
  5515.                  UPD_MM_GET_ARRAY(bp,nbp);
  5516.  
  5517.                  if(0 <= j) memcpy(bp,upd->strings[S_BEGIN].data,j+1);
  5518.                  memcpy(bp+j+1,    cv,ncv);
  5519.                  memcpy(bp+j+1+ncv,upd->strings[S_BEGIN].data+i,
  5520.                                    upd->strings[S_BEGIN].size-i);
  5521.                  i = j+1+ncv;
  5522.                  UPD_MM_DEL_PARAM(upd->strings[S_BEGIN]);
  5523.                  upd->strings[S_BEGIN].data = bp;
  5524.                  upd->strings[S_BEGIN].size = nbp;
  5525.  
  5526.               } else if((B_PAGELENGTH & upd->flags) &&
  5527.                  (('t' == upd->strings[S_BEGIN].data[i]) ||
  5528.                   ('T' == upd->strings[S_BEGIN].data[i])   )) {
  5529.  
  5530.                  sprintf(cv,"%d",upd->pheight);
  5531.                  ncv = strlen(cv);
  5532.  
  5533.                  nbp = (j+1) + ncv + (upd->strings[S_BEGIN].size-i);
  5534.                  UPD_MM_GET_ARRAY(bp,nbp);
  5535.  
  5536.                  if(0 <= j) memcpy(bp,upd->strings[S_BEGIN].data,j+1);
  5537.                  memcpy(bp+j+1,    cv,ncv);
  5538.                  memcpy(bp+j+1+ncv,upd->strings[S_BEGIN].data+i,
  5539.                                    upd->strings[S_BEGIN].size-i);
  5540.                  i = j+1+ncv;
  5541.                  UPD_MM_DEL_PARAM(upd->strings[S_BEGIN]);
  5542.                  upd->strings[S_BEGIN].data = bp;
  5543.                  upd->strings[S_BEGIN].size = nbp;
  5544.  
  5545.               }
  5546.               if(isupper(upd->strings[S_BEGIN].data[i])) state = 0;
  5547.  
  5548.            break;
  5549.  
  5550.            case 4:
  5551.  
  5552.               if((B_RESOLUTION & upd->flags) &&
  5553.                  (('r' == upd->strings[S_BEGIN].data[i]) ||
  5554.                   ('R' == upd->strings[S_BEGIN].data[i])   )) {
  5555.  
  5556.                  sprintf(cv,"%d",(int)
  5557.                   ((udev->y_pixels_per_inch < udev->x_pixels_per_inch ?
  5558.                     udev->x_pixels_per_inch : udev->y_pixels_per_inch)
  5559.                     +0.5));
  5560.                  ncv = strlen(cv);
  5561.  
  5562.                  nbp = (j+1) + ncv + (upd->strings[S_BEGIN].size-i);
  5563.                  UPD_MM_GET_ARRAY(bp,nbp);
  5564.  
  5565.                  if(0 <= j) memcpy(bp,upd->strings[S_BEGIN].data,j+1);
  5566.                  memcpy(bp+j+1,    cv,ncv);
  5567.                  memcpy(bp+j+1+ncv,upd->strings[S_BEGIN].data+i,
  5568.                                    upd->strings[S_BEGIN].size-i);
  5569.                  i = j+1+ncv;
  5570.                  UPD_MM_DEL_PARAM(upd->strings[S_BEGIN]);
  5571.                  upd->strings[S_BEGIN].data = bp;
  5572.                  upd->strings[S_BEGIN].size = nbp;
  5573.  
  5574.               }
  5575.               if(isupper(upd->strings[S_BEGIN].data[i])) state = 0;
  5576.  
  5577.            break;
  5578.         }
  5579.  
  5580.         if((0x30 > upd->strings[S_BEGIN].data[i]) ||
  5581.            (0x39 < upd->strings[S_BEGIN].data[i])   ) j = i;
  5582.  
  5583.      }
  5584.    }                                    /* BOP-Checker */
  5585.  
  5586.  
  5587. /** SA_WRITECOMP must be valid */
  5588.    if(upd->ncomp > upd->string_a[SA_WRITECOMP].size) {
  5589. #if UPD_MESSAGES & UPD_M_WARNING
  5590.       fprintf(stderr,
  5591.          "PCL-Open: WRITECOMP-Commands must be given\n");
  5592. #endif
  5593.       error = -1;
  5594.    }
  5595.  
  5596. /**
  5597. If all this is correct, it's time to compute the size of the output-buffer.
  5598. It must hold:
  5599.   1. Y-Positioning
  5600.   2. Component-Data
  5601. */
  5602.    if(0 <= error) {
  5603.       int32 ny,noutbuf;
  5604.       char  tmp[16];
  5605.  
  5606.       if(0 < upd->strings[S_YMOVE].size) {
  5607.          sprintf(tmp,"%d",upd->pheight);
  5608.          ny = upd->strings[S_YMOVE].size + strlen(tmp);
  5609.       } else {
  5610.          ny = 1 + upd->string_a[SA_WRITECOMP].data[upd->ncomp-1].size;
  5611.          ny *= upd->pheight;
  5612.       }
  5613.  
  5614.       noutbuf = upd->nbytes + (upd->nbytes + 127) / 128;
  5615.  
  5616.       if(ny > noutbuf) noutbuf = ny;
  5617.       noutbuf += 16;
  5618.  
  5619.       if((0 < noutbuf) && (noutbuf <= INT_MAX)) {
  5620.          upd->noutbuf      = noutbuf;
  5621.          upd->writer       = upd_wrtrtl;
  5622.          error             = 1;
  5623.       } else {
  5624.          error = -1;
  5625. #if      UPD_MESSAGES & UPD_M_WARNING
  5626.             fprintf(stderr,
  5627.               "PCL-Open: %ld is unreasonable size of Outputbuffer\n",
  5628.               (long) noutbuf);
  5629. #endif
  5630.       }
  5631.    }
  5632.  
  5633.    return error;
  5634. }
  5635.  
  5636. /* ------------------------------------------------------------------- */
  5637. /* upd_wrtrtl: Write a pass                                            */
  5638. /* ------------------------------------------------------------------- */
  5639.  
  5640. private int
  5641. upd_wrtrtl(upd_p upd, FILE *out)
  5642. {
  5643.    const updscan_p scan = upd->scnbuf[upd->yscan & upd->scnmsk];
  5644.  
  5645.    int  x,xend,icomp,ioutbuf;
  5646.    byte *data;
  5647.  
  5648. /** Determine Width of this scan */
  5649.  
  5650.    xend   = -1;
  5651.    for(icomp = 0; icomp < upd->ncomp; ++icomp) {
  5652.  
  5653.       data = scan[icomp].bytes;
  5654.  
  5655.       for(x = upd->nbytes-1; 0 <= x; --x) if(data[x]) break;
  5656.       if(x > xend) xend  = x;
  5657.    }
  5658.  
  5659.    if(0 <= xend) { /* Some data to write */
  5660.  
  5661.       ioutbuf = 0;
  5662.       xend   += 1;
  5663. /*
  5664.  *    Adjust the Printers Y-Position
  5665.  */
  5666.       if(upd->yscan != upd->yprinter) { /* Adjust Y-Position */
  5667.          if(1 < upd->strings[S_YMOVE].size) {
  5668.             sprintf((char *)upd->outbuf+ioutbuf,
  5669.                (char *) upd->strings[S_YMOVE].data,upd->yscan - upd->yprinter);
  5670.             ioutbuf += strlen((char *)upd->outbuf+ioutbuf);
  5671.          } else {
  5672.             while(upd->yscan > upd->yprinter) {
  5673.                for(icomp = 0; icomp < upd->ncomp; ++icomp) {
  5674.                   sprintf((char *)upd->outbuf+ioutbuf,
  5675.                      (char *) upd->string_a[SA_WRITECOMP].data[icomp].data,0);
  5676.                   ioutbuf += strlen((char *)upd->outbuf+ioutbuf);
  5677.                }
  5678.                fwrite(upd->outbuf,1,ioutbuf,out);
  5679.                ioutbuf = 0;
  5680.                upd->yprinter += 1;
  5681.             }
  5682.          }
  5683.          upd->yprinter = upd->yscan;
  5684.          fwrite(upd->outbuf,1,ioutbuf,out);
  5685.          ioutbuf = 0;
  5686.       }                                 /* Adjust Y-Position */
  5687. /*
  5688.  * Now write the all! components
  5689.  */
  5690.       for(icomp = 0; icomp < upd->ncomp; ++icomp) { /* Component-Print */
  5691.          data = scan[icomp].bytes;
  5692.          for(x = 0; x <= xend; ++x) if(data[x]) break;
  5693.          if(x <= xend) {
  5694.             ioutbuf = upd_rle(upd->outbuf,scan[icomp].bytes,xend);
  5695.             fprintf(out,
  5696.                (char *)upd->string_a[SA_WRITECOMP].data[icomp].data,ioutbuf);
  5697.             fwrite(upd->outbuf,1,ioutbuf,out);
  5698.          } else {
  5699.             fprintf(out,
  5700.                (char *)upd->string_a[SA_WRITECOMP].data[icomp].data,0);
  5701.          }
  5702.       }
  5703.  
  5704.       upd->yprinter += 1;
  5705.  
  5706.    }                    /* Some data to write */
  5707.  
  5708. /** Advance scan by one */
  5709.  
  5710.    upd->yscan += 1;
  5711.  
  5712.    return 0;
  5713. }
  5714.  
  5715. /* ------------------------------------------------------------------- */
  5716. /* upd_open_wrtcanon: Basic Canon Extended Mode Writer (hr)            */
  5717. /* ------------------------------------------------------------------- */
  5718.  
  5719. private int
  5720. upd_open_wrtcanon(upd_device *udev)
  5721. {
  5722.   const upd_p upd = udev->upd;
  5723.   int error = 0;
  5724.  
  5725.   /* max length of one printer line */
  5726.   upd->noutbuf = upd->nbytes + (upd->nbytes + 127) / 128;
  5727.   upd->writer  = upd_wrtcanon;
  5728.   error        = 1;
  5729.  
  5730.   return error;
  5731. }
  5732.  
  5733. /* ------------------------------------------------------------------- */
  5734. /* upd_wrtcanon: Write a pass (hr)                                     */
  5735. /* ------------------------------------------------------------------- */
  5736.  
  5737. #define LOW(b)     ((b)&0xFF)
  5738. #define HIGH(b)    ((b)>>8)
  5739. #define ESC 0x1B
  5740. #define CR  0x0D
  5741.  
  5742. private int
  5743. upd_wrtcanon(upd_p upd, FILE *out)
  5744. {
  5745.   const updscan_p scan = upd->scnbuf[upd->yscan & upd->scnmsk];
  5746.  
  5747.   int x, xend, icomp, ioutbuf, step, ioutbuf1;
  5748.   byte *data;
  5749.  
  5750.  
  5751.   /* Check length of the printable date */
  5752.   xend = -1;
  5753.   for(icomp = 0; icomp < upd->ncomp; ++icomp) {
  5754.     data = scan[icomp].bytes;
  5755.  
  5756.     for(x = upd->nbytes-1; 0 <= x; --x) if(data[x]) break;
  5757.  
  5758.     if(x > xend) xend  = x;
  5759.   }
  5760.  
  5761.   /* If some date to print */
  5762.   if(0 <= xend) { /* Some data to write */
  5763.     ioutbuf = 0;
  5764.     xend   += 1;
  5765.  
  5766.     /* Perform vertical tab */
  5767.     if(upd->yscan != upd->yprinter) {
  5768.       step = upd->yscan - upd->yprinter;
  5769.  
  5770.       fputc(ESC,        out);
  5771.       fputc('(',        out);
  5772.       fputc('e',        out);
  5773.       fputc(2,          out);
  5774.       fputc(0,          out);
  5775.       fputc(HIGH(step), out);
  5776.       fputc(LOW(step),  out);
  5777.  
  5778.       upd->yprinter = upd->yscan;
  5779.     }
  5780.  
  5781.     for(icomp = 0; icomp < upd->ncomp; ++icomp) {
  5782.  
  5783.       /* Are there date to print for the selected color component */
  5784.       data = scan[icomp].bytes;
  5785.       for(x = 0; x <= xend; ++x) if(data[x]) break;
  5786.  
  5787.       /* Compressing of the scan line */
  5788.       if(x <= xend) {
  5789.     ioutbuf = upd_rle(upd->outbuf, scan[icomp].bytes, xend);
  5790.       } else {
  5791.     ioutbuf = 0;
  5792.       }
  5793.  
  5794.       ioutbuf1 = ioutbuf + 1;
  5795.  
  5796.       /* prints the scan line */
  5797.       fputc(ESC,            out);
  5798.       fputc('(',            out);
  5799.       fputc('A',            out);
  5800.       fputc(LOW(ioutbuf1),  out);
  5801.       fputc(HIGH(ioutbuf1), out);
  5802.       fputc("YMCK"[icomp],  out);
  5803.  
  5804.       fwrite(upd->outbuf, 1, ioutbuf, out);
  5805.  
  5806.       fputc(CR,             out);
  5807.     }
  5808.  
  5809.     /* Printer advances one raster line */
  5810.     fputc(ESC,        out);
  5811.     fputc('(',        out);
  5812.     fputc('e',        out);
  5813.     fputc(2,          out);
  5814.     fputc(0,          out);
  5815.     fputc(HIGH(1),    out);
  5816.     fputc(LOW(1),     out);
  5817.  
  5818.     upd->yprinter += 1;
  5819.  
  5820.   }
  5821.  
  5822.   /* Advance scan by one */
  5823.   upd->yscan += 1;
  5824.  
  5825.   return 0;
  5826. }
  5827.  
  5828. /* ------------------------------------------------------------------- */
  5829. /* All the Pixel-Get Routines                                          */
  5830. /* ------------------------------------------------------------------- */
  5831.  
  5832. /* That bunch of Pixel-Get Routines */
  5833.  
  5834. private upd_proc_pxlget(upd_pxlgetnix); /* A Dummy */
  5835.  
  5836. private upd_proc_pxlget(upd_pxlget1f1); /* 1 Bit Forward */
  5837. private upd_proc_pxlget(upd_pxlget1f2);
  5838. private upd_proc_pxlget(upd_pxlget1f3);
  5839. private upd_proc_pxlget(upd_pxlget1f4);
  5840. private upd_proc_pxlget(upd_pxlget1f5);
  5841. private upd_proc_pxlget(upd_pxlget1f6);
  5842. private upd_proc_pxlget(upd_pxlget1f7);
  5843. private upd_proc_pxlget(upd_pxlget1f8);
  5844.  
  5845. private upd_proc_pxlget(upd_pxlget1r1); /* 1 Bit Reverse */
  5846. private upd_proc_pxlget(upd_pxlget1r2);
  5847. private upd_proc_pxlget(upd_pxlget1r3);
  5848. private upd_proc_pxlget(upd_pxlget1r4);
  5849. private upd_proc_pxlget(upd_pxlget1r5);
  5850. private upd_proc_pxlget(upd_pxlget1r6);
  5851. private upd_proc_pxlget(upd_pxlget1r7);
  5852. private upd_proc_pxlget(upd_pxlget1r8);
  5853.  
  5854. private upd_proc_pxlget(upd_pxlget2f1); /* 2 Bit Forward */
  5855. private upd_proc_pxlget(upd_pxlget2f2);
  5856. private upd_proc_pxlget(upd_pxlget2f3);
  5857. private upd_proc_pxlget(upd_pxlget2f4);
  5858.  
  5859. private upd_proc_pxlget(upd_pxlget2r1); /* 2 Bit Reverse */
  5860. private upd_proc_pxlget(upd_pxlget2r2);
  5861. private upd_proc_pxlget(upd_pxlget2r3);
  5862. private upd_proc_pxlget(upd_pxlget2r4);
  5863.  
  5864. private upd_proc_pxlget(upd_pxlget4f1); /* 4 Bit Forward */
  5865. private upd_proc_pxlget(upd_pxlget4f2);
  5866.  
  5867. private upd_proc_pxlget(upd_pxlget4r1); /* 4 Bit Reverse */
  5868. private upd_proc_pxlget(upd_pxlget4r2);
  5869.  
  5870. private upd_proc_pxlget(upd_pxlget8f);  /* 8 Bit Forward */
  5871. private upd_proc_pxlget(upd_pxlget8r);  /* 8 Bit Reverse */
  5872.  
  5873. private upd_proc_pxlget(upd_pxlget16f); /* 16 Bit Forward */
  5874. private upd_proc_pxlget(upd_pxlget16r); /* 16Bit Reverse */
  5875.  
  5876. private upd_proc_pxlget(upd_pxlget24f); /* 24 Bit Forward */
  5877. private upd_proc_pxlget(upd_pxlget24r); /* 24 Bit Reverse */
  5878.  
  5879. private upd_proc_pxlget(upd_pxlget32f); /* 32 Bit Forward */
  5880. private upd_proc_pxlget(upd_pxlget32r); /* 32 Bit Reverse */
  5881.  
  5882. /* Initialize Forward-Run */
  5883.  
  5884. private uint32
  5885. upd_pxlfwd(upd_p upd)
  5886. {
  5887.    if(!(upd->pxlptr = upd->gsscan)) {
  5888.  
  5889.       upd->pxlget = upd_pxlgetnix;
  5890.  
  5891.    } else {
  5892.       switch(upd->int_a[IA_COLOR_INFO].data[1]) {
  5893.          case  1: upd->pxlget = upd_pxlget1f1; break;
  5894.          case  2: upd->pxlget = upd_pxlget2f1; break;
  5895.          case  4: upd->pxlget = upd_pxlget4f1; break;
  5896.          case  8: upd->pxlget = upd_pxlget8f;  break;
  5897.          case 16: upd->pxlget = upd_pxlget16f; break;
  5898.          case 24: upd->pxlget = upd_pxlget24f; break;
  5899.          case 32: upd->pxlget = upd_pxlget32f; break;
  5900.          default:
  5901. #if UPD_MESSAGES & UPD_M_ERROR
  5902.            fprintf(stderr,"upd_pxlfwd: unsupported depth (%d)\n",
  5903.               upd->int_a[IA_COLOR_INFO].data[1]);
  5904. #endif
  5905.            upd->pxlget = upd_pxlgetnix;
  5906.            break;
  5907.       }
  5908.    }
  5909.    return (uint32) 0;
  5910. }
  5911.  
  5912. /* 1 Bit Forward */
  5913.  
  5914. private uint32
  5915. upd_pxlget1f1(upd_p upd)
  5916. {
  5917.    upd->pxlget = upd_pxlget1f2;
  5918.    return *upd->pxlptr   & 0x80 ? (uint32) 1 : (uint32) 0;
  5919. }
  5920.  
  5921. private uint32
  5922. upd_pxlget1f2(upd_p upd)
  5923. {
  5924.    upd->pxlget = upd_pxlget1f3;
  5925.    return *upd->pxlptr   & 0x40 ? (uint32) 1 : (uint32) 0;
  5926. }
  5927.  
  5928. private uint32
  5929. upd_pxlget1f3(upd_p upd)
  5930. {
  5931.    upd->pxlget = upd_pxlget1f4;
  5932.    return *upd->pxlptr   & 0x20 ? (uint32) 1 : (uint32) 0;
  5933. }
  5934.  
  5935. private uint32
  5936. upd_pxlget1f4(upd_p upd)
  5937. {
  5938.    upd->pxlget = upd_pxlget1f5;
  5939.    return *upd->pxlptr   & 0x10 ? (uint32) 1 : (uint32) 0;
  5940. }
  5941.  
  5942. private uint32
  5943. upd_pxlget1f5(upd_p upd)
  5944. {
  5945.    upd->pxlget = upd_pxlget1f6;
  5946.    return *upd->pxlptr   & 0x08 ? (uint32) 1 : (uint32) 0;
  5947. }
  5948.  
  5949. private uint32
  5950. upd_pxlget1f6(upd_p upd)
  5951. {
  5952.    upd->pxlget = upd_pxlget1f7;
  5953.    return *upd->pxlptr   & 0x04 ? (uint32) 1 : (uint32) 0;
  5954. }
  5955.  
  5956. private uint32
  5957. upd_pxlget1f7(upd_p upd)
  5958. {
  5959.    upd->pxlget = upd_pxlget1f8;
  5960.    return *upd->pxlptr   & 0x02 ? (uint32) 1 : (uint32) 0;
  5961. }
  5962.  
  5963. private uint32
  5964. upd_pxlget1f8(upd_p upd)
  5965. {
  5966.    upd->pxlget = upd_pxlget1f1;
  5967.    return *upd->pxlptr++ & 0x01 ? (uint32) 1 : (uint32) 0;
  5968. }
  5969.  
  5970. /* 2 Bit Forward */
  5971.  
  5972. private uint32
  5973. upd_pxlget2f1(upd_p upd)
  5974. {
  5975.    upd->pxlget = upd_pxlget2f2;
  5976.    return ((uint32) (*upd->pxlptr  ) & (uint32) 0xC0) >> 6;
  5977. }
  5978.  
  5979. private uint32
  5980. upd_pxlget2f2(upd_p upd)
  5981. {
  5982.    upd->pxlget = upd_pxlget2f3;
  5983.    return ((uint32) (*upd->pxlptr  ) & (uint32) 0x30) >> 4;
  5984. }
  5985.  
  5986. private uint32
  5987. upd_pxlget2f3(upd_p upd)
  5988. {
  5989.    upd->pxlget = upd_pxlget2f4;
  5990.    return ((uint32) (*upd->pxlptr  ) & (uint32) 0x0C) >> 2;
  5991. }
  5992.  
  5993. private uint32
  5994. upd_pxlget2f4(upd_p upd)
  5995. {
  5996.    upd->pxlget = upd_pxlget2f1;
  5997.    return  (uint32) (*upd->pxlptr++) & (uint32) 0x03;
  5998. }
  5999.  
  6000.  
  6001. /* 4 Bit Forward */
  6002. private uint32
  6003. upd_pxlget4f1(upd_p upd)
  6004. {
  6005.    upd->pxlget = upd_pxlget4f2;
  6006.    return ((uint32) (*upd->pxlptr  ) & (uint32) 0xF0) >> 4;
  6007. }
  6008.  
  6009. private uint32
  6010. upd_pxlget4f2(upd_p upd)
  6011. {
  6012.    upd->pxlget = upd_pxlget4f1;
  6013.    return  (uint32) (*upd->pxlptr++) & (uint32) 0x0F;
  6014. }
  6015.  
  6016.  
  6017. /* 8 Bit Forward */
  6018. private uint32
  6019. upd_pxlget8f(upd_p upd)
  6020. {
  6021.    return (uint32) (*upd->pxlptr++);
  6022. }
  6023.  
  6024.  
  6025. /* 16 Bit Forward */
  6026. private uint32
  6027. upd_pxlget16f(upd_p upd)
  6028. {
  6029.    uint32 ci  = (uint32) (*upd->pxlptr++) << 8;
  6030.                   ci |=                   *upd->pxlptr++;
  6031.    return         ci;
  6032. }
  6033.  
  6034. /* 24 Bit Forward */
  6035. private uint32
  6036. upd_pxlget24f(upd_p upd)
  6037. {
  6038.    uint32 ci  = (uint32) (*upd->pxlptr++) << 16;
  6039.           ci |= (uint32) (*upd->pxlptr++) <<  8;
  6040.           ci |=           *upd->pxlptr++;
  6041.    return ci;
  6042. }
  6043.  
  6044. /* 32 Bit Forward */
  6045. private uint32
  6046. upd_pxlget32f(upd_p upd)
  6047. {
  6048.    uint32 ci  = (uint32) (*upd->pxlptr++) << 24;
  6049.                   ci |= (uint32) (*upd->pxlptr++) << 16;
  6050.                   ci |= (uint32) (*upd->pxlptr++) <<  8;
  6051.                   ci |=                   *upd->pxlptr++;
  6052.    return         ci;
  6053. }
  6054.  
  6055.  
  6056. /* Dummy-Routine */
  6057.  
  6058. private uint32
  6059. upd_pxlgetnix(upd_p upd)
  6060. {
  6061.    return (uint32) 0;
  6062. }
  6063.  
  6064. /* Initialize Reverse-Run */
  6065.  
  6066. private uint32
  6067. upd_pxlrev(upd_p upd)
  6068. {
  6069.    const uint width = upd->pwidth < upd->gswidth ? upd->pwidth : upd->gswidth;
  6070.  
  6071.    if(!(upd->pxlptr = upd->gsscan)) {
  6072.  
  6073.       upd->pxlget = upd_pxlgetnix;
  6074.  
  6075.    } else {
  6076.       uint32 ofs = (uint32) upd->int_a[IA_COLOR_INFO].data[1] * (width-1);
  6077.  
  6078.       upd->pxlptr += ofs>>3;
  6079.  
  6080.       ofs &= 7;
  6081.  
  6082.       switch(upd->int_a[IA_COLOR_INFO].data[1]) {
  6083.          case  1: switch(ofs) {
  6084.                case 0:  upd->pxlget = upd_pxlget1r1; break;
  6085.                case 1:  upd->pxlget = upd_pxlget1r2; break;
  6086.                case 2:  upd->pxlget = upd_pxlget1r3; break;
  6087.                case 3:  upd->pxlget = upd_pxlget1r4; break;
  6088.                case 4:  upd->pxlget = upd_pxlget1r5; break;
  6089.                case 5:  upd->pxlget = upd_pxlget1r6; break;
  6090.                case 6:  upd->pxlget = upd_pxlget1r7; break;
  6091.                case 7:  upd->pxlget = upd_pxlget1r8; break;
  6092.             } break;
  6093.          case  2: switch(ofs) {
  6094.                case 0:  upd->pxlget = upd_pxlget2r1; break;
  6095.                case 2:  upd->pxlget = upd_pxlget2r2; break;
  6096.                case 4:  upd->pxlget = upd_pxlget2r3; break;
  6097.                case 6:  upd->pxlget = upd_pxlget2r4; break;
  6098.             } break;
  6099.          case  4: switch(ofs) {
  6100.                case 0:  upd->pxlget = upd_pxlget4r1; break;
  6101.                case 4:  upd->pxlget = upd_pxlget4r2; break;
  6102.             } break;
  6103.          case  8: upd->pxlget = upd_pxlget8r;  break;
  6104.          case 16:
  6105.             upd->pxlget  = upd_pxlget16r;
  6106.             upd->pxlptr += 1;
  6107.             break;
  6108.          case 24:
  6109.             upd->pxlget = upd_pxlget24r;
  6110.             upd->pxlptr += 2;
  6111.             break;
  6112.          case 32:
  6113.             upd->pxlget = upd_pxlget32r;
  6114.             upd->pxlptr += 3;
  6115.             break;
  6116.          default:
  6117. #if UPD_MESSAGES & UPD_M_ERROR
  6118.            fprintf(stderr,"upd_pxlrev: unsupported depth (%d)\n",
  6119.               upd->int_a[IA_COLOR_INFO].data[1]);
  6120. #endif
  6121.            upd->pxlget = upd_pxlgetnix;
  6122.            break;
  6123.       }
  6124.    }
  6125.    return (uint32) 0;
  6126. }
  6127.  
  6128. /* 1 Bit Reverse */
  6129.  
  6130. private uint32
  6131. upd_pxlget1r1(upd_p upd)
  6132. {
  6133.    upd->pxlget = upd_pxlget1r8;
  6134.    return *upd->pxlptr-- & 0x80 ? (uint32) 1 : (uint32) 0;
  6135. }
  6136.  
  6137. private uint32
  6138. upd_pxlget1r2(upd_p upd)
  6139. {
  6140.    upd->pxlget = upd_pxlget1r1;
  6141.    return *upd->pxlptr   & 0x40 ? (uint32) 1 : (uint32) 0;
  6142. }
  6143.  
  6144. private uint32
  6145. upd_pxlget1r3(upd_p upd)
  6146. {
  6147.    upd->pxlget = upd_pxlget1r2;
  6148.    return *upd->pxlptr   & 0x20 ? (uint32) 1 : (uint32) 0;
  6149. }
  6150.  
  6151. private uint32
  6152. upd_pxlget1r4(upd_p upd)
  6153. {
  6154.    upd->pxlget = upd_pxlget1r3;
  6155.    return *upd->pxlptr   & 0x10 ? (uint32) 1 : (uint32) 0;
  6156. }
  6157.  
  6158. private uint32
  6159. upd_pxlget1r5(upd_p upd)
  6160. {
  6161.    upd->pxlget = upd_pxlget1r4;
  6162.    return *upd->pxlptr   & 0x08 ? (uint32) 1 : (uint32) 0;
  6163. }
  6164.  
  6165. private uint32
  6166. upd_pxlget1r6(upd_p upd)
  6167. {
  6168.    upd->pxlget = upd_pxlget1r5;
  6169.    return *upd->pxlptr   & 0x04 ? (uint32) 1 : (uint32) 0;
  6170. }
  6171.  
  6172. private uint32
  6173. upd_pxlget1r7(upd_p upd)
  6174. {
  6175.    upd->pxlget = upd_pxlget1r6;
  6176.    return *upd->pxlptr   & 0x02 ? (uint32) 1 : (uint32) 0;
  6177. }
  6178.  
  6179. private uint32
  6180. upd_pxlget1r8(upd_p upd)
  6181. {
  6182.    upd->pxlget = upd_pxlget1r7;
  6183.    return *upd->pxlptr   & 0x01 ? (uint32) 1 : (uint32) 0;
  6184. }
  6185.  
  6186. /* 2 Bit Reverse */
  6187.  
  6188. private uint32
  6189. upd_pxlget2r1(upd_p upd)
  6190. {
  6191.    upd->pxlget = upd_pxlget2r4;
  6192.    return ((uint32) (*upd->pxlptr--) & (uint32) 0xC0) >> 6;
  6193. }
  6194.  
  6195. private uint32
  6196. upd_pxlget2r2(upd_p upd)
  6197. {
  6198.    upd->pxlget = upd_pxlget2r1;
  6199.    return ((uint32) (*upd->pxlptr  ) & (uint32) 0x30) >> 4;
  6200. }
  6201.  
  6202. private uint32
  6203. upd_pxlget2r3(upd_p upd)
  6204. {
  6205.    upd->pxlget = upd_pxlget2r2;
  6206.    return ((uint32) (*upd->pxlptr  ) & (uint32) 0x0C) >> 2;
  6207. }
  6208.  
  6209. private uint32
  6210. upd_pxlget2r4(upd_p upd)
  6211. {
  6212.    upd->pxlget = upd_pxlget2r3;
  6213.    return  (uint32) (*upd->pxlptr  ) & (uint32) 0x03;
  6214. }
  6215.  
  6216. /* 4 Bit Reverse */
  6217.  
  6218. private uint32
  6219. upd_pxlget4r1(upd_p upd)
  6220. {
  6221.    upd->pxlget = upd_pxlget4r2;
  6222.    return ((uint32) (*upd->pxlptr--) & (uint32) 0xF0) >> 4;
  6223. }
  6224.  
  6225. private uint32
  6226. upd_pxlget4r2(upd_p upd)
  6227. {
  6228.    upd->pxlget = upd_pxlget4r1;
  6229.    return  (uint32) (*upd->pxlptr  ) & (uint32) 0x0F;
  6230. }
  6231.  
  6232.  
  6233. /* 8 Bit Reverse */
  6234. private uint32
  6235. upd_pxlget8r(upd_p upd)
  6236. {
  6237.    return (uint32) (*upd->pxlptr--);
  6238. }
  6239.  
  6240.  
  6241. /* 16 Bit Reverse */
  6242. private uint32
  6243. upd_pxlget16r(upd_p upd)
  6244. {
  6245.    uint32 ci  =                   *upd->pxlptr--;
  6246.                   ci |= (uint32) (*upd->pxlptr--) << 8;
  6247.    return         ci;
  6248. }
  6249.  
  6250. /* 24 Bit Reverse */
  6251. private uint32
  6252. upd_pxlget24r(upd_p upd)
  6253. {
  6254.    uint32 ci  =           *upd->pxlptr--;
  6255.           ci |= (uint32) (*upd->pxlptr--) <<  8;
  6256.           ci |= (uint32) (*upd->pxlptr--) << 16;
  6257.    return ci;
  6258. }
  6259.  
  6260. /* 32 Bit Reverse */
  6261. private uint32
  6262. upd_pxlget32r(upd_p upd)
  6263. {
  6264.    uint32 ci  =                   *upd->pxlptr--;
  6265.                   ci |= (uint32) (*upd->pxlptr--) <<  8;
  6266.                   ci |= (uint32) (*upd->pxlptr--) << 16;
  6267.                   ci |= (uint32) (*upd->pxlptr--) << 24;
  6268.    return         ci;
  6269. }
  6270.