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