xref: /plan9-contrib/sys/src/cmd/gs/src/gdevstc.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1 /* Copyright (C) 1995, 1996 Aladdin Enterprises.  All rights reserved.
2   This file is part of Aladdin Ghostscript.
3 
4   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
5   or distributor accepts any responsibility for the consequences of using it,
6   or for whether it serves any particular purpose or works at all, unless he
7   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
8   License (the "License") for full details.
9 
10   Every copy of Aladdin Ghostscript must include a copy of the License,
11   normally in a plain ASCII text file named PUBLIC.  The License grants you
12   the right to copy, modify and redistribute Aladdin Ghostscript, but only
13   under certain conditions described in the License.  Among other things, the
14   License requires that the copyright notice and this notice be preserved on
15   all copies.
16 */
17 
18 /*$Id: gdevstc.c,v 1.1 2000/03/09 08:40:41 lpd Exp $*/
19 /* Epson Stylus-Color Printer-Driver */
20 
21 /***
22  *** This file was "copied" from gdevcdj.c (ghostscript-3.12), which was
23  *** contributed by:
24  ***    George Cameron      - g.cameron@biomed.abdn.ac.ukis
25  ***    Koert Zeilstra      - koert@zen.cais.com
26  ***    Eckhard Rueggeberg  - eckhard@ts.go.dlr.de
27  ***
28  *** Some of the ESC/P2-code was drawn from gdevescp.c, contributed by
29  ***    Richard Brown       - rab@eos.ncsu.edu
30  ***
31  *** The POSIX-Interrupt-Code is from (Compile-Time-Option -DSTC_SIGNAL)
32  ***    Frederic Loyer      - loyer@ensta.fr
33  ***
34  *** And several improvements are based on discussions with
35  ***    Brian Converse      - BCONVERSE@ids.net
36  ***    Bill Davidson       - bdavidson@ra.isisnet.com
37  ***    Gero Guenther       - gero@cs.tu-berlin.de
38  ***    Jason Patterson     - jason@reflections.com.au
39  ***    ? Rueschstroer      - rue@ibe.med.uni-muenchen.de
40  ***    Steven Singer       - S.Singer@ph.surrey.ac.uk
41  ***
42  *** And the remaining little rest, mainly the bugs, were written by me:
43  *** Gunther Hess           - gunther@elmos.de
44  ***
45  *** P.S.: there is some documentation, see devices.doc
46  ***
47  *** Revision-History:
48  *** 16-DEC-1994  1.1  - initial Version (GS-Dithering & Plain-Write)
49      ...
50  *** 30-JAN-1995  1.11 - FS-Improvements, u/sWeave, 1/4/24-Bits
51  ***  5-MAR-1995  1.12 - L. Peter Deutsch - updated put_params routine
52                          (first distributed version with gs3.33)
53  *** 26-APR-1995  1.13 - merged Peters fixes with algorithmic changes:
54                          Changed 24Bit-Mode, added 32Bit-Mode (moves colors)
55                          [Arrgh: much better than 1.12, but patch was lost]
56  ***  5-JUN-1995  1.14 - Added Color-Correction & Transfer-Curves
57                          (Several Beta-Testers, but not distributed)
58      ...
59  *** 24-JUL-1995  1.16 - Made dithering-Algorithms external-functions.
60                          (Mailed for Beta-Distribution)
61  *** 10-AUG-1995  1.17 - Several Bug-Fixes and some new features:
62                          CMYK10-Coding added
63                          Readonly Parameters added
64                           "Algorithms", "BitsPerComponent", "Version"
65                          Parameters Flag0-4, Model, OutputCode
66                          (mailed for distribution)
67  *** 14-SEP-1995  1.18   Fixes Bugs with Borland C (gs3.47)
68  *** 23-SEP-1995  1.19 - reorganized printcode + bug-fixing
69  *** 24-SEP-1995  1.20 - Little Cleanup for the release
70  *** 25-SEP-1995  1.21 - Readonly-Parameters added to put_params.
71  *** 31-Dec-1995  1.22 - Sanitary Engineering on the code
72  *** 16-Jan-1996  1.23 - Added String escp_Release
73  ***  8-May-1996  1.90 - Reintroduced Deltarow & Fixed MEMORY-BUG!
74  ***/
75 
76 #include "gdevstc.h"
77 #ifdef    STC_SIGNAL
78 #  include <signal.h>
79 #endif /* STC_SIGNAL */
80 /***
81  *** Mode-Table - the various algorithms
82  *** (The intention is, that this source can live alone)
83  ***/
84 
85 private stc_proc_dither(stc_gscmyk);   /* resides in this file */
86 private stc_proc_dither(stc_hscmyk);   /* resides in this file */
87 
88 #include <stdlib.h> /* for rand, used in stc_hscmyk */
89 
90 private const stc_dither_t stc_dither[] = {
91   {"gscmyk", stc_gscmyk, DeviceCMYK|STC_BYTE|STC_DIRECT,0,{0.0,1.0}},
92   {"hscmyk", stc_hscmyk,
93   DeviceCMYK|STC_LONG|STC_CMYK10|STC_DIRECT|1*STC_SCAN,1+2*4,
94                                                   {0.0,    1023.0}},
95   STC_MODI
96   { NULL   , NULL      , 0,                  0,{0.0,0.0}}
97 };
98 
99 /***
100  ***  forward-declarations of routines
101  ***/
102 
103 /* Primary Device functions
104  * (I've the idea to rename the driver to stc)
105  */
106 private dev_proc_print_page(stc_print_page);
107 private dev_proc_open_device(stc_open);
108 private dev_proc_close_device(stc_close);
109 private dev_proc_get_params(stc_get_params);
110 private dev_proc_put_params(stc_put_params);
111 
112 /*
113  * Color-Mapping-functions.
114  */
115 
116 /* routines for monochrome monochrome modi */
117 private dev_proc_map_rgb_color(stc_map_gray_color);
118 private dev_proc_map_color_rgb(stc_map_color_gray);
119 
120 /* routines for RGB-Modi */
121 private dev_proc_map_rgb_color(stc_map_rgb_color);
122 private dev_proc_map_color_rgb(stc_map_color_rgb);
123 
124 /* routines for general CMYK-Modi */
125 private dev_proc_map_cmyk_color(stc_map_cmyk_color);
126 private dev_proc_map_color_rgb(stc_map_color_cmyk);
127 
128 /* routines for 10Bit/Component CMYK */
129 private dev_proc_map_cmyk_color(stc_map_cmyk10_color);
130 private dev_proc_map_color_rgb(stc_map_color_cmyk10);
131 
132 /***
133  *** Table of Device-Procedures
134  ***/
135 private gx_device_procs stcolor_procs = {
136         stc_open,
137         gx_default_get_initial_matrix,
138         gx_default_sync_output,
139         gdev_prn_output_page,
140         stc_close,
141         NULL,
142         stc_map_color_cmyk,
143         NULL,   /* fill_rectangle */
144         NULL,   /* tile_rectangle */
145         NULL,   /* copy_mono */
146         NULL,   /* copy_color */
147         NULL,   /* draw_line */
148         gx_default_get_bits,
149         stc_get_params,
150         stc_put_params,
151         stc_map_cmyk_color
152 };
153 
154 /***
155  *** A local dummy-array for extvals
156  ***/
157 
158 private float defext[] = { 0.0, 1.0 };
159 
160 /***
161  *** Main device-control structure
162  ***/
163 stcolor_device far_data gs_stcolor_device = {
164    prn_device_body(stcolor_device, stcolor_procs, "stcolor",
165       DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
166       X_DPI,  Y_DPI,
167       STC_L_MARGIN,STC_B_MARGIN,STC_R_MARGIN,STC_T_MARGIN,
168       4,  4, 1, 1, 2, 2,            /* default: cmyk-direct */
169       stc_print_page),
170      {STCNWEAVE,                    /* stcflags:  noWeave/bidirectional */
171       1,                            /* stcbits:   matches the default */
172       stc_dither,                   /* stcdither: first algorithm */
173       NULL,                         /* stcam:     NULL -> not used */
174       { NULL, NULL, NULL, NULL},    /* extcode:   none defined yet */
175       {    0,    0,    0,    0},    /* sizcode:   0, since no extcode yet */
176       { NULL, NULL, NULL, NULL},    /* stccode:   computed by put_params */
177       {defext,defext,defext,defext},/* extvals:   default */
178       {    2,    2,    2,    2},    /* sizvals:   default countof(defext) */
179       { NULL, NULL, NULL, NULL},    /* stcvals:   computed by put_params */
180       {    0,    0,    0},          /* white-run */
181       {    0,    0,    0},          /* white-end */
182       {NULL,0,false},               /* algorithm-table */
183       {NULL,0,false},               /* initialization-String (BOP) */
184       {NULL,0,false},               /* release-String (EOP) */
185       0,0,0,0,                      /* New escp-stuff */
186       1}                            /* itemsize used by algorithm */
187 };
188 /***
189  *** Test for white scan-lines
190  ***/
191 private bool stc_iswhite(P3(stcolor_device *, int, byte *));
192 
193 /***
194  *** Functions used for conversion inside the print-loop
195  ***/
196 #define stc_proc_iconvert(Name) \
197 byte * Name(P4(stcolor_device *sd,byte *ext_data,int prt_pixels,byte *alg_line))
198 
199 private stc_proc_iconvert(stc_any_depth);    /* general input-conversion */
200 private stc_proc_iconvert(stc_rgb24_long);   /* 24Bit RGB  -> long's */
201 
202 private stc_proc_iconvert(stc_cmyk32_long);  /* 32Bit CMYK -> long's */
203 private stc_proc_iconvert(stc_any_direct);   /* use ext_data as input */
204 
205 private stc_proc_iconvert(stc_cmyk10_byte);  /* CMYK10->vals-> any type */
206 private stc_proc_iconvert(stc_cmyk10_long);  /* CMYK10->vals-> any type */
207 private stc_proc_iconvert(stc_cmyk10_float); /* CMYK10->vals-> any type */
208 private stc_proc_iconvert(stc_cmyk10_dbyte); /* CMYK10 direct bytes */
209 private stc_proc_iconvert(stc_cmyk10_dlong); /* CMYK10 direct longs */
210 
211 /***
212  *** Print-functions
213  ***/
214 private void stc_print_weave(P2(stcolor_device *sd,FILE *prn_stream));
215 private void stc_print_bands(P2(stcolor_device *sd,FILE *prn_stream));
216 private void stc_print_delta(P2(stcolor_device *sd,FILE *prn_stream));
217 private int  stc_print_setup(P1(stcolor_device *sd));
218 
219 /***
220  *** compute the ESC/P2 specific values
221  ***/
222 
223 private int
224 stc_print_setup(stcolor_device *sd)
225 {
226 
227 /*
228  * Compute the resolution-parameters
229  */
230    sd->stc.escp_u = 3600.0 / sd->y_pixels_per_inch; /* y-units */
231    sd->stc.escp_h = 3600.0 / sd->x_pixels_per_inch; /* x-units */
232    sd->stc.escp_v = sd->stc.flags & (STCUWEAVE | STCNWEAVE) ?
233                     sd->stc.escp_u : 40;
234 /*
235  * Initialize color
236  */
237    sd->stc.escp_c = 0; /* preselect-black */
238 
239 /*
240  * Band-Width
241  */
242    if((sd->stc.flags & STCBAND) == 0) {
243       if(sd->stc.escp_v != sd->stc.escp_u)            sd->stc.escp_m = 15;
244       else if(STCSTCII == (sd->stc.flags & STCMODEL)) sd->stc.escp_m =  1;
245       else if(  sd->stc.flags & STCUWEAVE)            sd->stc.escp_m =  1;
246       else if((sd->stc.escp_v == sd->stc.escp_u) &&
247               (sd->stc.escp_u == 5))                  sd->stc.escp_m =  1;
248       else                                            sd->stc.escp_m =  1;
249    }
250 
251 /*
252  * Page-Dimensions
253  */
254    if((sd->stc.flags & STCWIDTH ) == 0)
255        sd->stc.escp_width = sd->width -
256            (dev_l_margin(sd)+dev_r_margin(sd))*sd->x_pixels_per_inch;
257 
258    if((sd->stc.flags & STCHEIGHT) == 0)
259        sd->stc.escp_height = sd->height;
260 
261    if((sd->stc.flags & STCTOP) == 0)
262        sd->stc.escp_top = dev_t_margin(sd)*sd->y_pixels_per_inch;
263 
264    if((sd->stc.flags & STCBOTTOM) == 0)
265       sd->stc.escp_bottom = sd->height - dev_b_margin(sd)*sd->y_pixels_per_inch;
266 
267    if((sd->stc.flags & STCINIT) == 0) { /* No Initialization-String defined */
268       int need  = 8  /* Reset, Graphics-Mode 1 */
269                 + 6  /* MicroWeave */
270                 + 6  /* Select Units */
271                 + 7  /* Set Page-Length */
272                 + 9  /* Set Margins */
273                 + 3; /* Select Unidirectionality */
274       byte *bp  = (byte *) (sd->stc.escp_init.data);
275 
276       if(need != sd->stc.escp_init.size) {  /* Reallocate */
277 
278          if(NULL != (bp = gs_malloc(need,1,"stcolor/init"))) { /* Replace */
279             if(0 != sd->stc.escp_init.size)
280                gs_free((byte *)sd->stc.escp_init.data,sd->stc.escp_init.size,1,
281                        "stcolor/init");
282             sd->stc.escp_init.data       = bp;
283             sd->stc.escp_init.size       = need;
284             sd->stc.escp_init.persistent = false;
285          }  else {                                             /* Replace */
286              return_error(gs_error_VMerror);
287          }
288       }
289 
290       if(need != 39) return_error(gs_error_unregistered);
291 
292       memcpy(bp,
293 /*                       1 1 11  1 11  1   1 1  2 22 2  2 22  2 22 3  3 3333  3 33*/
294 /* 0 1  2 34  5  6 7  8 90 1 23  4 56  7   8 9  0 12 3  4 56  7 89 0  1 2345  6 78*/
295 "\033@\033(G\001\0\1\033(i\1\0w\033(U\001\000u\033(C\2\000hh\033(c\4\000ttbb\033U",
296              need);
297 
298 
299       if((sd->stc.flags & STCUWEAVE) != 0) bp[13] = '\1';
300       else                                 bp[13] = '\0';
301 
302       bp[19] =  sd->stc.escp_u;
303 
304       bp[25] =  sd->stc.escp_height     & 0xff;
305       bp[26] = (sd->stc.escp_height>>8) & 0xff;
306 
307       bp[32] =  sd->stc.escp_top        & 0xff;
308       bp[33] = (sd->stc.escp_top>>8)    & 0xff;
309       bp[34] =  sd->stc.escp_bottom     & 0xff;
310       bp[35] = (sd->stc.escp_bottom>>8) & 0xff;
311 
312       if(sd->stc.flags & STCUNIDIR)        bp[38] = 1;
313       else                                 bp[38] = 0;
314 
315    }                                    /* No Initialization-String defined */
316 
317    if((sd->stc.flags & STCRELEASE) == 0) { /* No Release-String defined */
318       int need  = 3;  /* ESC @ \f */
319       byte *bp  = (byte *) (sd->stc.escp_release.data);
320 
321       if(need != sd->stc.escp_release.size) {  /* Reallocate */
322 
323          if(NULL != (bp = gs_malloc(need,1,"stcolor/release"))) { /* Replace */
324             if(0 != sd->stc.escp_release.size)
325                gs_free((byte *)sd->stc.escp_release.data,sd->stc.escp_release.size,1,
326                        "stcolor/release");
327             sd->stc.escp_release.data       = bp;
328             sd->stc.escp_release.size       = need;
329             sd->stc.escp_release.persistent = false;
330          }  else {                                             /* Replace */
331              return_error(gs_error_VMerror);
332          }
333       }
334 
335       if(need != 3) return_error(gs_error_unregistered);
336 
337       memcpy(bp,"\033@\f",need);
338 
339    }                                    /* No Release-String defined */
340 
341    return 0;
342 }
343 
344 /***
345  *** stc_print_page: here we go to do the nasty work
346  ***/
347 
348 private int
349 stc_print_page(gx_device_printer * pdev, FILE * prn_stream)
350 {
351    stcolor_device *sd    = (stcolor_device *) pdev;
352    long            flags = sd == NULL ? 0 : sd->stc.flags;
353 
354    int  npass;           /* # of print-passes (softweave) */
355 
356    int    ext_size;      /* size of a ghostscript-scanline */
357    byte  *ext_line;      /* dyn: for this scanline */
358 
359    int    alg_size;      /* size of a scanline for the dithering-algorithm */
360    byte  *alg_line;      /* dyn: 1 scanline for the dithering-algorithm */
361    int    buf_size;      /* size of the private-buffer for dither-function */
362    byte  *buf;           /* dyn: the private buffer */
363 
364    int    prt_pixels;    /* Number of pixels printed */
365    byte  *col_line;      /* A Line with a byte per pixel */
366 
367 #define OK4GO        ((flags &   STCOK4GO)              != 0)
368 #define SORRY        ( flags &= ~STCOK4GO)
369 
370    if(0 > (npass = stc_print_setup(sd))) return_error(npass);
371 
372    npass = sd->stc.escp_v / sd->stc.escp_u;
373 
374 /***
375  *** Allocate dynamic memory
376  ***/
377 
378    ext_size   = gdev_prn_raster(sd);
379    ext_line   = gs_malloc(ext_size,1,"stc_print_page/ext_line");
380    if(ext_line == NULL) SORRY;
381 
382    prt_pixels        = sd->stc.escp_width;
383    sd->stc.prt_size  = (prt_pixels+7)/8;
384    prt_pixels        =  sd->stc.prt_size * 8;
385 
386    sd->stc.prt_scans  = sd->height -
387       (dev_t_margin(sd)+dev_b_margin(sd))*sd->y_pixels_per_inch;
388 
389    col_line   = gs_malloc(prt_pixels,1,"stc_print_page/col_line");
390    if(col_line == NULL) SORRY;
391 
392    alg_size  = prt_pixels;
393    alg_size *= sd->color_info.num_components;
394 
395    if((sd->stc.dither->flags & STC_DIRECT) ||
396       ((sd->stc.bits                 == 8) &&
397        (sd->stc.alg_item                     == 1)))  {
398       alg_line = NULL;
399    } else {
400       alg_line = gs_malloc(alg_size,sd->stc.alg_item,"stc_print_page/alg_line");
401       if(alg_line == NULL) SORRY;
402    }
403 
404    buf_size = sd->stc.dither->bufadd
405             + alg_size*(sd->stc.dither->flags/STC_SCAN);
406    if(buf_size > 0) {
407       buf    = gs_malloc(buf_size,sd->stc.alg_item,"stc_print_page/buf");
408       if(buf == NULL) SORRY;
409    } else {
410       buf = NULL;
411    }
412 
413 /*
414  * compute the number of printer-buffers
415  */
416 
417     for(sd->stc.prt_buf   = 16; sd->stc.prt_buf < (sd->stc.escp_m * npass);
418         sd->stc.prt_buf <<= 1);
419     if(sd->color_info.num_components > 1) sd->stc.prt_buf *= 4;
420 
421     sd->stc.prt_width = gs_malloc(sd->stc.prt_buf,sizeof(int),
422                         "stc_print_page/prt_width");
423     if(sd->stc.prt_width == NULL) SORRY;
424 
425     sd->stc.prt_data  = gs_malloc(sd->stc.prt_buf,sizeof(byte *),
426                         "stc_print_page/prt_data");
427 
428     if(sd->stc.prt_data == NULL) {
429        SORRY;
430     } else {
431        int i;
432 
433        for(i = 0; i < sd->stc.prt_buf; ++i) {
434           sd->stc.prt_data[i] = gs_malloc(sd->stc.prt_size,1,
435                                 "stc_print_page/prt");
436           if(sd->stc.prt_data[i] == NULL) SORRY;
437        }
438     }
439 
440     sd->stc.seed_size = (sd->stc.prt_size + 2*sizeof(int) - 1)/sizeof(int);
441     {
442        int i;
443        for(i = 0; i < sd->color_info.num_components; ++i) {
444           if((flags & STCCOMP) == STCDELTA) {
445              sd->stc.seed_row[i] = gs_malloc(sd->stc.seed_size,sizeof(int),
446                                    "stc_print_page/seed_row");
447              if(sd->stc.seed_row[i] == NULL) SORRY;
448              else memset(sd->stc.seed_row[i],0,sd->stc.seed_size*sizeof(int));
449           } else {
450              sd->stc.seed_row[i] = NULL;
451           }
452        }
453        while(i < countof(sd->stc.seed_row)) sd->stc.seed_row[i++] = NULL;
454     }
455 
456     switch(flags & STCCOMP) {
457        case STCPLAIN:
458           sd->stc.escp_size = 64 + sd->stc.prt_size;
459           break;
460        case STCDELTA:
461           sd->stc.escp_size = 64 + 2 * sd->stc.prt_size;
462           break;
463        default:
464           sd->stc.escp_size = 64 +
465                               sd->stc.prt_size + (sd->stc.prt_size + 127)/128;
466           break;
467     }
468 
469     sd->stc.escp_data = gs_malloc(sd->stc.escp_size,1,
470                                   "stc_print_page/escp_data");
471     if(sd->stc.escp_data == NULL) SORRY;
472 
473 /*
474  * If we're still ok, we can print something
475  */
476 
477    if(OK4GO) {
478 
479       int ncolor;
480       int buf_i;
481       stc_proc_iconvert((*iconvert)) = stc_any_depth;
482 
483 /*
484  * initialize col_line
485  */
486       if(sd->color_info.num_components == 3) {
487          memset(col_line,RED|GREEN|BLUE,prt_pixels);
488       } else {
489          memset(col_line,0,             prt_pixels);
490       }
491 
492 /*
493  * select proper conversion for input to algorithm
494  */
495       if(     (sd->stc.dither->flags & STC_DIRECT ) ||
496               ((sd->stc.bits                 == 8) &&
497                (sd->stc.alg_item                     == 1)))
498          iconvert = stc_any_direct;
499       else if((sd->color_info.num_components ==  3) &&
500               (sd->color_info.depth          == 24) &&
501               (sizeof(long)                  == sd->stc.alg_item))
502          iconvert = stc_rgb24_long;
503       else if(sd->stc.flags & STCCMYK10) {
504          if(     ((sd->stc.dither->flags & STC_TYPE) == STC_BYTE) &&
505                  ( sd->stc.dither->minmax[0]         ==    0.0  ))
506             iconvert = stc_cmyk10_dbyte;
507          else if ((sd->stc.dither->flags & STC_TYPE) == STC_BYTE)
508             iconvert = stc_cmyk10_byte;
509          else if(((sd->stc.dither->flags & STC_TYPE) == STC_LONG) &&
510                  ( sd->stc.dither->minmax[0]         ==    0.0  ) &&
511                  ( sd->stc.dither->minmax[1]         <= 1023.0  ))
512             iconvert = stc_cmyk10_dlong;
513          else if( (sd->stc.dither->flags & STC_TYPE) == STC_LONG)
514             iconvert = stc_cmyk10_long;
515          else
516             iconvert = stc_cmyk10_float;
517       }
518       else if((sd->color_info.num_components ==  4) &&
519               (sd->color_info.depth          == 32) &&
520               (sizeof(long)                  == sd->stc.alg_item))
521          iconvert = stc_cmyk32_long;
522 
523 /*
524  * initialize the algorithm
525  */
526 
527       if((*sd->stc.dither->fun)(sd,-prt_pixels,alg_line,buf,col_line) < 0)
528          SORRY;
529 
530 /*
531  * Main-Print-Loop
532  */
533 
534       if(OK4GO) {
535 #ifdef    STC_SIGNAL
536          sigset_t stc_int_mask, stc_int_save, stc_int_pending;
537 
538          sigemptyset(&stc_int_mask);
539          sigaddset(&stc_int_mask,SIGINT);
540          sigprocmask(SIG_BLOCK,&stc_int_mask, &stc_int_save);
541 #endif /* STC_SIGNAL */
542 
543 
544          if(sd->color_info.num_components > 1) ncolor = 4;
545          else                                  ncolor = 1;
546 
547 /*
548  * Decide, wether we Adjust Linefeeds or not. (I hate it here)
549  */
550          if((0   == ((sd->stc.escp_m*sd->stc.escp_u) % 10)) &&
551             (256  > ((sd->stc.escp_m*sd->stc.escp_u) / 10))) sd->stc.escp_lf = sd->stc.escp_m;
552          else                                                sd->stc.escp_lf = 0;
553 
554 /*
555  * prepare run-values, then loop over scans
556  */
557          sd->stc.stc_y      =  0; /* current printer y-Position */
558          sd->stc.buf_y      =  0; /* Top-Position within the buffer */
559          sd->stc.prt_y      =  0; /* physical position of the printer */
560          buf_i              =  0; /* next free line in buffer */
561          sd->stc.flags     &= ~STCPRINT; /* no data yet */
562 
563          while(sd->stc.stc_y < sd->stc.prt_scans) {  /* Until all scans are processed */
564             int need;
565 
566             need = sd->stc.stc_y + npass * sd->stc.escp_m;
567 
568             if(sd->stc.buf_y < need) { /* Nr. 5 (give me input) */
569 
570 /* read as much as the buffer can hold */
571                if(ncolor == 1) need = sd->stc.stc_y +  sd->stc.prt_buf;
572                else            need = sd->stc.stc_y + (sd->stc.prt_buf>>2);
573 
574                for(;sd->stc.buf_y < need;
575                     buf_i = (sd->stc.prt_buf-1) & (buf_i+ncolor),
576                     ++sd->stc.buf_y) {
577 
578                   int color;
579                   byte *ext_data;
580                   byte *alg_data;
581 
582 /* initialize output data 1st -> may take shortcut */
583 
584                   for(color = 0; color < ncolor; ++color) {
585                      memset(sd->stc.prt_data[buf_i+color],0,sd->stc.prt_size);
586                      sd->stc.prt_width[buf_i+color] = 0;
587                   }
588 
589 
590 /* "read data", immediately continue if all is white */
591 
592                   if(sd->stc.buf_y < sd->stc.prt_scans) {  /* Test for White */
593 
594                      gdev_prn_get_bits(pdev,sd->stc.buf_y,ext_line,&ext_data);
595 
596                      color = stc_iswhite(sd,prt_pixels,ext_data) ? ext_size : 0;
597 
598                   } else {
599 
600                      color = ext_size;
601 
602                   }                        /* Test for White */
603 
604                   if(color >= ext_size) {  /* bypass processing */
605 
606                      if(sd->stc.dither->flags & STC_WHITE)
607                         (*sd->stc.dither->fun)(sd,prt_pixels,NULL,buf,col_line);
608                      continue;
609 
610                   }                        /* bypass processing */
611 
612 /* convert data for the various cases */
613 
614                   alg_data = (*iconvert)(sd,ext_data,prt_pixels,alg_line);
615 
616 
617 /*
618  * invoke the dithering-algorithm
619  */
620 
621                   (*sd->stc.dither->fun)(sd,prt_pixels,alg_data,buf,col_line);
622 /*
623  * convert col_line to printer-format (separate colors)
624  */
625                   switch(sd->color_info.num_components) {
626                   case 1: /* Black & White: just merge into 8 Bytes */
627                   {
628                       byte *bytein,*byteout;
629                       int   width;
630 
631                       bytein  = col_line;
632                       byteout = sd->stc.prt_data[buf_i];
633 
634                       for(width = 1; width <= sd->stc.prt_size; ++width) {
635                           byte tmp = 0;
636                           byte i;
637 
638                           for(i = 128; i; i >>= 1) if(*bytein++) tmp  |= i;
639 
640                           if(tmp != 0) sd->stc.prt_width[buf_i] = width;
641 
642                           *byteout++ = tmp;
643                       }
644                   }
645                   break;
646                   case 3: /* convert rgb into cmyk */
647                   {
648                       byte *bytein;
649                       int   width;
650 
651                       bytein  = col_line;
652 
653                       for(width = 0; width < sd->stc.prt_size; ++width) {
654                          byte i,tmp,cmyk[4];
655 
656                          memset(cmyk,0,4);
657 
658                          for(i = 128; i; i >>= 1) {
659                             static const byte rgb2cmyk[] = {
660                                BLACK,            /* 0->Black */
661                                CYAN | MAGENTA,   /* 1->BLUE  */
662                                CYAN | YELLOW,    /* 2->GREEN */
663                                CYAN,             /* 3->CYAN  */
664                                MAGENTA | YELLOW, /* 4->RED   */
665                                MAGENTA,          /* 5->MAGENTA */
666                                YELLOW,           /* 6->YELLOW */
667                                0};               /* 7->WHITE */
668 
669                             tmp = rgb2cmyk[(*bytein++) & 7];
670 
671                             if(tmp & BLACK)   cmyk[3] |= i;
672                             if(tmp & YELLOW)  cmyk[2] |= i;
673                             if(tmp & MAGENTA) cmyk[1] |= i;
674                             if(tmp & CYAN)    cmyk[0] |= i;
675                          }
676 
677                          for(i = 0; i < 4; ++i) {
678                             if(cmyk[i] != 0) sd->stc.prt_width[buf_i+i] = width+1;
679                             sd->stc.prt_data[buf_i+i][width] = cmyk[i];
680                          }
681                       }
682                   }
683                   break;
684                   case 4: /* split cmyk */
685                   {
686                       byte *bytein;
687                       int   width;
688 
689                       bytein  = col_line;
690 
691                       for(width = 0; width < sd->stc.prt_size; ++width) {
692                          byte i,tmp,cmyk[4];
693 
694                          memset(cmyk,0,4);
695 
696                          for(i = 128; i; i >>= 1) {
697                             tmp = (*bytein++) & 15;
698                             if(tmp & BLACK)   cmyk[3] |= i;
699                             if(tmp & YELLOW)  cmyk[2] |= i;
700                             if(tmp & MAGENTA) cmyk[1] |= i;
701                             if(tmp & CYAN)    cmyk[0] |= i;
702                          }
703 
704                          for(i = 0; i < 4; ++i) {
705                             if(cmyk[i] != 0) sd->stc.prt_width[buf_i+i] = width+1;
706                             sd->stc.prt_data[buf_i+i][width] = cmyk[i];
707                          }
708                       }
709                   }
710                   break;
711                   default: break;
712                   }
713                }
714             }                  /* Nr. 5 (give me input) */
715 
716 /*
717  *    Nr. 5 has got enough input, now we should print it
718  */
719             if((flags & STCCOMP) == STCDELTA) stc_print_delta(sd,prn_stream);
720             else if(npass > 1)                stc_print_weave(sd,prn_stream);
721             else                              stc_print_bands(sd,prn_stream);
722 
723 #ifdef    STC_SIGNAL
724             sigpending(&stc_int_pending);
725             if(sigismember(&stc_int_pending,SIGINT)) {
726                fputs("\033@[Aborted]\f", prn_stream);
727                fflush(prn_stream);
728                sigprocmask(SIG_SETMASK,&stc_int_save,NULL);
729                break;
730             }
731 #endif /* STC_SIGNAL */
732 
733          }                           /* Until all scans are processed */
734 
735          if(sd->stc.flags & STCPRINT) {
736             if((flags & STCCOMP) == STCDELTA) fputc(0xe3,prn_stream);
737             fwrite(sd->stc.escp_release.data,1,sd->stc.escp_release.size,prn_stream);
738             fflush(prn_stream);
739          }
740 #ifdef    STC_SIGNAL
741          sigprocmask(SIG_SETMASK,&stc_int_save,NULL);
742 #endif /* STC_DIGNAL */
743 
744       }
745    }
746 
747 /***
748  *** Release the dynamic memory
749  ***/
750 
751    if(ext_line != NULL)
752       gs_free(ext_line,ext_size,1,"stc_print_page/ext_line");
753 
754    if(col_line != NULL)
755       gs_free(col_line,prt_pixels,1,"stc_print_page/col_line");
756 
757    if(alg_line != NULL)
758       gs_free(alg_line,alg_size,sd->stc.alg_item,
759          "stc_print_page/alg_line");
760 
761    if(buf != NULL)
762       gs_free(buf,buf_size,sd->stc.alg_item,"stc_print_page/buf");
763 
764     if(sd->stc.prt_width != NULL)
765        gs_free(sd->stc.prt_width,sd->stc.prt_buf,sizeof(int),
766        "stc_print_page/prt_width");
767 
768     if(sd->stc.prt_data != NULL) {
769        int i;
770 
771        for(i = 0; i < sd->stc.prt_buf; ++i) {
772           if(sd->stc.prt_data[i] != NULL)
773              gs_free(sd->stc.prt_data[i],sd->stc.prt_size,1,
774              "stc_print_page/prt");
775        }
776 
777        gs_free(sd->stc.prt_data,sd->stc.prt_buf,sizeof(byte *),
778        "stc_print_page/prt_data");
779     }
780 
781     {
782        int i;
783        for(i = 0; i < sd->color_info.num_components; ++i) {
784           if(sd->stc.seed_row[i] != NULL)
785             gs_free(sd->stc.seed_row[i],sd->stc.seed_size,sizeof(int),
786             "stc_print_page/seed_row");
787        }
788     }
789 
790     if(sd->stc.escp_data != NULL)
791        gs_free(sd->stc.escp_data,sd->stc.escp_size,1,
792        "stc_print_page/escp_data");
793 
794    return OK4GO ? 0 : gs_error_undefined;
795 }
796 
797 /*
798  * white-check
799  */
800 private bool
801 stc_iswhite(stcolor_device *sd, int prt_pixels,byte *ext_data)
802 {
803    long  b2do = (prt_pixels*sd->color_info.depth+7)>>3;
804    int   bcmp = 4 * countof(sd->stc.white_run);
805    byte *wht  = (byte *) sd->stc.white_run;
806 
807    while(b2do >= bcmp) {
808       if(memcmp(ext_data,wht,bcmp)) break;
809       ext_data += bcmp;
810       b2do     -= bcmp;
811    }
812 
813    if((b2do > 0) && (b2do < bcmp))
814       b2do  = memcmp(ext_data,sd->stc.white_end,b2do);
815 
816    return b2do ? false : true;
817 }
818 
819 /***
820  *** A bunch of routines that convert gslines into algorithms format.
821  ***/
822 private byte *
823 stc_any_depth(stcolor_device *sd,byte *ext_data,int prt_pixels,byte *alg_line)
824 { /* general conversion */
825 
826    int p,c,       niext,         nbits;
827    gx_color_index ciext,ci,cimsk,cvmsk;
828    byte          *ap = alg_line;
829 
830    nbits =  sd->stc.bits;
831    cvmsk = ((gx_color_index) 1<<nbits) - 1;
832 
833 /* it is nonsense to use this algorithm for this cases, but if it claims
834  * generality, it should deliver correct results in this cases too */
835    if(sd->color_info.depth == (sd->color_info.num_components<<3)) nbits = 8;
836 
837    cimsk = cvmsk;
838    for(c = 1; c < sd->color_info.num_components; ++c)
839        cimsk = (cimsk<<nbits) | cvmsk;
840 
841    ciext = 0;
842    niext = 0;
843 
844    for(p = 0; p < prt_pixels; ++p) { /* over pixels */
845 
846       ci = ciext;
847       for(c =  sd->color_info.depth-niext; c >= 8; c -= 8)
848          ci  = (ci<<8) | *ext_data++;
849 
850       if(c > 0) {         /* partial byte required */
851 
852          niext  = 8 - c;
853          ciext  = *ext_data++;
854          ci     = (ci<<c) | (ciext>>niext);
855          ciext &= (1L<<niext)-1;
856 
857       } else if(c < 0) { /* some bits left in ciext */
858 
859          niext  = -c;
860          ciext &= (1L<<niext)-1;
861          ci     = ci>>niext;
862 
863       } else {           /* entire ciext used */
864 
865          niext = 0;
866          ciext = 0;
867 
868       }                  /* ciext-adjust */
869 
870       ci &= cimsk;
871 
872 #     define stc_storeapc(T) \
873          ((T *)ap)[c] = ((T *)(sd->stc.vals[c]))[ci & cvmsk];
874 
875       for(c = sd->color_info.num_components; c--;) { /* comp */
876          STC_TYPESWITCH(sd->stc.dither,stc_storeapc)
877          ci >>= nbits;
878       }                                              /* comp */
879 
880 #     undef  stc_storeapc
881 
882       ap += sd->color_info.num_components * sd->stc.alg_item;
883 
884    }                                 /* over pixels */
885 
886    return alg_line;
887 } /* general conversion */
888 
889 /*
890  * rgb-data with depth=24, can use a faster algorithm
891  */
892 private byte *
893 stc_rgb24_long(stcolor_device *sd,byte *ext_data,int prt_pixels,byte *alg_line)
894 { /* convert 3 bytes into appropriate long-Values */
895   register int   p;
896   register long *out   = (long *) alg_line;
897   register long *rvals = (long *) (sd->stc.vals[0]);
898   register long *gvals = (long *) (sd->stc.vals[1]);
899   register long *bvals = (long *) (sd->stc.vals[2]);
900 
901   for(p = prt_pixels; p; --p) {
902      *out++ = rvals[*ext_data++];
903      *out++ = gvals[*ext_data++];
904      *out++ = bvals[*ext_data++];
905   }
906 
907   return alg_line;
908 } /* convert 3 bytes into appropriate long-Values */
909 
910 /*
911  * cmyk-data with depth=32, can use a faster algorithm
912  */
913 private byte *
914 stc_cmyk32_long(stcolor_device *sd,byte *ext_data,int prt_pixels,byte *alg_line)
915 { /* convert 4 bytes into appropriate long-Values */
916   register int   p;
917   register long *out   = (long *) alg_line;
918   register long *cvals = (long *) (sd->stc.vals[0]);
919   register long *mvals = (long *) (sd->stc.vals[1]);
920   register long *yvals = (long *) (sd->stc.vals[2]);
921   register long *kvals = (long *) (sd->stc.vals[3]);
922 
923   for(p = prt_pixels; p; --p) {
924      *out++ = cvals[*ext_data++];
925      *out++ = mvals[*ext_data++];
926      *out++ = yvals[*ext_data++];
927      *out++ = kvals[*ext_data++];
928   }
929 
930   return alg_line;
931 } /* convert 4 bytes into appropriate long-Values */
932 
933 /*
934  * handle indirect encoded cmyk-data
935  */
936 #define STC_CMYK10_ANY(T)\
937                                                                             \
938       register int p               = prt_pixels;                            \
939       register stc_pixel      ci,k,n,mode;                                  \
940       register stc_pixel      *in  = (stc_pixel *) ext_data;                \
941       register T              *out = (T *) alg_line;                        \
942       register T              *cv  = (T *) sd->stc.vals[0];                 \
943       register T              *mv  = (T *) sd->stc.vals[1];                 \
944       register T              *yv  = (T *) sd->stc.vals[2];                 \
945       register T              *kv  = (T *) sd->stc.vals[3];                 \
946                                                                             \
947       while(p--) {                                                          \
948          ci   = *in++;                                                      \
949          mode = ci & 3;                                                     \
950          k    = (ci>>2) & 0x3ff;                                            \
951          if(mode == 3) {                                                    \
952             *out++ = cv[0];                                                 \
953             *out++ = mv[0];                                                 \
954             *out++ = yv[0];                                                 \
955             *out++ = kv[k];                                                 \
956          } else {                                                           \
957             out[3] = kv[k];                                                 \
958             n = (ci>>12) & 0x3ff;                                           \
959             if(mode == 2) { out[2] = yv[k]; }                               \
960             else          { out[2] = yv[n]; n = (ci>>22) & 0x3ff; }         \
961             if(mode == 1) { out[1] = mv[k]; }                               \
962             else          { out[1] = mv[n]; n = (ci>>22) & 0x3ff; }         \
963             if(mode == 0)   out[0] = cv[k];                                 \
964             else            out[0] = cv[n];                                 \
965             out += 4;                                                       \
966          }                                                                  \
967       }                                                                     \
968                                                                             \
969       return alg_line;
970 
971 private byte *
972 stc_cmyk10_byte(stcolor_device *sd,
973                 byte *ext_data,int prt_pixels,byte *alg_line)
974 {
975    STC_CMYK10_ANY(byte)
976 }
977 private byte *
978 stc_cmyk10_long(stcolor_device *sd,
979                 byte *ext_data,int prt_pixels,byte *alg_line)
980 {
981    STC_CMYK10_ANY(long)
982 }
983 private byte *
984 stc_cmyk10_float(stcolor_device *sd,
985                 byte *ext_data,int prt_pixels,byte *alg_line)
986 {
987    STC_CMYK10_ANY(float)
988 }
989 
990 #undef  STC_CMYK10_ANY
991 
992 #define STC_CMYK10_DANY(T)\
993                                                                             \
994       register int p               = prt_pixels;                            \
995       register stc_pixel       ci,k,n,mode;                                 \
996       register stc_pixel      *in  = (stc_pixel *) ext_data;                \
997       register T              *out = (T *) alg_line;                        \
998                                                                             \
999       while(p--) {                                                          \
1000          ci   = *in++;                                                      \
1001          mode = ci & 3;                                                     \
1002          k    = (ci>>2) & 0x3ff;                                            \
1003          if(mode == 3) {                                                    \
1004             *out++ = 0;                                                     \
1005             *out++ = 0;                                                     \
1006             *out++ = 0;                                                     \
1007             *out++ = k;                                                     \
1008          } else {                                                           \
1009             out[3] = k;                                                     \
1010             n = (ci>>12) & 0x3ff;                                           \
1011             if(mode == 2) { out[2] = k; }                                   \
1012             else          { out[2] = n; n = (ci>>22) & 0x3ff; }             \
1013             if(mode == 1) { out[1] = k; }                                   \
1014             else          { out[1] = n; n = (ci>>22) & 0x3ff; }             \
1015             if(mode == 0)   out[0] = k;                                     \
1016             else            out[0] = n;                                     \
1017             out += 4;                                                       \
1018          }                                                                  \
1019       }                                                                     \
1020                                                                             \
1021       return alg_line;
1022 
1023 
1024 private byte *
1025 stc_cmyk10_dbyte(stcolor_device *sd,
1026                 byte *ext_data,int prt_pixels,byte *alg_line)
1027 {
1028    STC_CMYK10_DANY(byte)
1029 }
1030 private byte *
1031 stc_cmyk10_dlong(stcolor_device *sd,
1032                 byte *ext_data,int prt_pixels,byte *alg_line)
1033 {
1034    STC_CMYK10_DANY(long)
1035 }
1036 
1037 #undef  STC_CMYK10_DANY
1038 
1039 /*
1040  * if the algorithm uses bytes & bytes are in ext_data, use them
1041  */
1042 /*ARGSUSED*/
1043 private byte *
1044 stc_any_direct(stcolor_device *sd,byte *ext_data,int prt_pixels,byte *alg_line)
1045 { /* return ext_data */
1046   return ext_data;
1047 } /* return ext_data */
1048 
1049 /* ----------------------------------------------------------------------- */
1050 /* stc_rle: epson ESC/P2 RLE-Encoding
1051  */
1052 private int
1053 stc_rle(byte *out,const byte *in,int width)
1054 {
1055 
1056    int used = 0;
1057    int crun,cdata;
1058    byte run;
1059 
1060    if(in != NULL) { /* Data present */
1061 
1062       crun = 1;
1063 
1064       while(width > 0) { /* something to compress */
1065 
1066          run = in[0];
1067 
1068          while((width > crun) && (run == in[crun])) if(++crun == 129) break;
1069 
1070          if((crun > 2) || (crun == width)) { /* use this run */
1071 
1072             *out++ = (257 - crun) & 0xff; *out++ = run; used += 2;
1073 
1074             width -= crun; in    += crun;
1075             crun = 1;
1076 
1077          } else {                            /* ignore this run */
1078 
1079             for(cdata = crun; (width > cdata) && (crun < 4);) {
1080                if(run  == in[cdata]) crun += 1;
1081                else run = in[cdata], crun  = 1;
1082                if(++cdata == 128) break;
1083             }
1084 
1085             if(crun < 3) crun   = 0;    /* ignore trailing run */
1086             else         cdata -= crun;
1087 
1088             *out++ = cdata-1;     used++;
1089             memcpy(out,in,cdata); used += cdata; out   += cdata;
1090 
1091             width -= cdata; in    += cdata;
1092 
1093          }              /* use/ignore run */
1094 
1095       }                  /* something to compress */
1096 
1097    } else {         /* Empty scans to fill bands */
1098 
1099       while(width > 0) {
1100          crun   = width > 129 ? 129 : width;
1101          width -= crun;
1102          *out++ = (257 - crun) & 0xff;
1103          *out++ = 0;
1104          used  += 2;
1105       }
1106    }                /* Data present or empty */
1107    return used;
1108 }
1109 
1110 
1111 /*
1112  * Horizontal & vertical positioning, color-selection, "ESC ."
1113  */
1114 private int
1115 stc_print_escpcmd(stcolor_device *sd, FILE *prn_stream,
1116    int escp_used, int color,int m,int wbytes)
1117 {
1118 
1119    int dy  = sd->stc.stc_y - sd->stc.prt_y; /* number of units to skip */
1120    int nlf;
1121 
1122 /* ESC-R color codes, used only here */
1123    static const byte stc_colors[] = { 0x02, 0x01, 0x04, 0x00 }; /* CMYK */
1124 
1125 /*
1126  * initialize the printer, if necessary
1127  */
1128    if(0 == (sd->stc.flags & STCPRINT)) {
1129 
1130       fwrite(sd->stc.escp_init.data,1,sd->stc.escp_init.size,prn_stream);
1131 
1132       if(0 < sd->stc.escp_lf) { /* Adjust Linefeed */
1133          fputc('\033',        prn_stream);
1134          fputc('+',           prn_stream);
1135          fputc(((sd->stc.escp_m*sd->stc.escp_u) / 10),prn_stream);
1136       }                         /* Adjust Linefeed */
1137       sd->stc.flags |= STCPRINT;
1138    }
1139 
1140    sd->stc.escp_data[escp_used++]  = '\r';     /* leftmost position */
1141 
1142    if(dy) {                                    /* position the printer */
1143       if(( sd->stc.escp_lf      >  0) && /* Linefeed allowed */
1144          ((dy % sd->stc.escp_lf) == 0))   /* and possible */
1145             nlf = dy / sd->stc.escp_lf;
1146       else  nlf = 7;
1147 
1148       if(nlf > 6) {
1149          sd->stc.escp_data[escp_used++]  = '\033';
1150          sd->stc.escp_data[escp_used++]  = '(';
1151          sd->stc.escp_data[escp_used++]  = 'V';
1152          sd->stc.escp_data[escp_used++]  = '\002';
1153          sd->stc.escp_data[escp_used++]  = '\000';
1154          sd->stc.escp_data[escp_used++]  =  sd->stc.stc_y       & 0xff;
1155          sd->stc.escp_data[escp_used++]  = (sd->stc.stc_y >> 8) & 0xff;
1156       } else {
1157          while(nlf--) sd->stc.escp_data[escp_used++] = '\n';
1158       }
1159       sd->stc.prt_y = sd->stc.stc_y;
1160    }                                           /* position the printer */
1161 
1162    if((sd->color_info.num_components > 1) &&
1163       (sd->stc.escp_c != stc_colors[color])) { /* select color */
1164        sd->stc.escp_data[escp_used++]  = '\033';
1165        sd->stc.escp_data[escp_used++]  = 'r';
1166        sd->stc.escp_c                  = stc_colors[color];
1167        sd->stc.escp_data[escp_used++]  = sd->stc.escp_c;
1168    }                                           /* select color */
1169 
1170 /*
1171  * Build the command used
1172  */
1173    sd->stc.escp_data[escp_used++] = '\033';
1174    sd->stc.escp_data[escp_used++] = '.';
1175    sd->stc.escp_data[escp_used++] =
1176        (sd->stc.flags & STCCOMP) == STCPLAIN ? 0 : 1;
1177    sd->stc.escp_data[escp_used++] = sd->stc.escp_v;
1178    sd->stc.escp_data[escp_used++] = sd->stc.escp_h;
1179    sd->stc.escp_data[escp_used++] = m;
1180    sd->stc.escp_data[escp_used++] = (wbytes<<3) & 0xff; /* width in Pixels */
1181    sd->stc.escp_data[escp_used++] = (wbytes>>5) & 0xff;
1182 
1183    return escp_used;
1184 }
1185 
1186 /*
1187  * compute width of a group of scanlines
1188  */
1189 private int
1190 stc_bandwidth(stcolor_device *sd,int color,int m,int npass)
1191 {
1192    int ncolor = sd->color_info.num_components == 1 ? 1 : 4;
1193    int buf_a  = (sd->stc.prt_buf-1) & (sd->stc.stc_y * ncolor + color);
1194    int w      = 0;
1195 
1196    while(m-- > 0) { /* check width */
1197       if(sd->stc.prt_width[buf_a] > w) w = sd->stc.prt_width[buf_a];
1198       buf_a = (sd->stc.prt_buf-1) & (buf_a + ncolor * npass);
1199    }                       /* check width */
1200 
1201    return w;
1202 }
1203 
1204 /*
1205  * Multi-Pass Printing-Routine
1206  */
1207 private void
1208 stc_print_weave(stcolor_device *sd, FILE *prn_stream)
1209 {
1210 
1211    int escp_used,nprint,nspace,color,buf_a,iprint,w;
1212 
1213    int npass  = sd->stc.escp_v / sd->stc.escp_u;
1214    int ncolor = sd->color_info.num_components == 1 ? 1 : 4;
1215 
1216 
1217    while(sd->stc.stc_y < sd->stc.prt_scans) {
1218 
1219 /*
1220  * compute spacing & used heads (seems to work with odd escp_m)
1221  */
1222       if(sd->stc.stc_y >= sd->stc.escp_m) { /* in normal mode */
1223          nprint = sd->stc.escp_m;
1224          nspace = sd->stc.escp_m;
1225       } else if((sd->stc.stc_y) < npass) {                /* initialisation */
1226          nprint = sd->stc.escp_m - sd->stc.stc_y * ((sd->stc.escp_m+1)/npass);
1227          nspace = 1;
1228       } else {                                   /* switch to normal */
1229          nprint = sd->stc.escp_m - sd->stc.stc_y * ((sd->stc.escp_m+1)/npass);
1230          nspace = sd->stc.escp_m - sd->stc.stc_y;
1231       }
1232       iprint = sd->stc.stc_y + npass * nprint;
1233       if(sd->stc.buf_y < iprint) break;
1234 
1235       escp_used = 0;
1236       for(color = 0; color < ncolor; ++color) { /* print the colors */
1237 
1238          if(0 == (w = stc_bandwidth(sd,color,nprint,npass))) continue;
1239 
1240          escp_used = stc_print_escpcmd(sd,prn_stream,
1241                                        escp_used,color,sd->stc.escp_m,w);
1242 
1243          buf_a = (sd->stc.prt_buf-1) & (sd->stc.stc_y * ncolor + color);
1244          for(iprint = 0; iprint < nprint; ++iprint) { /* send data */
1245 
1246             if((sd->stc.flags & STCCOMP) == STCPLAIN) {
1247                memcpy(sd->stc.escp_data+escp_used,sd->stc.prt_data[buf_a],w);
1248                escp_used += w;
1249             } else {
1250                escp_used += stc_rle(sd->stc.escp_data+escp_used,
1251                                     sd->stc.prt_data[buf_a],w);
1252             }
1253 
1254             fwrite(sd->stc.escp_data,1,escp_used,prn_stream);
1255             escp_used = 0;
1256 
1257             buf_a = (sd->stc.prt_buf-1) & (buf_a + ncolor * npass);
1258 
1259          }                                            /* send data */
1260 
1261          while(iprint++ < sd->stc.escp_m) {  /* add empty rows */
1262 
1263             if((sd->stc.flags & STCCOMP) == STCPLAIN) {
1264                memset(sd->stc.escp_data+escp_used,0,w);
1265                escp_used += w;
1266             } else {
1267                escp_used += stc_rle(sd->stc.escp_data+escp_used,NULL,w);
1268             }
1269 
1270             fwrite(sd->stc.escp_data,1,escp_used,prn_stream);
1271             escp_used = 0;
1272          }                               /* add empty rows */
1273       }                                             /* print the colors */
1274 
1275       sd->stc.stc_y += nspace;
1276    }
1277 }
1278 
1279 /*
1280  * Single-Pass printing-Routine
1281  */
1282 private void
1283 stc_print_bands(stcolor_device *sd, FILE *prn_stream)
1284 {
1285 
1286    int escp_used,color,buf_a,iprint,w,m;
1287 
1288    int ncolor = sd->color_info.num_components == 1 ? 1 : 4;
1289 
1290    while(sd->stc.stc_y < sd->stc.prt_scans) {
1291 
1292 /*
1293  * find the begin of the band
1294  */
1295       for(w = 0; sd->stc.stc_y < sd->stc.buf_y; ++sd->stc.stc_y) {
1296          buf_a = (sd->stc.prt_buf-1) & (sd->stc.stc_y * ncolor);
1297          for(color = 0; color < ncolor; ++color)
1298             if(sd->stc.prt_width[buf_a+color] > w)
1299                w = sd->stc.prt_width[buf_a+color];
1300          if(w != 0) break;
1301       }
1302       if(w == 0) break;
1303 /*
1304  * adjust the band-height
1305  */
1306       w = sd->stc.prt_scans - sd->stc.stc_y;
1307       if((w < sd->stc.escp_m) && (sd->stc.escp_v != 40)) {
1308          if(w < 8)       m =  1;
1309          else if(w < 24) m =  8;
1310          else            m = 24;
1311       } else {
1312          m = sd->stc.escp_m;
1313       }
1314 
1315       if(sd->stc.buf_y < (sd->stc.stc_y+m)) break;
1316 
1317       escp_used = 0;
1318       for(color = 0; color < ncolor; ++color) { /* print the colors */
1319 
1320          if(0 == (w = stc_bandwidth(sd,color,m,1))) continue; /* shortcut */
1321 
1322          escp_used = stc_print_escpcmd(sd,prn_stream,escp_used,color,m,w);
1323 
1324          buf_a = (sd->stc.prt_buf-1) & (sd->stc.stc_y * ncolor + color);
1325          for(iprint = 0; iprint < m; ++iprint) { /* send data */
1326 
1327             if((sd->stc.flags & STCCOMP) == STCPLAIN) {
1328                memcpy(sd->stc.escp_data+escp_used,sd->stc.prt_data[buf_a],w);
1329                escp_used += w;
1330             } else {
1331                escp_used += stc_rle(sd->stc.escp_data+escp_used,
1332                                     sd->stc.prt_data[buf_a],w);
1333             }
1334 
1335             fwrite(sd->stc.escp_data,1,escp_used,prn_stream);
1336             escp_used = 0;
1337 
1338             buf_a = (sd->stc.prt_buf-1) & (buf_a + ncolor);
1339 
1340          }                                            /* send data */
1341 
1342       }                                             /* print the colors */
1343 
1344       sd->stc.stc_y += m;
1345    }
1346 }
1347 /* ----------------------------------------------------------------------- */
1348 
1349 private int
1350 stc_deltarow(byte *out,const byte *in,int width,byte *seed)
1351 {
1352 
1353    int istop,nmove,ndata,i,j;
1354    int *wseed = (int *) seed;
1355    int used   = 0;
1356 
1357    seed += sizeof(int);
1358 
1359    if((in != NULL) && (width > 0)) { /* Data present */
1360 
1361       istop = width < wseed[0] ? wseed[0] : width;
1362 
1363       i = 0;
1364       while(i < istop) {
1365 
1366          for(j = i; j < istop; ++j) if(in[j] != seed[j]) break;
1367 
1368          nmove = j - i;
1369 
1370          if(nmove > 0) { /* issue a move */
1371            i     = j;
1372            if(i == istop) break;
1373 
1374            if(       nmove <   8) {
1375               out[used++] = 0x40 | nmove;
1376            } else if(nmove < 128) {
1377               out[used++] = 0x51;
1378               out[used++] = nmove;
1379            } else {
1380               out[used++] = 0x52;
1381               out[used++] = 0xff & nmove;
1382               out[used++] = 0xff & (nmove>>8);
1383            }
1384          }           /* issue a move */
1385 
1386 /*
1387  * find the end of this run
1388  */
1389          nmove = 0;
1390          for(j = i+1; (j < istop) && ((nmove < 4)); ++j) {
1391             if(in[j] == seed[j]) nmove += 1;
1392             else                 nmove  = 0;
1393          }
1394 
1395          ndata = j-i-nmove;
1396 
1397          nmove = stc_rle(out+used+3,in+i,ndata);
1398          if(nmove < 16) {
1399             out[used++] = 0x20 | nmove;
1400             for(j = 0; j < nmove; ++j) out[used+j] = out[used+j+2];
1401          } else if(nmove < 256) {
1402             out[used++] = 0x31;
1403             out[used++] = nmove;
1404             for(j = 0; j < nmove; ++j) out[used+j] = out[used+j+1];
1405          } else {
1406             out[used++] = 0x32;
1407             out[used++] = 0xff & nmove;
1408             out[used++] = 0xff & (nmove>>8);
1409          }
1410          used += nmove;
1411          i    += ndata;
1412       }
1413 
1414       memcpy(seed,in,istop);
1415       wseed[0] = width;
1416 
1417    } else if(wseed[0] > 0) { /* blank line, but seed has data */
1418 
1419       out[used++] = 0xe1; /* clear row */
1420       memset(seed,0,wseed[0]);
1421       wseed[0] = 0;
1422 
1423    }
1424 
1425    return used;
1426 }
1427 
1428 /*
1429  * Slightly different single-pass printing
1430  */
1431 private void
1432 stc_print_delta(stcolor_device *sd, FILE *prn_stream)
1433 {
1434 
1435    int color,buf_a,w;
1436    int escp_used = 0;
1437    int ncolor = sd->color_info.num_components == 1 ? 1 : 4;
1438 
1439    while(sd->stc.stc_y < sd->stc.prt_scans) {
1440 
1441 /*
1442  * find the begin of the band
1443  */
1444       for(w = 0; sd->stc.stc_y < sd->stc.buf_y; ++sd->stc.stc_y) {
1445          buf_a = (sd->stc.prt_buf-1) & (sd->stc.stc_y * ncolor);
1446          for(color = 0; color < ncolor; ++color)
1447             if(sd->stc.prt_width[buf_a+color] > w)
1448                w = sd->stc.prt_width[buf_a+color];
1449          if(w != 0) break;
1450       }
1451 
1452       if(sd->stc.buf_y == sd->stc.stc_y) break;
1453 
1454       escp_used = 0;
1455 
1456 /*
1457  * Send Initialization & ESC . 3 once
1458  */
1459       if(0 == (sd->stc.flags & STCPRINT)) {
1460 
1461          sd->stc.flags |= STCPRINT;
1462 
1463          fwrite(sd->stc.escp_init.data,1,sd->stc.escp_init.size,prn_stream);
1464 
1465          sd->stc.escp_data[escp_used++] = '\033';
1466          sd->stc.escp_data[escp_used++] = '.';
1467          sd->stc.escp_data[escp_used++] =  3;
1468          sd->stc.escp_data[escp_used++] = sd->stc.escp_v;
1469          sd->stc.escp_data[escp_used++] = sd->stc.escp_h;
1470          sd->stc.escp_data[escp_used++] = sd->stc.escp_m;
1471          sd->stc.escp_data[escp_used++] = 0;
1472          sd->stc.escp_data[escp_used++] = 0;
1473          sd->stc.escp_data[escp_used++] = 0xe4; /* MOVXBYTE */
1474       }
1475 
1476       if(sd->stc.stc_y != sd->stc.prt_y) { /* really position the printer */
1477          w = sd->stc.stc_y - sd->stc.prt_y;
1478          if(       w <  16) {
1479             sd->stc.escp_data[escp_used++] = 0x60 | w;
1480          } else if(w < 256) {
1481             sd->stc.escp_data[escp_used++] = 0x71;
1482             sd->stc.escp_data[escp_used++] = w;
1483          } else {
1484             sd->stc.escp_data[escp_used++] = 0x72;
1485             sd->stc.escp_data[escp_used++] = 0xff & w;
1486             sd->stc.escp_data[escp_used++] = 0xff & (w>>8);
1487          }
1488          sd->stc.prt_y = sd->stc.stc_y;
1489       }                                    /* really position the printer */
1490 
1491       for(color = 0; color < ncolor; ++color) { /* print the colors */
1492 
1493 /* Color-Selection */
1494          if(color == (ncolor-1)) {
1495             sd->stc.escp_data[escp_used++] = 0x80; /* Black */
1496          } else {
1497             switch(color) {
1498             case 1:  sd->stc.escp_data[escp_used++] = 0x81; break; /* M */
1499             case 2:  sd->stc.escp_data[escp_used++] = 0x84; break; /* Y */
1500             default: sd->stc.escp_data[escp_used++] = 0x82; break; /* C */
1501             }
1502          }
1503 
1504 /* Data-Transfer */
1505          buf_a = (sd->stc.prt_buf-1) & (sd->stc.stc_y * ncolor + color);
1506 
1507          w = stc_deltarow(sd->stc.escp_data+escp_used,
1508              sd->stc.prt_data[buf_a],sd->stc.prt_width[buf_a],
1509              sd->stc.seed_row[color]);
1510 
1511          if(w == 0) escp_used -= 1;
1512          else       escp_used += w;
1513 
1514          if(escp_used > 0) fwrite(sd->stc.escp_data,1,escp_used,prn_stream);
1515          escp_used = 0;
1516 
1517       }                                             /* print the colors */
1518 
1519       sd->stc.stc_y += 1;
1520 
1521    }
1522 
1523 }
1524 
1525 /* ----------------------------------------------------------------------- */
1526 
1527 /***
1528  *** Free-Data: release the specific-Arrays
1529  ***/
1530 private void
1531 stc_freedata(stc_t *stc)
1532 {
1533    int i,j;
1534 
1535    for(i = 0; i < 4; ++i) {
1536       if(stc->code[i] != NULL) {
1537 
1538          for(j = 0; j < i; ++j) if(stc->code[i] == stc->code[j]) break;
1539 
1540          if(i == j) gs_free(stc->code[i],1<<stc->bits,sizeof(gx_color_value),
1541                            "stcolor/code");
1542       }
1543 
1544       if(stc->vals[i] != NULL) {
1545 
1546          for(j = 0; j < i; ++j)
1547             if(stc->vals[i] == stc->vals[j]) break;
1548 
1549          if(i == j) gs_free(stc->vals[i],1<<stc->bits,sd->stc.alg_item,
1550                            "stcolor/transfer");
1551       }
1552    }
1553 
1554    for(i = 0; i < 4; ++i) {
1555       stc->code[i] = NULL;
1556       stc->vals[i] = NULL;
1557    }
1558 }
1559 
1560 /***
1561  *** open the device and initialize margins & arrays
1562  ***/
1563 
1564 private int
1565 stc_open(gx_device *pdev) /* setup margins & arrays */
1566 {
1567   stcolor_device *sd = (stcolor_device *) pdev;
1568   int i,j,code;
1569   gx_color_index white;
1570   byte *bpw,*bpm;
1571 
1572   code = 0;
1573 /*
1574  * Establish Algorithm-Table, if not present
1575  */
1576   if(sd->stc.algorithms.size == 0) {
1577      gs_param_string *dp;
1578      for(i = 0; stc_dither[i].name != NULL; ++i); /* count 'em */
1579      sd->stc.algorithms.size = i;
1580      dp = gs_malloc(i,sizeof(gs_param_string),
1581                                         "stcolor/algorithms");
1582      if(dp == NULL) {
1583         code = gs_error_VMerror;
1584         sd->stc.algorithms.size = 0;
1585      } else {
1586         sd->stc.algorithms.data       = dp;
1587         sd->stc.algorithms.persistent = true;
1588         for(i = 0; stc_dither[i].name != NULL; ++i) {
1589         param_string_from_string(dp[i],stc_dither[i].name);
1590         }
1591      }
1592   }
1593 
1594 # define stc_sizeofitem(T) sd->stc.alg_item = sizeof(T)
1595   STC_TYPESWITCH(sd->stc.dither,stc_sizeofitem)
1596 
1597   stc_print_setup(sd);
1598 
1599 /*
1600  * Establish internal Value & Code-Arrays
1601  */
1602 
1603 
1604   for(i = 0; i < sd->color_info.num_components; ++i) { /* comp */
1605 
1606      if((sd->stc.sizc[i] >  1) && (sd->stc.extc[i] != NULL)) { /* code req. */
1607 
1608         for(j = 0; j < i; ++j) if(sd->stc.extc[i] == sd->stc.extc[j]) break;
1609 
1610         if(i == j) { /* new one */
1611            sd->stc.code[i] = gs_malloc(1<<sd->stc.bits,sizeof(gx_color_value),
1612                              "stcolor/code");
1613 
1614            if(sd->stc.code[i] == NULL) { /* error */
1615               code = gs_error_VMerror;
1616            } else {                      /* success */
1617 /*
1618  * Try making things easier:
1619  *     normalize values to 0.0/1.0-Range
1620  *     X-Axis:   Color-Values (implied)
1621  *     Y-Values: Indices      (given)
1622  */
1623               unsigned long ly,iy;
1624               double ystep,xstep,fx,fy;
1625 
1626 /* normalize */
1627 
1628               fx =  1e18;
1629               fy = -1e18;
1630               for(ly = 0; ly < sd->stc.sizc[i]; ++ly) {
1631                  if(sd->stc.extc[i][ly] < fx) fx = sd->stc.extc[i][ly];
1632                  if(sd->stc.extc[i][ly] > fy) fy = sd->stc.extc[i][ly];
1633               }
1634               if((fx != 0.0) || (fy != 1.0)) {
1635                  fy = 1.0 / (fy - fx);
1636                  for(ly = 0; ly < sd->stc.sizc[i]; ++ly)
1637                     sd->stc.extc[i][ly] = fy * (sd->stc.extc[i][ly]-fx);
1638               }
1639 
1640 /* interpolate */
1641               ystep = 1.0 / (double)((1<<sd->stc.bits)-1);
1642               xstep = 1.0 / (double)( sd->stc.sizc[i] -1);
1643 
1644               iy = 0;
1645               for(ly = 0; ly < (1<<sd->stc.bits); ++ly) {
1646                  fy = ystep * ly;
1647                  while(((iy+1) < sd->stc.sizc[i]) &&
1648                        (  fy   > sd->stc.extc[i][iy+1])) ++iy;
1649                  fx  = iy + (fy - sd->stc.extc[i][iy])
1650                             / (sd->stc.extc[i][iy+1] - sd->stc.extc[i][iy]);
1651                  fx *= xstep * gx_max_color_value;
1652 
1653                  fx = fx < 0.0 ? 0.0 :
1654                       (fx > gx_max_color_value ? gx_max_color_value : fx);
1655 
1656                  sd->stc.code[i][ly] = fx;
1657                  if((fx-sd->stc.code[i][ly]) >= 0.5) sd->stc.code[i][ly] += 1;
1658               }
1659            }                             /* error || success */
1660 
1661         } else {     /* shared one */
1662 
1663            sd->stc.code[i] = sd->stc.code[j];
1664 
1665         }           /* new || shared one */
1666      }                                                         /* code req. */
1667 
1668      if((sd->stc.sizv[i] >  1) && (sd->stc.extv[i] != NULL)) { /* vals req. */
1669 
1670         for(j = 0; j < i; ++j)
1671            if((sd->stc.extc[i] == sd->stc.extc[j]) &&
1672               (sd->stc.extv[i] == sd->stc.extv[j])) break;
1673 
1674         if(i == j) { /* new one */
1675 
1676              sd->stc.vals[i] =
1677                 gs_malloc(1<<sd->stc.bits,sd->stc.alg_item,"stcolor/transfer");
1678 
1679            if(sd->stc.vals[i] == NULL) {
1680 
1681               code = gs_error_VMerror;
1682 
1683            } else {                      /* success */
1684 
1685 
1686               if(sd->stc.code[i] == NULL) { /* linear */
1687 
1688                  byte  *Out  = sd->stc.vals[i];
1689                  int    Nout = 1<<sd->stc.bits;
1690                  double Omin = sd->stc.dither->minmax[0];
1691                  double Omax = sd->stc.dither->minmax[1];
1692                  float *In   = sd->stc.extv[i];
1693                  int    Nin  = sd->stc.sizv[i];
1694                  unsigned long I,io;
1695                  double Istep,Ostep,Y;
1696                  byte   Ovb; long Ovl;
1697 
1698                  Istep = 1.0 / (double) ((Nin)-1);
1699                  Ostep = 1.0 / (double) ((Nout)-1);
1700 
1701                  for(io = 0; io < (Nout); ++io) {
1702                     I = (long)(io * ((Nin)-1))/((Nout)-1);
1703 
1704                     if((I+1) < (Nin))
1705                        Y = In[I] + (In[I+1]-In[I])
1706                                      * ((double) io * Ostep - (double)I * Istep)
1707                                                /  (double) Istep;
1708                     else
1709                        Y = In[I] + (In[I]-In[I-1])
1710                                      * ((double) io * Ostep - (double)I * Istep)
1711                                                /  (double) Istep;
1712 
1713                     Y = Omin + (Omax-Omin) * Y;
1714                     Y = Y < Omin ? Omin : (Y > Omax ? Omax : Y);
1715 
1716 
1717                     switch(sd->stc.dither->flags & STC_TYPE) {
1718                        case STC_BYTE:
1719                           Ovb = Y;
1720                           if(((Y-Ovb) >= 0.5) && ((Ovb+1) <= Omax)) Ovb += 1;
1721                           Out[io] = Ovb;
1722                           break;
1723                        case STC_LONG:
1724                           Ovl = Y;
1725                           if(((Y-Ovl) >= 0.5) && ((Ovl+1) <= Omax)) Ovl += 1;
1726                           if(((Ovl-Y) >= 0.5) && ((Ovl-1) >= Omax)) Ovl -= 1;
1727                           ((long *)Out)[io] = Ovl;
1728                           break;
1729                        default:
1730                           ((float *)Out)[io] = Y;
1731                           break;
1732                     }
1733                  }
1734 
1735               } else {                     /* encoded */
1736                  unsigned long j,o;
1737                  double xstep,x,y;
1738 
1739                  xstep = 1.0 / (double) (sd->stc.sizv[i]-1);
1740 
1741 /*
1742  * The following differs in so far from the previous, that the desired
1743  * X-Values are stored in another array.
1744  */
1745                  for(o = 0; o < (1<<sd->stc.bits); ++o) { /* code-loop */
1746 
1747                     x = sd->stc.code[i][o]; x /= gx_max_color_value;
1748 
1749                     j = x / xstep;
1750 
1751                     if((j+1) < sd->stc.sizv[i]) {
1752                        y  = sd->stc.extv[i][j];
1753                        y += (sd->stc.extv[i][j+1]-y)*(x-(double)j*xstep)/xstep;
1754                     } else {
1755                        y  = sd->stc.extv[i][j];
1756                        y += (y-sd->stc.extv[i][j-1])*(x-(double)j*xstep)/xstep;
1757                     }
1758 
1759                     y = sd->stc.dither->minmax[0]
1760                       +(sd->stc.dither->minmax[1]-sd->stc.dither->minmax[0])*y;
1761 
1762 #                   define stc_adjvals(T)                                             \
1763                      ((T *)(sd->stc.vals[i]))[o] = y;                                 \
1764                                                                                       \
1765                     if(((y-((T *)(sd->stc.vals[i]))[o]) >= 0.5) &&                    \
1766                        ((1+((T *)(sd->stc.vals[i]))[o]) <= sd->stc.dither->minmax[1]))\
1767                        ((T *)(sd->stc.vals[i]))[o]      += 1;                         \
1768                                                                                       \
1769                     if(((((T *)(sd->stc.vals[i]))[o]-y) >= 0.5) &&                    \
1770                        ((((T *)(sd->stc.vals[i]))[o]-1) >= sd->stc.dither->minmax[0]))\
1771                        ((T *)(sd->stc.vals[i]))[o]      -= 1;
1772 
1773                     STC_TYPESWITCH(sd->stc.dither,stc_adjvals)
1774 
1775 #                   undef stc_adjvals
1776                  }                                       /* code-loop */
1777               }                            /* lineaer / encoded */
1778            }                             /* error || success */
1779 
1780         } else {     /* shared one */
1781 
1782            sd->stc.vals[i] = sd->stc.vals[j];
1783 
1784         }           /* new || shared one */
1785      }                                                         /* vals req. */
1786   }                                                    /* comp */
1787 
1788   if(code == 0) {
1789 
1790       sd->stc.flags |= STCOK4GO;
1791 
1792 /*
1793  * Arrgh: open-procedure seems to be the right-place, but it is
1794  *        necessary to establish the defaults for omitted procedures too.
1795  */
1796 
1797       switch(sd->color_info.num_components) { /* Establish color-procs */
1798       case 1:
1799          set_dev_proc(sd,map_rgb_color, stc_map_gray_color);
1800          set_dev_proc(sd,map_cmyk_color,gx_default_map_cmyk_color);
1801          set_dev_proc(sd,map_color_rgb, stc_map_color_gray);
1802          white = stc_map_gray_color((gx_device *) sd,
1803                     gx_max_color_value,gx_max_color_value,gx_max_color_value);
1804          break;
1805       case 3:
1806          set_dev_proc(sd,map_rgb_color, stc_map_rgb_color);
1807          set_dev_proc(sd,map_cmyk_color,gx_default_map_cmyk_color);
1808          set_dev_proc(sd,map_color_rgb, stc_map_color_rgb);
1809          white = stc_map_rgb_color((gx_device *) sd,
1810                     gx_max_color_value,gx_max_color_value,gx_max_color_value);
1811          break;
1812       default:
1813          set_dev_proc(sd,map_rgb_color, gx_default_map_rgb_color);
1814          if(sd->stc.flags & STCCMYK10) {
1815             set_dev_proc(sd,map_cmyk_color,stc_map_cmyk10_color);
1816             set_dev_proc(sd,map_color_rgb, stc_map_color_cmyk10);
1817             white = stc_map_cmyk10_color((gx_device *) sd,0,0,0,0);
1818          } else {
1819             set_dev_proc(sd,map_cmyk_color,stc_map_cmyk_color);
1820             set_dev_proc(sd,map_color_rgb, stc_map_color_cmyk);
1821             white = stc_map_cmyk_color((gx_device *) sd,0,0,0,0);
1822          }
1823          break;                               /* Establish color-procs */
1824       }
1825 
1826 
1827 /*
1828  * create at least a Byte
1829  */
1830       if(sd->color_info.depth < 2) white |= (white<<1);
1831       if(sd->color_info.depth < 4) white |= (white<<2);
1832       if(sd->color_info.depth < 8) white |= (white<<4);
1833 
1834 /*
1835  * copy the Bytes
1836  */
1837       bpw = (byte *) sd->stc.white_run;
1838 
1839       if(sd->color_info.depth < 16) {
1840          for(i = 0; i < sizeof(sd->stc.white_run); i += 1) {
1841             bpw[i] = 0xff & white;
1842          }
1843       } else if(sd->color_info.depth < 24) {
1844          for(i = 0; i < sizeof(sd->stc.white_run); i += 2) {
1845             bpw[i]   = 0xff & (white>>8);
1846             bpw[i+1] = 0xff &  white;
1847          }
1848       } else if(sd->color_info.depth < 32) {
1849          for(i = 0; i < sizeof(sd->stc.white_run); i += 3) {
1850             bpw[i]   = 0xff & (white>>16);
1851             bpw[i+1] = 0xff & (white>> 8);
1852             bpw[i+2] = 0xff &  white;
1853          }
1854       } else {
1855          for(i = 0; i < sizeof(sd->stc.white_run); i += 4) {
1856             bpw[i]   = 0xff & (white>>24);
1857             bpw[i+1] = 0xff & (white>>16);
1858             bpw[i+2] = 0xff & (white>> 8);
1859             bpw[i+3] = 0xff &  white;
1860          }
1861       }
1862 /*
1863  *    compute the trailer
1864  */
1865       j  = sd->width -
1866           (dev_l_margin(sd)+dev_r_margin(sd))*sd->x_pixels_per_inch;
1867       j  = j * sd->color_info.depth;            /* the Bit-count */
1868       j  = j % (32*countof(sd->stc.white_run)); /* remaining Bits */
1869 
1870       bpm = (byte *) sd->stc.white_end;
1871       for(i = 0; i < (4*countof(sd->stc.white_end)); ++i) {
1872          if(       j <= 0) {
1873             bpm[i] = 0;
1874          } else if(j >= 8) {
1875             bpm[i] = 0xff;
1876             j -= 8;
1877          } else {
1878             bpm[i] = 0xff ^ ((1<<(8-j))-1);
1879             j  = 0;
1880          }
1881          bpm[i] &= bpw[i];
1882       }
1883 
1884 /*
1885  * Call super-class open
1886  */
1887 
1888       return gdev_prn_open(pdev);
1889 
1890    } else {
1891 
1892       stc_freedata(&sd->stc);
1893 
1894       return_error(code);
1895    }
1896 
1897 }
1898 
1899 /***
1900  *** stc_close: release the internal data
1901  ***/
1902 private int
1903 stc_close(gx_device *pdev)
1904 {
1905    stc_freedata(&((stcolor_device *) pdev)->stc);
1906    ((stcolor_device *) pdev)->stc.flags &= ~STCOK4GO;
1907    return gdev_prn_close(pdev);
1908 }
1909 
1910 
1911 /***
1912  *** Function for Bit-Truncation, including direct-byte-transfer
1913  ***/
1914 private gx_color_value
1915 stc_truncate(stcolor_device *sd,int i,gx_color_value v)
1916 {
1917 
1918    if(sd->stc.bits < gx_color_value_bits) {
1919       if(sd->stc.code[i] != NULL) {
1920 /*
1921  * Perform binary search in the code-array
1922  */
1923          long  s;
1924          gx_color_value *p;
1925 
1926          s = sd->stc.bits > 1 ? 1L<<(sd->stc.bits-2) : 0L;
1927          p = sd->stc.code[i]+(1L<<(sd->stc.bits-1));
1928 
1929          while(s > 0) {
1930             if(v > *p) {
1931                p += s;
1932             } else if(v < p[-1]) {
1933                p -= s;
1934             } else {
1935                if((v-p[-1]) < (p[0]-v)) p -= 1;
1936                break;
1937             }
1938             s >>= 1;
1939          }
1940          if((v-p[-1]) < (p[0]-v)) p -= 1;
1941          v = p - sd->stc.code[i];
1942 
1943       } else {
1944 
1945          v >>= gx_color_value_bits-sd->stc.bits;
1946 
1947       }
1948 
1949 /*
1950       V = (((1L<<D->stc.bits)-1)*V+(gx_max_color_value>>1))\
1951           /gx_max_color_value;                             \
1952 */
1953    }
1954    return v;
1955 }
1956 
1957 private gx_color_value
1958 stc_truncate1(stcolor_device *sd,int i,gx_color_value v)
1959 {
1960 
1961    return sd->stc.vals[i][stc_truncate(sd,i,v)];
1962 }
1963 
1964 /***
1965  *** Expansion of indices for reverse-mapping
1966  ***/
1967 private gx_color_value
1968 stc_expand(stcolor_device *sd,int i,gx_color_index col)
1969 {
1970 
1971    gx_color_index cv;
1972    gx_color_index l = (1<<sd->stc.bits)-1;
1973 
1974    if(sd->stc.code[i] != NULL) {
1975 
1976       cv  = sd->stc.code[i][col & l];
1977 
1978    } else if(sd->stc.bits < gx_color_value_bits) {
1979 
1980       cv  = (col & l)<<(gx_color_value_bits-sd->stc.bits);
1981       cv += (col & l)/l * ((1<<(gx_color_value_bits-sd->stc.bits))-1);
1982 
1983    } else if(sd->stc.bits > gx_color_value_bits) {
1984 
1985       cv  = (col & l)>>(sd->stc.bits-gx_color_value_bits);
1986 
1987    } else {
1988 
1989       cv  = col & l;
1990 
1991    }
1992 
1993    return cv;
1994 }
1995 
1996 /***
1997  *** color-mapping of gray-scales
1998  ***/
1999 private gx_color_index
2000 stc_map_gray_color(gx_device *pdev,
2001         gx_color_value r, gx_color_value g, gx_color_value b)
2002 {
2003 
2004    stcolor_device *sd = (stcolor_device *) pdev;
2005    gx_color_index rv;
2006 
2007    if((r == g) && (g == b)) {
2008 
2009       rv = gx_max_color_value - r;
2010 
2011    } else if(sd->stc.am != NULL) {
2012       float *m,fv;
2013 
2014       m   = sd->stc.am;
2015 
2016       fv  = gx_max_color_value;
2017       fv -= *m++ * (float) r; fv -= *m++ * (float) g; fv -= *m   * (float) b;
2018 
2019       if(     fv < 0.0)                      rv = 0;
2020       else if((fv+0.5) > gx_max_color_value) rv = gx_max_color_value;
2021       else                                   rv = fv+0.5;
2022 
2023    } else {
2024 
2025       rv  = ((gx_color_index)gx_max_color_value)<<3;
2026       rv -= (gx_color_index) 3 * r;
2027       rv -= (gx_color_index) 3 * g;
2028       rv -= ((gx_color_index)b)<<1;
2029       rv  = (rv+4)>>3;
2030       if(rv > gx_max_color_value) rv = gx_max_color_value;
2031 
2032    }
2033 
2034    if(( sd->stc.bits                      ==    8) &&
2035       ((sd->stc.dither->flags & STC_TYPE) == STC_BYTE))
2036       rv = stc_truncate1(sd,0,(gx_color_value)rv);
2037    else
2038       rv =  stc_truncate(sd,0,(gx_color_value)rv);
2039 
2040    return rv;
2041 }
2042 
2043 private int
2044 stc_map_color_gray(gx_device *pdev, gx_color_index color,gx_color_value prgb[3])
2045 {
2046    stcolor_device *sd = (stcolor_device *) pdev;
2047    gx_color_index l = ((gx_color_index)1<<sd->stc.bits)-1;
2048 
2049    prgb[0] = gx_max_color_value - stc_expand(sd,0,color & l);
2050    prgb[1] = prgb[0]; prgb[2] = prgb[0];
2051 
2052    return 0;
2053 }
2054 
2055 /***
2056  *** color-mapping of rgb-values
2057  ***/
2058 private gx_color_index
2059 stc_map_rgb_color(gx_device *pdev,
2060                   gx_color_value r, gx_color_value g, gx_color_value b)
2061 {
2062 
2063    stcolor_device *sd = (stcolor_device *) pdev;
2064    int          shift = sd->color_info.depth == 24 ? 8 : sd->stc.bits;
2065    gx_color_index  rv = 0;
2066 
2067    if((sd->stc.am != NULL) && ((r != g) || (g != b))) {
2068       float *m,fr,fg,fb,fv;
2069 
2070       m  = sd->stc.am;
2071       fr = r; fg = g; fb = b;
2072 
2073       fv = *m++ * fr; fv += *m++ * fg; fv += *m++ * fb;
2074 
2075       if(     fv < 0.0)                      r = 0;
2076       else if((fv+0.5) > gx_max_color_value) r = gx_max_color_value;
2077       else                                   r = fv+0.5;
2078 
2079       fv = *m++ * fr; fv += *m++ * fg; fv += *m++ * fb;
2080 
2081       if(     fv < 0.0)                      g = 0;
2082       else if((fv+0.5) > gx_max_color_value) g = gx_max_color_value;
2083       else                                   g = fv+0.5;
2084 
2085       fv = *m++ * fr; fv += *m++ * fg; fv += *m++ * fb;
2086 
2087       if(     fv < 0.0)                      b = 0;
2088       else if((fv+0.5) > gx_max_color_value) b = gx_max_color_value;
2089       else                                   b = fv+0.5;
2090 
2091    }
2092 
2093    if(( sd->stc.bits                      ==    8) &&
2094       ((sd->stc.dither->flags & STC_TYPE) == STC_BYTE)) {
2095       rv =               stc_truncate1(sd,0,r);
2096       rv = (rv<<shift) | stc_truncate1(sd,1,g);
2097       rv = (rv<<shift) | stc_truncate1(sd,2,b);
2098    } else {
2099       rv =                stc_truncate(sd,0,r);
2100       rv = (rv<<shift) |  stc_truncate(sd,1,g);
2101       rv = (rv<<shift) |  stc_truncate(sd,2,b);
2102    }
2103 
2104    return rv;
2105 }
2106 
2107 private int
2108 stc_map_color_rgb(gx_device *pdev, gx_color_index color,gx_color_value prgb[3])
2109 {
2110 
2111    stcolor_device *sd = (stcolor_device *) pdev;
2112    int          shift = sd->color_info.depth == 24 ? 8 : sd->stc.bits;
2113    gx_color_index l =   ((gx_color_index)1<<sd->stc.bits)-1;
2114 
2115    prgb[0] = stc_expand(sd,0,((color>>(shift<<1)) & l));
2116    prgb[1] = stc_expand(sd,1,((color>> shift    ) & l));
2117    prgb[2] = stc_expand(sd,2,( color              & l));
2118 
2119    return 0;
2120 }
2121 
2122 /***
2123  *** color-mapping of cmyk-values
2124  ***/
2125 private gx_color_index
2126 stc_map_cmyk_color(gx_device *pdev,
2127         gx_color_value c, gx_color_value m, gx_color_value y,gx_color_value k)
2128 {
2129 
2130    stcolor_device *sd = (stcolor_device *) pdev;
2131    int          shift = sd->color_info.depth == 32 ? 8 : sd->stc.bits;
2132    gx_color_index rv = 0;
2133 
2134    if((c == m) && (m == y)) {
2135 
2136       k = c > k ? c : k;
2137       c = m = y = 0;
2138 
2139       if(( sd->stc.bits                      ==    8) &&
2140       ((sd->stc.dither->flags & STC_TYPE) == STC_BYTE)) {
2141          k  = stc_truncate1(sd,3,k);
2142       } else {
2143          k  =  stc_truncate(sd,3,k);
2144       }
2145 
2146    } else {
2147 
2148       if(sd->stc.am != NULL) {
2149 
2150          float *a,fc,fm,fy,fk,fv;
2151 
2152          if(k == 0) { /* no separated black yet */
2153             k  = c < m ? c : m;
2154             k  = k < y ? k : y;
2155             if(k) { /* no black at all */
2156                c -= k;
2157                m -= k;
2158                y -= k;
2159            }       /* no black at all */
2160          }            /* no separated black yet */
2161 
2162          a  = sd->stc.am;
2163          fc = c; fm = m; fy = y; fk = k;
2164 
2165          fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk;
2166          if(     fv < 0.0)                      c = 0;
2167          else if((fv+0.5) > gx_max_color_value) c = gx_max_color_value;
2168          else                                   c = fv+0.5;
2169 
2170          fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk;
2171          if(     fv < 0.0)                      m = 0;
2172          else if((fv+0.5) > gx_max_color_value) m = gx_max_color_value;
2173          else                                   m = fv+0.5;
2174 
2175          fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk;
2176          if(     fv < 0.0)                      y = 0;
2177          else if((fv+0.5) > gx_max_color_value) y = gx_max_color_value;
2178          else                                   y = fv+0.5;
2179 
2180          fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk;
2181          if(     fv < 0.0)                      k = 0;
2182          else if((fv+0.5) > gx_max_color_value) k = gx_max_color_value;
2183          else                                   k = fv+0.5;
2184 
2185       } else if(k == 0) {
2186 
2187          k  = c < m ? c : m;
2188          k  = k < y ? k : y;
2189       }
2190 
2191       if(( sd->stc.bits                      ==    8) &&
2192          ((sd->stc.dither->flags & STC_TYPE) == STC_BYTE)) {
2193          c = stc_truncate1(sd,0,c);
2194          m = stc_truncate1(sd,1,m);
2195          y = stc_truncate1(sd,2,y);
2196          k = stc_truncate1(sd,3,k);
2197       } else {
2198          c = stc_truncate(sd,0,c);
2199          m = stc_truncate(sd,1,m);
2200          y = stc_truncate(sd,2,y);
2201          k = stc_truncate(sd,3,k);
2202       }
2203    }
2204 
2205    rv =               c;
2206    rv = (rv<<shift) | m;
2207    rv = (rv<<shift) | y;
2208    rv = (rv<<shift) | k;
2209 
2210    if(rv == gx_no_color_index) rv ^= 1;
2211 
2212    return rv;
2213 }
2214 
2215 private int
2216 stc_map_color_cmyk(gx_device *pdev, gx_color_index color,gx_color_value prgb[3])
2217 {
2218 
2219    stcolor_device *sd = (stcolor_device *) pdev;
2220    int          shift = sd->color_info.depth == 32 ? 8 : sd->stc.bits;
2221    gx_color_index   l = ((gx_color_index)1<<sd->stc.bits)-1;
2222    gx_color_value c,m,y,k;
2223 
2224    k = stc_expand(sd,3, color & l); color >>= shift;
2225    y = stc_expand(sd,2, color & l); color >>= shift;
2226    m = stc_expand(sd,1, color & l); color >>= shift;
2227    c = stc_expand(sd,0, color & l);
2228 
2229    if((c == m) && (m == y)) {
2230       prgb[0] = gx_max_color_value-k;
2231       prgb[1] = prgb[0];
2232       prgb[2] = prgb[0];
2233    } else {
2234       prgb[0] = gx_max_color_value-c;
2235       prgb[1] = gx_max_color_value-m;
2236       prgb[2] = gx_max_color_value-y;
2237    }
2238    return 0;
2239 }
2240 
2241 /***
2242  *** color-mapping of cmyk10-values
2243  ***/
2244 private gx_color_index
2245 stc_map_cmyk10_color(gx_device *pdev,
2246         gx_color_value c, gx_color_value m, gx_color_value y,gx_color_value k)
2247 {
2248 
2249    stcolor_device *sd = (stcolor_device *) pdev;
2250    int             mode;
2251    gx_color_index rv  = 0;
2252 
2253    if((c == m) && (m == y)) {
2254 
2255       k = c > k ? c : k;
2256       c = m = y = 0;
2257       mode = 3;
2258 
2259    } else {
2260 
2261       if(sd->stc.am != NULL) {
2262 
2263          float *a,fc,fm,fy,fk,fv;
2264 
2265          k  = c < m ? c : m;
2266          k  = k < y ? k : y;
2267          if(k) { /* no black at all */
2268             c -= k;
2269             m -= k;
2270             y -= k;
2271          }       /* no black at all */
2272 
2273          a  = sd->stc.am;
2274          fc = c; fm = m; fy = y; fk = k;
2275 
2276          fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk;
2277          if(     fv < 0.0)                      c = 0;
2278          else if((fv+0.5) > gx_max_color_value) c = gx_max_color_value;
2279          else                                   c = fv+0.5;
2280 
2281          fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk;
2282          if(     fv < 0.0)                      m = 0;
2283          else if((fv+0.5) > gx_max_color_value) m = gx_max_color_value;
2284          else                                   m = fv+0.5;
2285 
2286          fv = *a++ * fc; fv += *a++ * fm; fv += *a++ * fy; fv += *a++ * fk;
2287          if(     fv < 0.0)                      y = 0;
2288          else if((fv+0.5) > gx_max_color_value) y = gx_max_color_value;
2289          else                                   y = fv+0.5;
2290 
2291       }
2292 
2293       if(c < m) {
2294         if(c < y) { k = c; c = 0; mode = 0; }
2295         else      { k = y; y = 0; mode = 2; }
2296       } else {
2297         if(m < y) { k = m; m = 0; mode = 1; }
2298         else      { k = y; y = 0; mode = 2; }
2299       }
2300    }
2301 
2302 /*
2303  * truncate only the values that require it
2304  */
2305    if(c) c = stc_truncate(sd,0,c);
2306    if(m) m = stc_truncate(sd,1,m);
2307    if(y) y = stc_truncate(sd,2,y);
2308    if(k) k = stc_truncate(sd,3,k);
2309 
2310 /*
2311  * make sure that truncation-white becomes white.
2312  */
2313    if((c|m|y) == 0) mode = 3;
2314 
2315 /*
2316  * check wether value-arrays can be bypassed
2317  */
2318    if(((sd->stc.dither->flags & STC_TYPE) == STC_BYTE) &&
2319       ( sd->stc.dither->minmax[0]         ==    0.0 )) {
2320       c = sd->stc.vals[0][c];
2321       m = sd->stc.vals[1][m];
2322       y = sd->stc.vals[2][y];
2323       k = sd->stc.vals[3][k];
2324    } else if(((sd->stc.dither->flags & STC_TYPE) == STC_LONG) &&
2325              ( sd->stc.dither->minmax[0]         ==     0.0 ) &&
2326              ( sd->stc.dither->minmax[1]         <=  1023.0 )) {
2327       c = ((long *)(sd->stc.vals[0]))[c];
2328       m = ((long *)(sd->stc.vals[1]))[m];
2329       y = ((long *)(sd->stc.vals[2]))[y];
2330       k = ((long *)(sd->stc.vals[3]))[k];
2331    }                                                       /* direct */
2332 /*
2333  * compute the long-representation of gx_color_index
2334  */
2335    switch(mode) {
2336    case 0:
2337       rv = (((gx_color_index) m)<<22)|
2338            (((gx_color_index) y)<<12)|
2339            (((gx_color_index) k)<< 2)|mode;
2340       break;
2341    case 1:
2342       rv = (((gx_color_index) c)<<22)|
2343            (((gx_color_index) y)<<12)|
2344            (((gx_color_index) k)<< 2)|mode;
2345       break;
2346    case 2:
2347       rv = (((gx_color_index) c)<<22)|
2348            (((gx_color_index) m)<<12)|
2349            (((gx_color_index) k)<< 2)|mode;
2350       break;
2351    default:
2352       rv = (((gx_color_index) k)<< 2)|mode;
2353       break;
2354    }
2355 
2356 /*
2357  * We may need some swapping
2358  */
2359 #if !arch_is_big_endian
2360    {
2361       union { stc_pixel cv; byte bv[4]; } ui,uo;
2362       ui.cv = rv;
2363       uo.bv[0] = ui.bv[3];
2364       uo.bv[1] = ui.bv[2];
2365       uo.bv[2] = ui.bv[1];
2366       uo.bv[3] = ui.bv[0];
2367       rv       = uo.cv;
2368    }
2369 #endif
2370    return rv;
2371 }
2372 
2373 private int
2374 stc_map_color_cmyk10(gx_device *pdev, gx_color_index color,
2375                      gx_color_value prgb[3])
2376 {
2377 
2378    stcolor_device *sd = (stcolor_device *) pdev;
2379    gx_color_value c,m,y;
2380 
2381 /*
2382  * We may need some swapping
2383  */
2384 #if !arch_is_big_endian
2385    union { stc_pixel cv; byte bv[4]; } ui,uo;
2386    ui.cv = color;
2387    uo.bv[0] = ui.bv[3];
2388    uo.bv[1] = ui.bv[2];
2389    uo.bv[2] = ui.bv[1];
2390    uo.bv[3] = ui.bv[0];
2391    color    = uo.cv;
2392 #endif
2393 
2394    c    =   stc_expand(sd,3,(color>>2)&0x3ff);
2395 
2396    switch(color & 3) {
2397      case 0:
2398         m = stc_expand(sd,1,(color>>22) & 0x3ff);
2399         y = stc_expand(sd,2,(color>>12) & 0x3ff);
2400         break;
2401      case 1:
2402         m = c;
2403         c = stc_expand(sd,0,(color>>22) & 0x3ff);
2404         y = stc_expand(sd,2,(color>>12) & 0x3ff);
2405         break;
2406      case 2:
2407         y = c;
2408         c = stc_expand(sd,0,(color>>22) & 0x3ff);
2409         m = stc_expand(sd,1,(color>>12) & 0x3ff);
2410         break;
2411      default:
2412         m = c;
2413         y = c;
2414         break;
2415    }
2416 
2417    prgb[0] = gx_max_color_value - c;
2418    prgb[1] = gx_max_color_value - m;
2419    prgb[2] = gx_max_color_value - y;
2420 
2421    return 0;
2422 }
2423 
2424 /***
2425  *** Macros for parameter-handling
2426  ***/
2427 
2428 #define set_param_array(A, D, S)\
2429     {A.data = D; A.size = S; A.persistent = false;}
2430 
2431 #define stc_write_null(N)                        \
2432     set_param_array(pfa,defext,countof(defext))  \
2433     code = param_write_null(plist,N);            \
2434     if (code < 0) return code;
2435 
2436 #define stc_write_xarray(I,Coding,Transfer)                  \
2437     if(sd->stc.sizc[I] > 0) {                                \
2438        set_param_array(pfa, sd->stc.extc[I],sd->stc.sizc[I]) \
2439        code = param_write_float_array(plist,Coding,&pfa);    \
2440     } else {                                                 \
2441        code = param_write_null(plist,Coding);                \
2442     }                                                        \
2443     if ( code < 0 ) return code;                             \
2444                                                              \
2445     if(sd->stc.sizv[I] > 0)                                  \
2446        set_param_array(pfa, sd->stc.extv[I],sd->stc.sizv[I]) \
2447     else                                                     \
2448        set_param_array(pfa,defext,countof(defext))           \
2449     code = param_write_float_array(plist,Transfer,&pfa);     \
2450     if ( code < 0 ) return code;
2451 
2452 #define stc_read_null(N)                                   \
2453     code = param_read_null(plist,N);                       \
2454     if(code == gs_error_typecheck)                         \
2455        code = param_read_float_array(plist,N,&pfa);        \
2456     if(code < 0) param_signal_error(plist,N,code);         \
2457     error = error > code ? code : error;
2458 
2459 #define stc_read_xarray(I,Coding,Transfer)                 \
2460     code = param_read_float_array(plist,Coding,&pfa);      \
2461     if((error == 0) && (code == 0)) {                      \
2462        if(pfa.size > 1) {                                  \
2463           sd->stc.extc[I] = (float *) pfa.data;            \
2464           sd->stc.sizc[I] = pfa.size;                      \
2465        } else {                                            \
2466           code = gs_error_rangecheck;                      \
2467        }                                                   \
2468     } else if(code < 0) {                                  \
2469        code = param_read_null(plist,Coding);               \
2470        if(code == 0) {                                     \
2471           sd->stc.extc[I] = NULL;                          \
2472           sd->stc.sizc[I] = 0;                             \
2473        }                                                   \
2474     }                                                      \
2475     if(code < 0) param_signal_error(plist,Coding,code);    \
2476     error = error > code ? code : error;                   \
2477     code = param_read_float_array(plist,Transfer,&pfa);    \
2478     if((error == 0) && (code == 0)) {                      \
2479        sd->stc.extv[I] = (float *) pfa.data;               \
2480        sd->stc.sizv[I] = pfa.size;                         \
2481     } else if(code < 0) {                                  \
2482        code = param_read_null(plist,Transfer);             \
2483        if(code == 0) {                                     \
2484           sd->stc.extv[I] = defext;                        \
2485           sd->stc.sizv[I] = countof(defext);               \
2486        }                                                   \
2487     }                                                      \
2488     if(code < 0) param_signal_error(plist,Transfer,code);  \
2489     error = error > code ? code : error;
2490 
2491 /***
2492  *** Get parameters == Make them accessable via PostScript
2493  ***/
2494 
2495 private int
2496 stc_get_params(gx_device *pdev, gs_param_list *plist)
2497 {
2498    int code,nc;
2499    gs_param_string      ps;
2500    gs_param_float_array pfa;
2501    bool btmp;
2502    stcolor_device *sd = (stcolor_device *) pdev;
2503 
2504    code = gdev_prn_get_params(pdev, plist);
2505    if ( code < 0 ) return code;
2506 
2507 /*
2508  * Export some readonly-Parameters, used by stcinfo.ps
2509  */
2510    param_string_from_string(ps,"1.91");
2511    code = param_write_string(plist,"Version",&ps);
2512    if ( code < 0 ) return code;
2513 
2514    code = param_write_int(plist,"BitsPerComponent",&sd->stc.bits);
2515    if ( code < 0 ) return code;
2516 
2517    if(sd->stc.algorithms.size > 0) {
2518      code = param_write_string_array(plist,"Algorithms",&sd->stc.algorithms);
2519    } else {
2520      code = param_write_null(plist,"Algorithms");
2521    }
2522    if ( code < 0 ) return code;
2523 
2524 /*
2525  * Export OutputCode
2526  */
2527    switch(sd->stc.flags & STCCOMP) {
2528    case STCPLAIN: param_string_from_string(ps,"plain");     break;
2529    case STCDELTA: param_string_from_string(ps,"deltarow");  break;
2530    default:       param_string_from_string(ps,"runlength"); break;
2531    }
2532    code = param_write_string(plist,"OutputCode",&ps);
2533    if ( code < 0 ) return code;
2534 /*
2535  * Export Model
2536  */
2537    switch(sd->stc.flags & STCMODEL) {
2538    case STCST800: param_string_from_string(ps,"st800");   break;
2539    case STCSTCII: param_string_from_string(ps,"stcii");   break;
2540    default:       param_string_from_string(ps,"stc");     break;
2541    }
2542    code = param_write_string(plist,"Model",&ps);
2543    if ( code < 0 ) return code;
2544 
2545 /*
2546  * Export the booleans
2547  */
2548 #define stc_write_flag(Mask,Name)                \
2549    btmp = sd->stc.flags & (Mask) ? true : false; \
2550    code = param_write_bool(plist,Name,&btmp);    \
2551    if ( code < 0 ) return code;
2552 
2553    stc_write_flag(STCUNIDIR,"Unidirectional")
2554    stc_write_flag(STCUWEAVE,"Microweave")
2555    btmp = sd->stc.flags & (STCUNIDIR|STCUWEAVE) ? false : true;
2556    code = param_write_bool(plist,"Softweave",&btmp);
2557    if ( code < 0 ) return code;
2558    stc_write_flag(STCNWEAVE,"noWeave")
2559    stc_write_flag(STCDFLAG0, "Flag0")
2560    stc_write_flag(STCDFLAG1, "Flag1")
2561    stc_write_flag(STCDFLAG2, "Flag2")
2562    stc_write_flag(STCDFLAG3, "Flag3")
2563    stc_write_flag(STCDFLAG4, "Flag4")
2564 
2565 #undef stc_write_flag
2566 
2567 #  define stc_write_int(Mask,Name,Val)         \
2568       code = param_write_int(plist,Name,&Val); \
2569       if ( code < 0 ) return code
2570 
2571    stc_write_int(STCBAND,  "escp_Band",  sd->stc.escp_m);
2572    stc_write_int(STCWIDTH, "escp_Width", sd->stc.escp_width);
2573    stc_write_int(STCHEIGHT,"escp_Height",sd->stc.escp_height);
2574    stc_write_int(STCTOP,   "escp_Top",   sd->stc.escp_top);
2575    stc_write_int(STCBOTTOM,"escp_Bottom",sd->stc.escp_bottom);
2576 
2577 #  undef stc_write_int
2578 
2579    code = param_write_string(plist,"escp_Init",&sd->stc.escp_init);
2580    code = param_write_string(plist,"escp_Release",&sd->stc.escp_release);
2581 
2582    if(sd->stc.dither != NULL) {
2583       param_string_from_string(ps,sd->stc.dither->name);
2584       code = param_write_string(plist,"Dithering",&ps);
2585    } else {
2586       code = param_write_null(plist,"Dithering");
2587    }
2588    if ( code < 0 ) return code;
2589 
2590    nc = sd->color_info.num_components;
2591 
2592    if(sd->stc.am != NULL) {
2593       if(     nc == 1) set_param_array(pfa, sd->stc.am, 3)
2594       else if(nc == 3) set_param_array(pfa, sd->stc.am, 9)
2595       else             set_param_array(pfa, sd->stc.am,16)
2596       code = param_write_float_array(plist,"ColorAdjustMatrix",&pfa);
2597    } else {
2598       code = param_write_null(plist,"ColorAdjustMatrix");
2599    }
2600    if ( code < 0 ) return code;
2601 
2602    if(nc == 1) {        /* DeviceGray */
2603 
2604       stc_write_xarray(0,"Kcoding","Ktransfer");
2605 
2606       stc_write_null("Rcoding"); stc_write_null("Rtransfer");
2607       stc_write_null("Gcoding"); stc_write_null("Gtransfer");
2608       stc_write_null("Bcoding"); stc_write_null("Btransfer");
2609 
2610       stc_write_null("Ccoding"); stc_write_null("Ctransfer");
2611       stc_write_null("Mcoding"); stc_write_null("Mtransfer");
2612       stc_write_null("Ycoding"); stc_write_null("Ytransfer");
2613 
2614    } else if(nc == 3) { /* DeviceRGB */
2615 
2616       stc_write_xarray(0,"Rcoding","Rtransfer");
2617       stc_write_xarray(1,"Gcoding","Gtransfer");
2618       stc_write_xarray(2,"Bcoding","Btransfer");
2619 
2620       stc_write_null("Ccoding"); stc_write_null("Ctransfer");
2621       stc_write_null("Mcoding"); stc_write_null("Mtransfer");
2622       stc_write_null("Ycoding"); stc_write_null("Ytransfer");
2623       stc_write_null("Kcoding"); stc_write_null("Ktransfer");
2624 
2625    } else {             /* DeviceCMYK */
2626 
2627       stc_write_xarray(0,"Ccoding","Ctransfer");
2628       stc_write_xarray(1,"Mcoding","Mtransfer");
2629       stc_write_xarray(2,"Ycoding","Ytransfer");
2630       stc_write_xarray(3,"Kcoding","Ktransfer");
2631 
2632       stc_write_null("Rcoding"); stc_write_null("Rtransfer");
2633       stc_write_null("Gcoding"); stc_write_null("Gtransfer");
2634       stc_write_null("Bcoding"); stc_write_null("Btransfer");
2635 
2636    }
2637    return code;
2638 }
2639 
2640 /***
2641  *** put parameters == Store them in the device-structure
2642  ***/
2643 
2644 private int
2645 stc_put_params(gx_device *pdev, gs_param_list *plist)
2646 {
2647    int code,error,i,l;
2648    bool b1,b2,b3;
2649    float fv,*fp;
2650    gs_param_string      ps;
2651    gs_param_string_array psa;
2652    gs_param_float_array pfa;
2653    stcolor_device *sd = (stcolor_device *) pdev;
2654    gx_device_color_info oldcolor;
2655    stc_t                oldstc;
2656 
2657 /*
2658  * save old Values
2659  */
2660    memcpy(&oldcolor,&sd->color_info,sizeof(oldcolor));
2661    memcpy(&oldstc  ,&sd->stc       ,sizeof(oldstc  ));
2662 
2663 /*
2664  * Arrrgh:
2665  * With Version 3.4x and above my simple minded read-only Parameters
2666  * do not work any more. So read them here for heavens sake.
2667  */
2668    code = param_read_string(plist,"Version",&ps);
2669    code = param_read_int(plist,"BitsPerComponent",&i);
2670    code = param_read_string_array(plist,"Algorithms",&psa);
2671 
2672 /*
2673  * Fetch Major-Parameters (Model, Dithering, BitsPerPixel/BitsPerComponent)
2674  */
2675    error = 0;
2676 
2677    code  = param_read_string(plist,"Model",&ps);
2678    if(code == 0) {   /* Analyze the Model-String */
2679 /*
2680  * Arrgh: I should have known, that internal strings are not zero-terminated.
2681  */
2682       for(l = ps.size; (l > 0) && (ps.data[l-1] == 0); --l);
2683 #     define stc_putcmp(Name) \
2684         ((strlen(Name) != l) || (0 != strncmp(Name, (const char *)ps.data,l)))
2685 
2686       sd->stc.flags &= ~STCMODEL;
2687       if(     !stc_putcmp("st800"))  sd->stc.flags |= STCST800;
2688       else if(!stc_putcmp("stcii"))  sd->stc.flags |= STCSTCII;
2689 
2690    }                 /* Analyze the Model-String */
2691    if(code < 0) param_signal_error(plist,"Model",code);
2692    error = error > code ? code : error;
2693 
2694 /* If we're running for st800, #components must be 1 */
2695    if(((sd->stc.flags & STCMODEL) == STCST800) &&
2696       (( sd->color_info.num_components > 1) ||
2697        ( sd->stc.dither                == NULL) ||
2698        ((sd->stc.dither->flags & 7)    > 1))) {
2699         sd->color_info.num_components  = 1;
2700         sd->stc.dither = NULL;
2701     }
2702 
2703 /* Weaving isn't a feature for the st800 */
2704    if((sd->stc.flags & STCMODEL) == STCST800) {
2705       sd->stc.flags &= ~STCUWEAVE;
2706       sd->stc.flags |=  STCNWEAVE;
2707    } else if((sd->stc.flags & STCMODEL) == STCSTCII) { /* no SoftWeave */
2708       sd->stc.flags |=  STCNWEAVE;
2709    }
2710 
2711    code  = param_read_string(plist,"Dithering",&ps);
2712    if(code == 0) {                     /* lookup new value new value */
2713 
2714       for(l = ps.size; (l > 0) && (ps.data[l-1] == 0); --l);
2715 
2716       for(i = 0; stc_dither[i].name != NULL; ++i)
2717          if(!stc_putcmp(stc_dither[i].name)) break;
2718 
2719    } else if(sd->stc.dither != NULL) {  /* compute index of given value */
2720 
2721       i = sd->stc.dither - stc_dither;
2722 
2723    } else {                            /* find matching value */
2724 
2725       for(i = 0; stc_dither[i].name != NULL; ++i)
2726          if((stc_dither[i].flags & 7) == sd->color_info.num_components) break;
2727 
2728    }                                   /* we've got an index */
2729 
2730    if(stc_dither[i].name != NULL) { /* establish data */
2731 
2732 /*
2733  * Establish new dithering algorithm & color-model
2734  */
2735       sd->stc.dither                = stc_dither+i;
2736       sd->color_info.num_components = sd->stc.dither->flags & 7;
2737   STC_TYPESWITCH(sd->stc.dither,stc_sizeofitem)
2738 # undef stc_sizeofitem
2739       if(((sd->stc.flags & STCMODEL)    == STCST800) &&
2740          ( sd->color_info.num_components > 1       ))
2741          code = gs_error_rangecheck;
2742 
2743 /*
2744  * reset Parameters related to the color-model, if it changed
2745  */
2746 
2747       if(sd->color_info.num_components != oldcolor.num_components) {
2748 
2749          for(i = 0; i < sd->color_info.num_components; ++i) {
2750             sd->stc.extv[i]   = (float *) defext;
2751             sd->stc.sizv[i]   = countof(defext);
2752 
2753             sd->stc.extc[i] = NULL;
2754             sd->stc.sizc[i] = 0;
2755 
2756          }
2757 
2758          sd->stc.am = NULL;
2759 
2760       } else { /* guarantee, that extvals is present */
2761 
2762          for(i = 0; i < sd->color_info.num_components; ++i) {
2763             if(sd->stc.sizv[i] < 2) {
2764                sd->stc.extv[i]   = (float *) defext;
2765                sd->stc.sizv[i]   = countof(defext);
2766             }
2767          }
2768       }
2769 
2770       for(i = sd->color_info.num_components; i < 4; ++ i) { /* clear unused */
2771          sd->stc.extv[i]   = NULL;
2772          sd->stc.sizv[i]   = 0;
2773          sd->stc.vals[i]   = NULL;
2774 
2775          sd->stc.extc[i] = NULL;
2776          sd->stc.sizc[i] = 0;
2777          sd->stc.code[i] = NULL;
2778 
2779       }                                                     /* clear unused */
2780 
2781 /*
2782  * Guess default depth from range of values
2783  */
2784       if((sd->stc.dither != oldstc.dither)||(oldstc.vals[0] == NULL)) {
2785 
2786          if((sd->stc.dither->flags & STC_CMYK10) != 0) {
2787 
2788             sd->stc.flags       |= STCCMYK10;
2789             sd->stc.bits         = 10;
2790             sd->color_info.depth = 32;
2791 
2792          } else {
2793 
2794             sd->stc.flags       &= ~STCCMYK10;
2795 
2796             if((sd->stc.dither->flags & STC_FLOAT) != STC_FLOAT) {
2797                fv = 2.0;
2798                for(i = 1;(i  < gx_color_value_bits) &&
2799                   (fv <= (sd->stc.dither->minmax[1]-sd->stc.dither->minmax[0]));
2800                  ++i) fv *= 2.0;
2801 
2802             } else {
2803                i = 8; /* arbitrary */
2804             }
2805 
2806             if((i*sd->color_info.num_components) > (sizeof(stc_pixel)*8)) {
2807 
2808                sd->stc.bits         = (sizeof(stc_pixel)*8) /
2809                                        sd->color_info.num_components;
2810                sd->color_info.depth = sd->stc.bits * sd->color_info.num_components;
2811 
2812             } else {
2813 
2814                sd->stc.bits         = i;
2815                sd->color_info.depth = sd->stc.bits * sd->color_info.num_components;
2816 
2817             }
2818          }
2819       }
2820 
2821    } else {
2822 
2823       code = gs_error_rangecheck;
2824 
2825    }               /* verify new value */
2826    if(code < 0) param_signal_error(plist,"Dithering",code);
2827    error = error > code ? code : error;
2828 
2829 /*
2830  * now fetch the desired depth, if the algorithm allows it
2831  */
2832 /*
2833  * Arrrgh: We get code == 0, even if nobody sets BitsPerPixel.
2834  *         The value is the old one, but this may cause trouble
2835  *         with CMYK10.
2836  */
2837    code = param_read_int(plist, "BitsPerPixel", &i);
2838    if((error == 0) && (code == 0) &&
2839       (((sd->stc.flags & STCCMYK10) == 0) || (i != sd->color_info.depth))) {
2840 
2841       if((1 > i) || (i > (sizeof(stc_pixel)*8)))
2842          code = gs_error_rangecheck;
2843       else
2844          sd->color_info.depth = i;
2845 
2846       sd->stc.bits = i / sd->color_info.num_components;
2847 
2848       if(1 > sd->stc.bits) code = gs_error_rangecheck;
2849 
2850       if((sd->stc.dither->flags & STC_DIRECT) &&
2851          (sd->stc.dither->flags & STC_CMYK10))
2852          code           = gs_error_rangecheck;
2853       else
2854          sd->stc.flags &= ~STCCMYK10;
2855 
2856    }
2857    if(code < 0) param_signal_error(plist,"BitsPerPixel",code);
2858    error = error > code ? code : error;
2859 
2860 /*
2861  * Fetch OutputCode
2862  */
2863    code  = param_read_string(plist,"OutputCode",&ps);
2864    if(code == 0) {   /* Analyze the OutputCode-String */
2865 
2866       for(l = ps.size; (l > 0) && (ps.data[l-1] == 0); --l);
2867 
2868       sd->stc.flags &= ~STCCOMP;
2869       if(!stc_putcmp("plain"))         sd->stc.flags |= STCPLAIN;
2870       else if(!stc_putcmp("deltarow")) sd->stc.flags |= STCDELTA;
2871 
2872    }                 /* Analyze the OutputCode-String */
2873    if((sd->stc.flags & STCCOMP) == STCDELTA) {
2874       sd->stc.flags |=  STCUWEAVE;
2875       sd->stc.flags &= ~STCNWEAVE;
2876    }
2877    if(code < 0) param_signal_error(plist,"OutputCode",code);
2878    error = error > code ? code : error;
2879 
2880 /*
2881  * fetch the weave-mode (noWeave wins)
2882  */
2883    b1 = sd->stc.flags & STCUWEAVE ? true : false;
2884    b2 = sd->stc.flags & STCNWEAVE ? true : false;
2885    b3 = sd->stc.flags & (STCUWEAVE|STCNWEAVE) ? false : true;
2886 
2887    code = param_read_bool(plist,"Microweave",&b1);
2888    if(code < 0) {
2889       param_signal_error(plist,"Microweave",code);
2890    } else if(code == 0) {
2891       if(b1) { b2 = false; b3 = false; }
2892    }
2893    error = error > code ? code : error;
2894 
2895    code = param_read_bool(plist,"noWeave",&b2);
2896    if(code < 0) {
2897       param_signal_error(plist,"noWeave",code);
2898    } else if (code == 0) {
2899       if(b2) { b1 = false; b3 = false; }
2900    }
2901    error = error > code ? code : error;
2902 
2903    code = param_read_bool(plist,"Softweave",&b3);
2904    if(code < 0) {
2905       param_signal_error(plist,"Softweave",code);
2906    } else if (code == 0) {
2907       if(b3) { b1 = false; b2 = false; }
2908    }
2909    error = error > code ? code : error;
2910 
2911    if(b1) sd->stc.flags |=  STCUWEAVE;
2912    else   sd->stc.flags &= ~STCUWEAVE;
2913 
2914    if(b2) sd->stc.flags |=  STCNWEAVE;
2915    else   sd->stc.flags &= ~STCNWEAVE;
2916 
2917 /*
2918  * Check the simple Flags
2919  */
2920 #  define stc_read_flag(Mask,Name)                \
2921       code = param_read_bool(plist,Name,&b1);     \
2922       if(code < 0) {                              \
2923          param_signal_error(plist,Name,code);     \
2924       } else if(code == 0) {                      \
2925          if(b1 == true) sd->stc.flags |=  Mask;   \
2926          else           sd->stc.flags &= ~(Mask); \
2927       }                                           \
2928       error = error > code ? code : error;
2929 
2930    stc_read_flag(STCUNIDIR,"Unidirectional")
2931    stc_read_flag(STCDFLAG0, "Flag0")
2932    stc_read_flag(STCDFLAG1, "Flag1")
2933    stc_read_flag(STCDFLAG2, "Flag2")
2934    stc_read_flag(STCDFLAG3, "Flag3")
2935    stc_read_flag(STCDFLAG4, "Flag4")
2936 
2937 /*
2938  * Now deal with the escp-Stuff
2939  */
2940 #  define stc_read_int(Mask,Name,Val)             \
2941       code = param_read_int(plist,Name,&Val);     \
2942       if(code < 0)                                \
2943          param_signal_error(plist,Name,code);     \
2944       else if(code == 0)                          \
2945          sd->stc.flags |= Mask;                   \
2946       error = error > code ? code : error
2947 
2948    stc_read_int(STCBAND,  "escp_Band",  sd->stc.escp_m);
2949    stc_read_int(STCWIDTH, "escp_Width", sd->stc.escp_width);
2950    stc_read_int(STCHEIGHT,"escp_Height",sd->stc.escp_height);
2951    stc_read_int(STCTOP,   "escp_Top",   sd->stc.escp_top);
2952    stc_read_int(STCBOTTOM,"escp_Bottom",sd->stc.escp_bottom);
2953 
2954 #  undef stc_read_int
2955 
2956    code = param_read_string(plist,"escp_Init",&sd->stc.escp_init);
2957    if(code == 0) sd->stc.flags |= STCINIT;
2958    error = error > code ? code : error;
2959 
2960    code = param_read_string(plist,"escp_Release",&sd->stc.escp_release);
2961    if(code == 0) sd->stc.flags |= STCRELEASE;
2962    error = error > code ? code : error;
2963 
2964 /*
2965  * ColorAdjustMatrix must match the required size,
2966  * setting it explicitly to null, erases old matrix
2967  */
2968    code = param_read_float_array(plist,"ColorAdjustMatrix",&pfa);
2969    if((error == 0) && (code == 0)) {
2970       if(((sd->color_info.num_components == 1) && (pfa.size ==  3)) ||
2971          ((sd->color_info.num_components == 3) && (pfa.size ==  9)) ||
2972          ((sd->color_info.num_components == 4) && (pfa.size == 16)))
2973          sd->stc.am = (float *) pfa.data;
2974       else
2975          code =  gs_error_rangecheck;
2976    } else if(code < 0) {
2977       code = param_read_null(plist,"ColorAdjustMatrix");
2978       if(code == 0) sd->stc.am = NULL;
2979    }
2980    if(code < 0) param_signal_error(plist,"ColorAdjustMatrix",code);
2981    error = error > code ? code : error;
2982 
2983 /*
2984  * Read the external array-Parameters
2985  */
2986    if(sd->color_info.num_components == 1) {        /* DeviceGray */
2987 
2988       stc_read_xarray(0,"Kcoding","Ktransfer");
2989 
2990       stc_read_null("Rcoding"); stc_read_null("Rtransfer");
2991       stc_read_null("Gcoding"); stc_read_null("Gtransfer");
2992       stc_read_null("Bcoding"); stc_read_null("Btransfer");
2993 
2994       stc_read_null("Ccoding"); stc_read_null("Ctransfer");
2995       stc_read_null("Mcoding"); stc_read_null("Mtransfer");
2996       stc_read_null("Ycoding"); stc_read_null("Ytransfer");
2997 
2998    } else if(sd->color_info.num_components == 3) { /* DeviceRGB */
2999 
3000       stc_read_xarray(0,"Rcoding","Rtransfer");
3001       stc_read_xarray(1,"Gcoding","Gtransfer");
3002       stc_read_xarray(2,"Bcoding","Btransfer");
3003 
3004       stc_read_null("Ccoding"); stc_read_null("Ctransfer");
3005       stc_read_null("Mcoding"); stc_read_null("Mtransfer");
3006       stc_read_null("Ycoding"); stc_read_null("Ytransfer");
3007       stc_read_null("Kcoding"); stc_read_null("Ktransfer");
3008 
3009    } else {                                        /* DeviceCMYK */
3010 
3011       stc_read_xarray(0,"Ccoding","Ctransfer");
3012       stc_read_xarray(1,"Mcoding","Mtransfer");
3013       stc_read_xarray(2,"Ycoding","Ytransfer");
3014       stc_read_xarray(3,"Kcoding","Ktransfer");
3015 
3016       stc_read_null("Rcoding"); stc_read_null("Rtransfer");
3017       stc_read_null("Gcoding"); stc_read_null("Gtransfer");
3018       stc_read_null("Bcoding"); stc_read_null("Btransfer");
3019 
3020    }
3021 /*
3022  * Update remaining color_info values
3023  */
3024    if(error == 0) {
3025 
3026 /*    compute #values from the component-bits */
3027       sd->color_info.max_gray  = sd->stc.bits < gx_color_value_bits ?
3028                             (1<<sd->stc.bits)-1 : gx_max_color_value;
3029 
3030 /*    An integer-algorithm might reduce the number of values */
3031       if(((sd->stc.dither->flags & STC_TYPE) != STC_FLOAT) &&
3032          ((sd->stc.dither->minmax[1]-sd->stc.dither->minmax[0]) <
3033            sd->color_info.max_gray))
3034          sd->color_info.max_gray =
3035                 sd->stc.dither->minmax[1]-sd->stc.dither->minmax[0]+0.5;
3036 
3037       sd->color_info.max_color = sd->color_info.num_components < 3 ? 0 :
3038                                  sd->color_info.max_gray;
3039       sd->color_info.dither_grays =
3040           sd->color_info.max_gray < gx_max_color_value ?
3041           sd->color_info.max_gray+1  : gx_max_color_value;
3042       sd->color_info.dither_colors  = sd->color_info.num_components < 3 ? 0 :
3043           sd->color_info.dither_grays;
3044    }
3045 
3046 /*
3047  * Call superclass-Update
3048  */
3049 
3050    code = gdev_prn_put_params(pdev, plist);
3051    error = error > code ? code : error;
3052 
3053 /*
3054  * Arrrgh, writing BitsPerPixel is really *VERY* special:
3055  *    gdev_prn_put_params verifies, that the external value
3056  *    is written, if not, it raises a rangecheck-error.
3057  *    On the other hand ghostscript is quite unhappy with odd
3058  *    values, so we do the necessary rounding *AFTER* the
3059  *    "superclass-Update".
3060  */
3061 
3062    if(sd->color_info.depth ==  3) sd->color_info.depth = 4;
3063    else if(sd->color_info.depth > 4)
3064       sd->color_info.depth =  (sd->color_info.depth+7) & ~7;
3065 
3066 /*
3067  * Allocate the storage for the arrays in memory
3068  */
3069    if(error == 0) { /* Allocate new external-arrays */
3070 
3071      for(i = 0; i < sd->color_info.num_components; ++i){ /* Active components */
3072         int j;
3073 
3074         if((sd->stc.extv[i] != oldstc.extv[i]) &&
3075            (sd->stc.extv[i] != defext        )) { /* Value-Arrays */
3076 
3077            for(j = 0; j < i; ++j)
3078               if((sd->stc.sizv[j] == sd->stc.sizv[i]) &&
3079                  (memcmp(sd->stc.extv[j],sd->stc.extv[i],
3080                          sd->stc.sizv[i]*sizeof(float)) == 0)) break;
3081 
3082            if(j < i) {
3083               sd->stc.extv[i] = sd->stc.extv[j];
3084            } else {
3085               fp = gs_malloc(sd->stc.sizv[i],sizeof(float),"stc_put_params");
3086               if(fp != NULL)
3087                  memcpy(fp,sd->stc.extv[i],sd->stc.sizv[i]*sizeof(float));
3088                else
3089                  code = gs_error_VMerror;
3090                sd->stc.extv[i] = fp;
3091            }
3092         }                                         /* Value-Arrays */
3093 
3094         if((sd->stc.sizc[i] > 1) &&
3095            (sd->stc.extc[i] != oldstc.extc[i])) { /* Code-Arrays */
3096 
3097            for(j = 0; j < i; ++j)
3098               if((sd->stc.sizc[j] == sd->stc.sizc[i]) &&
3099                  (memcmp(sd->stc.extc[j],sd->stc.extc[i],
3100                          sd->stc.sizc[i]*sizeof(float)) == 0)) break;
3101 
3102            if(j < i) {
3103               sd->stc.extc[i] = sd->stc.extc[j];
3104            } else {
3105               fp = gs_malloc(sd->stc.sizc[i],sizeof(float),"stc_put_params");
3106               if(fp != NULL)
3107                  memcpy(fp,sd->stc.extc[i],sd->stc.sizc[i]*sizeof(float));
3108                else
3109                  code = gs_error_VMerror;
3110                sd->stc.extc[i] = fp;
3111            }
3112         }                                         /* Code-Arrays */
3113 
3114      }                                                   /* Active components */
3115 
3116      if((sd->stc.am != NULL) && (sd->stc.am != oldstc.am)) {
3117         if(     sd->color_info.num_components == 1) i =  3;
3118         else if(sd->color_info.num_components == 3) i =  9;
3119         else                                        i = 16;
3120         fp = gs_malloc(i,sizeof(float),"stc_put_params");
3121         if(fp != NULL) memcpy(fp,sd->stc.am,i*sizeof(float));
3122         else           code = gs_error_VMerror;
3123         sd->stc.am = fp;
3124      }
3125 
3126      if(sd->stc.escp_init.data != oldstc.escp_init.data) {
3127         byte *ip = NULL;
3128 
3129         if(sd->stc.escp_init.size > 0) {
3130            ip = gs_malloc(sd->stc.escp_init.size,1,"stcolor/init");
3131            if(ip == NULL) {
3132               code = gs_error_VMerror;
3133               sd->stc.escp_init.size = 0;
3134            } else {
3135               memcpy(ip,sd->stc.escp_init.data,sd->stc.escp_init.size);
3136            }
3137         }
3138         sd->stc.escp_init.data       = ip;
3139         sd->stc.escp_init.persistent = false;
3140      }
3141 
3142      if(sd->stc.escp_release.data != oldstc.escp_release.data) {
3143         byte *ip = NULL;
3144 
3145         if(sd->stc.escp_release.size > 0) {
3146            ip = gs_malloc(sd->stc.escp_release.size,1,"stcolor/release");
3147            if(ip == NULL) {
3148               code = gs_error_VMerror;
3149               sd->stc.escp_release.size = 0;
3150            } else {
3151               memcpy(ip,sd->stc.escp_release.data,sd->stc.escp_release.size);
3152            }
3153         }
3154         sd->stc.escp_release.data       = ip;
3155         sd->stc.escp_release.persistent = false;
3156      }
3157 
3158      if(code < 0) { /* free newly allocated arrays */
3159 
3160         if((sd->stc.am != NULL) && (sd->stc.am != oldstc.am)) {
3161            if(     sd->color_info.num_components == 1) i =  3;
3162            else if(sd->color_info.num_components == 3) i =  9;
3163            else                                        i = 16;
3164            gs_free(sd->stc.am,i,sizeof(float),"stc_put_params");
3165         }
3166 
3167         if((sd->stc.escp_init.data != NULL) &&
3168            (sd->stc.escp_init.data != oldstc.escp_init.data))
3169            gs_free((byte *) sd->stc.escp_init.data,sd->stc.escp_init.size,1,
3170               "stcolor/init");
3171 
3172         if((sd->stc.escp_release.data != NULL) &&
3173            (sd->stc.escp_release.data != oldstc.escp_release.data))
3174            gs_free((byte *) sd->stc.escp_release.data,sd->stc.escp_release.
3175               size,1,"stcolor/release");
3176 
3177         for(i = 0; i < sd->color_info.num_components; ++i) { /* components */
3178            int j;
3179 
3180            if((sd->stc.extc[i] != NULL) &&
3181               (sd->stc.extc[i] != defext) &&
3182               (sd->stc.extc[i] != oldstc.extc[i])) {
3183 
3184               for(j = 0; j < i; ++j)
3185                  if(sd->stc.extc[i] == sd->stc.extc[j]) break;
3186 
3187               if(i == j) gs_free(sd->stc.extc[i],sd->stc.sizc[i],sizeof(float),
3188                             "stc_put_params");
3189            }
3190 
3191            if((sd->stc.extv[i] != NULL) &&
3192               (sd->stc.extv[i] != oldstc.extv[i]) &&
3193               (sd->stc.extv[i] != defext)) {
3194 
3195               for(j = 0; j < i; ++j)
3196                  if(sd->stc.extv[i] == sd->stc.extv[j]) break;
3197 
3198               if(i == j) gs_free(sd->stc.extv[i],sd->stc.sizv[i],sizeof(float),
3199                             "stc_put_params");
3200            }
3201         }                                                    /* components */
3202      }              /* free newly allocated arrays */
3203    }                /* Allocate new arrays */
3204    error = error > code ? code : error;
3205 
3206 /*
3207  * finally decide upon restore or release of old, unused data
3208  */
3209    if(error != 0) { /* Undo changes */
3210 
3211       memcpy(&sd->color_info,&oldcolor,sizeof(oldcolor));
3212       memcpy(&sd->stc       ,&oldstc  ,sizeof(oldstc  ));
3213    } else {        /* undo / release */
3214 
3215       if((oldstc.escp_init.data != NULL) &&
3216          (oldstc.escp_init.data != sd->stc.escp_init.data)) {
3217             gs_free((byte *)oldstc.escp_init.data,
3218                             oldstc.escp_init.size,1,"stcolor/init");
3219       }
3220 
3221       if((oldstc.escp_release.data != NULL) &&
3222          (oldstc.escp_release.data != sd->stc.escp_release.data)) {
3223             gs_free((byte *)oldstc.escp_release.data,
3224                             oldstc.escp_release.size,1,"stcolor/release");
3225       }
3226 
3227       if((oldstc.am != NULL) && (oldstc.am != sd->stc.am)) {
3228          if(     oldcolor.num_components == 1) i =  3;
3229          else if(oldcolor.num_components == 3) i =  9;
3230          else                                  i = 16;
3231          gs_free(oldstc.am,i,sizeof(float),"stc_put_params");
3232       }
3233 
3234       for(i = 0; i < 4; ++i) {
3235          int j;
3236 
3237          if((oldstc.extc[i] != NULL) &&
3238             (oldstc.extc[i] != sd->stc.extc[i]) &&
3239             (oldstc.dither  != NULL) &&
3240             (oldstc.extc[i] != defext)) {
3241 
3242             for(j = 0; j < i; ++j) if(oldstc.extc[i] == oldstc.extc[j]) break;
3243 
3244             if(i == j) gs_free(oldstc.extc[i],oldstc.sizc[i],sizeof(float),
3245                             "stc_put_params");
3246          }
3247 
3248          if((oldstc.extv[i] != NULL) &&
3249             (oldstc.extv[i] != sd->stc.extv[i]) &&
3250             (oldstc.extv[i] != defext)) {
3251 
3252             for(j = 0; j < i; ++j) if(oldstc.extv[i] == oldstc.extv[j]) break;
3253 
3254             if(i == j) gs_free(oldstc.extv[i],oldstc.sizv[i],sizeof(float),
3255                             "stc_put_params");
3256          }
3257       }
3258 
3259 /*
3260  * Close the device if colormodel changed or recomputation
3261  * of internal arrays is required
3262  */
3263       if(sd->is_open) { /* we might need to close it */
3264          bool doclose = false;
3265          if((sd->color_info.num_components != oldcolor.num_components) ||
3266             (sd->color_info.depth          != oldcolor.depth         ) ||
3267             (sd->stc.bits                  != oldstc.bits            ) ||
3268             (sd->stc.dither                != oldstc.dither          ))
3269             doclose = true;
3270 
3271          for(i = 0; i < sd->color_info.num_components; ++i) {
3272             if(sd->stc.extv[i] != oldstc.extv[i]) doclose = true;
3273             if(sd->stc.extc[i] != oldstc.extc[i]) doclose = true;
3274          }
3275          if(doclose) {
3276             stc_freedata(&oldstc);
3277             for(i = 0; i < 4; ++i) {
3278                sd->stc.vals[i] = NULL;
3279                sd->stc.code[i] = NULL;
3280             }
3281 
3282             gs_closedevice(pdev);
3283          }
3284       }                 /* we might need to close it */
3285 
3286    }
3287 
3288    return error;
3289 }
3290 /*
3291  * 1Bit CMYK-Algorithm
3292  */
3293 
3294 private int
3295 stc_gscmyk(stcolor_device *sdev,int npixel,byte *in,byte *buf,byte *out)
3296 {
3297 
3298    byte *ip = in;
3299    int   error = 0;
3300 
3301 
3302 /* ============================================================= */
3303    if(npixel > 0) {  /* npixel >  0 -> scanline-processing       */
3304 /* ============================================================= */
3305 
3306       int p;
3307 
3308 /*
3309  *    simply split the two pixels rsiding in a byte
3310  */
3311       for(p = npixel; p > 0; --p) { /* loop over pixels */
3312          byte tmp =*ip++;
3313 
3314          *out++ = (tmp>>4) & 15;
3315          if(--p <= 0) break;
3316 
3317          *out++ =  tmp     & 15;
3318 
3319       }                                   /* loop over pixels */
3320 
3321 /* ============================================================= */
3322    } else {          /* npixel <= 0 -> initialisation            */
3323 /* ============================================================= */
3324 
3325 /*    we didn't check for the white-calls above, so this may cause errors */
3326       if(sdev->stc.dither->flags & STC_WHITE)              error = -1;
3327 
3328 /*    if we're not setup for bytes, this is an error too */
3329       if((sdev->stc.dither->flags & STC_TYPE) != STC_BYTE) error = -2;
3330 
3331 /*    This IS a direct-driver, so STC_DIRECT must be set! */
3332       if((sdev->stc.dither->flags & STC_DIRECT) == 0)      error = -3;
3333 
3334 /*    and cmyk-mode is the only supported mode */
3335       if(sdev->color_info.num_components != 4)             error = -4;
3336 
3337 /*    and we support only 4Bit-Depth here */
3338       if(sdev->color_info.depth != 4)                      error = -5;
3339 
3340 /* ============================================================= */
3341    } /* scanline-processing or initialisation */
3342 /* ============================================================= */
3343 
3344    return error;
3345 }
3346 
3347 /*
3348  * The following is an algorithm under test
3349  */
3350 private int
3351 stc_hscmyk(stcolor_device *sdev,int npixel,byte *in,byte *buf,byte *out)
3352 {
3353 
3354 /* ============================================================= */
3355    if(npixel < 0) {  /* npixel <= 0 -> initialisation            */
3356 /* ============================================================= */
3357 
3358       int i,i2do;
3359       long *lp = (long *) buf;
3360 
3361 /* CMYK-only algorithm */
3362       if( sdev->color_info.num_components != 4)                      return -1;
3363 
3364 /*
3365  * check wether stcdither & TYPE are correct
3366  */
3367       if(( sdev->stc.dither                    == NULL) ||
3368          ((sdev->stc.dither->flags & STC_TYPE) != STC_LONG))         return -2;
3369 
3370 /*
3371  * check wether the buffer-size is sufficiently large
3372  */
3373       if(((sdev->stc.dither->flags/STC_SCAN) < 1) ||
3374          ( sdev->stc.dither->bufadd          <
3375           (1 + 2*sdev->color_info.num_components)))                  return -3;
3376 
3377 /*
3378  * must have STC_CMYK10, STC_DIRECT, but not STC_WHITE
3379  */
3380       if((sdev->stc.dither->flags & STC_CMYK10) == 0)                return -4;
3381       if((sdev->stc.dither->flags & STC_DIRECT) == 0)                return -5;
3382       if((sdev->stc.dither->flags & STC_WHITE ) != 0)                return -6;
3383 
3384 /*
3385  * Must have values between 0-1023.0
3386  */
3387       if((sdev->stc.dither->minmax[0] !=    0.0) ||
3388          (sdev->stc.dither->minmax[1] != 1023.0))                    return -7;
3389 /*
3390  * initialize buffer
3391  */
3392 
3393      i2do            = 1 + 8 - 4 * npixel;
3394      lp[0] = 0;
3395 
3396       if(sdev->stc.flags & STCDFLAG0) {
3397         for(i = 1; i < i2do; ++i) lp[i] = 0;
3398       } else {
3399         for(i = 1; i < i2do; ++i)  lp[i] = (rand() % 381) - 190;
3400       }
3401 
3402 /* ============================================================= */
3403    } else {  /* npixel > 0 && in != NULL  -> scanline-processing */
3404 /* ============================================================= */
3405 
3406       long errc[4],*errv;
3407       int             step  = buf[0] ? -1 : 1;
3408       stc_pixel *ip    =  (stc_pixel *) in;
3409 
3410       buf[0] = ~ buf[0];
3411       errv   =  (long *) buf + 5;
3412 
3413       if(step < 0) {
3414         ip   += npixel-1;
3415         out  += npixel-1;
3416         errv += 4*(npixel-1);
3417       }
3418 
3419       errc[0] = 0; errc[1] = 0; errc[2] = 0; errc[3] = 0;
3420 
3421       while(npixel-- > 0) {
3422 
3423          register  stc_pixel ci,mode;
3424          register  long           k,v,n;
3425          register  int pixel; /* internal pixel-value */
3426 
3427          ci      = *ip; ip += step;
3428 
3429          mode    = ci & 3;
3430          k       = (ci>>2) & 0x3ff;
3431          pixel   = 0;
3432 
3433          v       = k+errv[3]+((7*errc[3])>>4);
3434 
3435          if(mode == 3) { /* only Black allowed to fire */
3436 
3437             if(v > 511) {
3438                v     -= 1023;
3439                pixel  = BLACK;
3440             }
3441             errv[3-(step<<2)] += ((3*v+8)>>4);        /* 3/16 */
3442             errv[3]            = ((5*v+errc[3]+8)>>4);/* 5/16 +1/16 (rest) */
3443             errc[3]            = v;
3444 
3445             errv[0] = errv[0] < -190 ? -190 : errv[0] < 190 ? errv[0] : 190;
3446             errv[1] = errv[1] < -190 ? -190 : errv[1] < 190 ? errv[1] : 190;
3447             errv[2] = errv[2] < -190 ? -190 : errv[2] < 190 ? errv[2] : 190;
3448 
3449             errc[0] = 0; errc[1] = 0; errc[2] = 0;
3450 
3451          } else if(v > 511) { /* black known to fire */
3452 
3453             v    -= 1023;
3454             pixel = BLACK;
3455 
3456             errv[3-(step<<2)] += ((3*v+8)>>4);        /* 3/16 */
3457             errv[3]            = ((5*v+errc[3]+8)>>4);/* 5/16 +1/16 (rest) */
3458             errc[3]            = v;
3459 
3460             n = (ci>>12) & 0x3ff;
3461 
3462             if(mode == 2) { v = k; }
3463             else          { v = n; n = (ci>>22) & 0x3ff; }
3464 
3465             v += errv[2]+((7*errc[2])>>4)-1023;
3466             if(v < -511) v = -511;
3467             errv[2-(step<<2)] += ((3*v+8)>>4);        /* 3/16 */
3468             errv[2]            = ((5*v+errc[2]+8)>>4);/* 5/16 +1/16 (rest) */
3469             errc[2]            = v;
3470 
3471             if(mode == 1) { v = k; }
3472             else          { v = n; n = (ci>>22) & 0x3ff; }
3473 
3474             v += errv[1]+((7*errc[1])>>4)-1023;
3475             if(v < -511) v = -511;
3476             errv[1-(step<<2)] += ((3*v+8)>>4);        /* 3/16 */
3477             errv[1]            = ((5*v+errc[1]+8)>>4);/* 5/16 +1/16 (rest) */
3478             errc[1]            = v;
3479 
3480             if(mode == 0) v = k;
3481             else          v = n;
3482 
3483             v += errv[0]+((7*errc[0])>>4)-1023;
3484             if(v < -511) v = -511;
3485             errv[0-(step<<2)] += ((3*v+8)>>4);        /* 3/16 */
3486             errv[0]            = ((5*v+errc[0]+8)>>4);/* 5/16 +1/16 (rest) */
3487             errc[0]            = v;
3488 
3489          } else { /* Black does not fire initially */
3490 
3491             long kv = v; /* Black computed after colors */
3492 
3493             n = (ci>>12) & 0x3ff;
3494 
3495             if(mode == 2) { v = k; }
3496             else          { v = n; n = (ci>>22) & 0x3ff; }
3497 
3498             v += errv[2]+((7*errc[2])>>4);
3499             if(v > 511) {
3500                pixel |= YELLOW;
3501                v     -= 1023;
3502             }
3503             errv[2-(step<<2)] += ((3*v+8)>>4);        /* 3/16 */
3504             errv[2]            = ((5*v+errc[2]+8)>>4);/* 5/16 +1/16 (rest) */
3505             errc[2]            = v;
3506 
3507             if(mode == 1) { v = k; }
3508             else          { v = n; n = (ci>>22) & 0x3ff; }
3509 
3510             v += errv[1]+((7*errc[1])>>4);
3511             if(v > 511) {
3512                pixel |= MAGENTA;
3513                v     -= 1023;
3514             }
3515             errv[1-(step<<2)] += ((3*v+8)>>4);        /* 3/16 */
3516             errv[1]            = ((5*v+errc[1]+8)>>4);/* 5/16 +1/16 (rest) */
3517             errc[1]            = v;
3518 
3519             if(mode == 0) v = k;
3520             else          v = n;
3521 
3522             v += errv[0]+((7*errc[0])>>4);
3523             if(v > 511) {
3524                pixel |= CYAN;
3525                v     -= 1023;
3526             }
3527             errv[0-(step<<2)] += ((3*v+8)>>4);        /* 3/16 */
3528             errv[0]            = ((5*v+errc[0]+8)>>4);/* 5/16 +1/16 (rest) */
3529             errc[0]            = v;
3530 
3531             v = kv;
3532             if(pixel == (CYAN|MAGENTA|YELLOW)) {
3533                pixel = BLACK;
3534                v     = v > 511 ? v-1023 : -511;
3535             }
3536             errv[3-(step<<2)] += ((3*v+8)>>4);        /* 3/16 */
3537             errv[3]            = ((5*v+errc[3]+8)>>4);/* 5/16 +1/16 (rest) */
3538             errc[3]            = v;
3539 
3540          }
3541 
3542          errv += step<<2;
3543          *out  = pixel; out += step;
3544 
3545       }                                         /* loop over pixels */
3546 
3547 /* ============================================================= */
3548    } /* initialisation, white or scanline-processing             */
3549 /* ============================================================= */
3550 
3551    return 0;
3552 }
3553