1 /***********************************************************************
2  *                                                                     *
3  * PS_LZWencode.c - output an image in PostScript format               *
4  *                  (Lelpel-Ziv Welch encoding)                        *
5  *                                                                     *
6  * Author: Evgeni Chernyaev (chernaev@mx.ihep.su)                      *
7  *                                                                     *
8  * Copyright (C) 1993, 1994 by Evgeni Chernyaev.                       *
9  *                                                                     *
10  * Permission to use, copy, modify, and distribute this software and   *
11  * its documentation for non-commercial purpose is hereby granted      *
12  * without fee, provided that the above copyright notice appear in all *
13  * copies and that both the copyright notice and this permission       *
14  * notice appear in supporting documentation.                          *
15  *                                                                     *
16  * This software is provided "as is" without express or implied        *
17  * warranty.                                                           *
18  *                                                                     *
19  ***********************************************************************/
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <time.h>
24 
25 #ifdef __STDC__
26 #define ARGS(alist) alist
27 #else
28 #define ARGS(alist) ()
29 #endif
30 
31 typedef unsigned char byte;
32 
33 static int       Nbyte;
34 static char      s[80];
35 static void      (*put_b) ARGS((byte));
36 #define put_string nc=strlen(s); for(i=0;i<nc;i++) (*put_b)(s[i]); Nbyte += nc
37 
38 
39 #define MAXWIDTH 4096
40 #define BLACK    1
41 #define WHITE    0
42 
43 /***********************************************************************
44  *                                                                     *
45  * Name: PutPreview                                  Date:    02.11.93 *
46  * Author: E.Chernyaev (IHEP/Protvino)               Revised:          *
47  *                                                                     *
48  * Function: Output device independent B&W preview                     *
49  *                                                                     *
50  * Input: Width      - image width                                     *
51  *        Height     - image height                                    *
52  *        R[]        - red components                                  *
53  *        G[]        - green components                                *
54  *        B[]        - blue components                                 *
55  *        ScLine[]   - array for scan line (byte per pixel)            *
56  *        get_scline - user routine to read scan line:                 *
57  *                       get_scline(y, Width, ScLine)                  *
58  *                                                                     *
59  ***********************************************************************/
PutPreview(Width,Height,R,G,B,ScLine,get_scline)60 static void PutPreview(Width, Height, R, G, B, ScLine, get_scline)
61                   int  Width, Height;
62                   byte R[], G[], B[], ScLine[];
63                   void (*get_scline) ARGS((int, int, byte *));
64 {
65   int    i, k, nc, x, y;
66   int    mask, hex, err, dp, dp1, dp2, ddd[MAXWIDTH];
67 
68   static int FSgamma[256] = {                   /* Floyd-Steinberg gamma */
69     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
70     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
71     0,  0,  0,  1,  1,  2,  2,  3,  3,  4,  4,  5,  6,  6,  7,  8,
72     9,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
73    24, 26, 27, 28, 29, 30, 32, 33, 34, 36, 37, 38, 40, 41, 43, 44,
74    45, 47, 48, 50, 51, 53, 54, 56, 58, 59, 61, 62, 64, 66, 67, 69,
75    70, 72, 74, 76, 77, 79, 81, 82, 84, 86, 88, 89, 91, 93, 95, 96,
76    98,100,102,104,105,107,109,111,113,114,116,118,120,122,124,125,
77   127,129,131,133,135,136,138,140,142,144,145,147,149,151,153,154,
78   156,158,160,162,163,165,167,169,170,172,174,175,177,179,181,182,
79   184,186,187,189,190,192,194,195,197,198,200,201,203,204,206,207,
80   209,210,212,213,215,216,217,219,220,221,223,224,225,226,228,229,
81   230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,
82   246,246,247,248,248,249,250,250,251,251,252,252,253,253,254,254,
83   255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
84   255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 };
85 
86   k = (Width + 279) / 280;                      /* 70 HEX per line */
87   sprintf(s,"%%%%BeginPreview: %d %d 1 %d\n", Width, Height, k*Height);
88                                                    put_string;
89   for (i=0; i<Width; i++)
90     ddd[i] = 0;
91 
92   for (y=0; y<Height; y++) {
93     (*get_scline)(y, Width, ScLine);
94     nc    = 0; mask = 128; hex = 0; dp1 = 0;
95     for (x=0; x<Width; x++) {
96       i     = ScLine[x];
97       i     = (11*R[i] + 16*G[i] + 5*B[i]) / 32;
98       dp    = FSgamma[i] + dp1 + ddd[x];        /* Floyd-Steinberg dithering */
99       if (dp<128) {                             /*     ---    x    7/16      */
100         hex += BLACK*mask; err = dp;            /*     3/16  5/16  1/16      */
101       }else{
102         hex += WHITE*mask; err = dp - 255;
103       }
104       dp1   = (err*7)/16;
105       if (x == 0) {
106         ddd[0]    = (err*5)/16;
107         dp2       = err/16;
108         }else{
109         ddd[x-1] += (err*3)/16;
110         ddd[x]    = dp2 + (err*5)/16;
111         dp2       = err/16;
112       }
113       mask /= 2;
114       if (mask == 0) {
115         if (nc == 0) {
116           sprintf(&s[nc],"%% "); nc = 2;
117         }
118         sprintf(&s[nc],"%02x",hex); nc += 2;
119         if (nc == 72) {
120           sprintf(&s[nc],"\n");                 put_string;
121           nc = 0;
122         }
123         mask = 128; hex = 0;
124       }
125     }
126     if (mask == 128) {
127       if (nc != 0) {
128         sprintf(&s[nc],"\n");                   put_string;
129       }
130     }else{
131       if (nc == 0) {
132         sprintf(&s[nc],"%% "); nc = 2;
133       }
134       sprintf(&s[nc],"%02x\n",hex);             put_string;
135     }
136   }
137   sprintf(s,"%%%%EndPreview\n");                put_string;
138 }
139 
140 /***********************************************************************
141  *                                                                     *
142  * Name: ASCII85encode                               Date:    05.11.93 *
143  * Author: E.Chernyaev (IHEP/Protvino)               Revised:          *
144  *                                                                     *
145  * Function: ASCII85 encode and output byte buffer                     *
146  *                                                                     *
147  * Input: k   - number of bytes                                        *
148  *        Buf - byte buffer                                            *
149  *                                                                     *
150  ***********************************************************************/
ASCII85encode(k,Buf)151 static void ASCII85encode(k, Buf)
152                      int  k;
153                      byte Buf[];
154 {
155   unsigned long Value;
156   int    i,j, n, nc;
157 
158   if (k == 0) return;
159   s[5] = '\0';
160   for (j=0; j<k; j+=4) {
161     Value = Buf[j]*256*256*256;
162     if (j+1 < k) Value += Buf[j+1]*256*256;
163     if (j+2 < k) Value += Buf[j+2]*256;
164     if (j+3 < k) Value += Buf[j+3];
165     for (n=4; n>=0; n--) {
166       s[n]   = Value % 85 + 33;
167       Value /= 85;
168     }
169     if (k-j < 4) s[k-j+1] = '\0';
170     put_string;
171   }
172   sprintf(s,"\n");
173   put_string;
174 }
175 
176 #define BITS           12                       /* largest code size */
177 #define HSIZE          5003                     /* hash table size */
178 #define SHIFT          4                        /* shift for hashing */
179 #define CLEARCODE      256                      /* Clear Code */
180 #define EOD            257                      /* End Of Data code */
181 #define PIXS           170000                   /* largest # of pixels */
182 
183 /***********************************************************************
184  *                                                                     *
185  * Name: PutCode                                     Date:    05.11.93 *
186  * Author: E.Chernyaev (IHEP/Protvino)               Revised:          *
187  *                                                                     *
188  * Function: Put out code (LZW encoding)                               *
189  *                                                                     *
190  * Input: Code - code                                                  *
191  *        CodeSize - codesize                                          *
192  *                                                                     *
193  ***********************************************************************/
PutCode(Code,CodeSize)194 static void PutCode(Code, CodeSize)
195                 int Code, CodeSize;
196 {
197   static int k, PartA, PartB, SizeA, SizeB;
198   static int mask[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
199                                 0x001F, 0x003F, 0x007F, 0x00FF,
200                                 0x01FF, 0x03FF, 0x07FF, 0x0FFF };
201   static byte Accum[56];
202   if (Code == -1) {
203     k      = 0;
204     PartA  = 0;
205     SizeA  = 0;
206     return;
207   }
208 
209   PartB = Code;
210   SizeB = CodeSize;
211 
212   while (SizeB >= 8) {
213     SizeB  = SizeA + SizeB - 8;
214     Accum[k++] = PartA | (PartB >> SizeB);
215     if (k == 56) {
216       ASCII85encode(k,Accum);
217       k      = 0;
218     }
219     PartB &= mask[SizeB];
220     SizeA  = 0;
221     PartA  = 0;
222   }
223 
224   SizeA = SizeB;
225   PartA = PartB << (8-SizeB);
226   if (Code == EOD) {
227     if (SizeA != 0) Accum[k++] = PartA;
228     ASCII85encode(k, Accum);
229   }
230 }
231 
232 /***********************************************************************
233  *                                                                     *
234  * Name: EncodeData                                  Date:    05.11.93 *
235  * Author: E.Chernyaev (IHEP/Protvino)               Revised: 21.06.94 *
236  *                                                            04.06.94 *
237  * Function: Lelpel-Ziv Welch encoding of an image                     *
238  *                                                                     *
239  * Input: Width      - image width                                     *
240  *        Height     - image height                                    *
241  *        Ncol       - number of colors                                *
242  *        R[]        - red components                                  *
243  *        G[]        - green components                                *
244  *        B[]        - blue components                                 *
245  *        ScLine[]   - array for scan line (byte per pixel)            *
246  *        get_scline - user routine to read scan line:                 *
247  *                       get_scline(y, Width, ScLine)                  *
248  *                                                                     *
249  * Return: size of PS                                                  *
250  *                                                                     *
251  ***********************************************************************/
EncodeData(Width,Height,Ncol,R,G,B,ScLine,get_scline)252 static void EncodeData(Width, Height, Ncol, R, G, B, ScLine, get_scline)
253                   int  Width, Height, Ncol;
254                   byte R[], G[], B[], ScLine[];
255                   void (*get_scline) ARGS((int, int, byte *));
256 {
257   int    i, k, nc, x, y, disp, Code, K;
258   long   CodeK, Npix;
259   char   **q;
260   int    FreeCode, CurCodeSize, CurMaxCode;
261 
262   long   HashTab [HSIZE];                       /* hash table */
263   int    CodeTab [HSIZE];                       /* code table */
264 
265   /*   O U T P U T   P A L E T T E   */
266 
267   for (k=0; k<Ncol; k++) {
268     sprintf(s,"%02x%02x%02x",R[k],G[k],B[k]);   put_string;
269     if (k % 10 == 9) {
270       sprintf(s,"\n");                          put_string;
271     }else{
272       sprintf(s," ");                           put_string;
273     }
274   }
275   for (k=Ncol; k<256; k++) {
276     sprintf(s,"000000");                        put_string;
277     if (k % 10 == 9) {
278       sprintf(s,"\n");                          put_string;
279     }else{
280       sprintf(s," ");                           put_string;
281     }
282   }
283   sprintf(s,"\n");                              put_string;
284 
285   /*   L W Z   C O M P R E S S I O N   */
286 
287   PutCode(-1, 0);
288   FreeCode    = CLEARCODE + 2;
289   CurCodeSize = 9;
290   CurMaxCode  = 511;
291   memset((char *) HashTab, -1, sizeof(HashTab));
292   PutCode(CLEARCODE, CurCodeSize);              /* 1st - clear code */
293   Npix = 0;
294   for (y=0; y<Height; y++) {
295     (*get_scline)(y, Width, ScLine);
296     x     = 0;
297     if (y == 0) Code  = ScLine[x++];
298     while(x < Width) {
299       K     = ScLine[x++];                      /* next symbol */
300       Npix++;
301       CodeK = ((long) K << BITS) + Code;        /* set full code */
302       k     = (K << SHIFT) ^ Code;              /* xor hashing */
303 
304       if (HashTab[k] == CodeK) {                /* full code found */
305         Code = CodeTab[k];
306         continue;
307       }
308       else if (HashTab[k] < 0 )                 /* empty slot */
309         goto NOMATCH;
310 
311       disp  = HSIZE - k;                        /* secondary hash */
312       if (k == 0) disp = 1;
313 
314 PROBE:
315       if ((k -= disp) < 0)
316         k  += HSIZE;
317 
318       if (HashTab[k] == CodeK) {                /* full code found */
319         Code = CodeTab[k];
320         continue;
321       }
322 
323       if (HashTab[k] > 0)                       /* try again */
324         goto PROBE;
325 
326 NOMATCH:                                        /* full code not found */
327       PutCode(Code, CurCodeSize);
328       Code = K;
329       if (FreeCode == CurMaxCode) {
330         CurCodeSize++;
331         CurMaxCode = CurMaxCode*2 + 1;
332       }
333 
334       if (CurCodeSize <= BITS && Npix <= PIXS) {
335         CodeTab[k] = FreeCode++;                /* code -> hashtable */
336         HashTab[k] = CodeK;
337       }else{
338         if (CurCodeSize > BITS) CurCodeSize = BITS;
339         PutCode(CLEARCODE, CurCodeSize);
340         memset((char *) HashTab, -1, sizeof(HashTab));
341         FreeCode    = CLEARCODE + 2;
342         CurCodeSize = 9;
343         CurMaxCode  = 511;
344         Npix = 0;
345       }
346     }
347   }
348    /*   O U T P U T   T H E   R E S T  */
349 
350   PutCode(Code, CurCodeSize);
351   if (FreeCode == CurMaxCode && CurCodeSize != BITS)
352     CurCodeSize++;
353   PutCode(EOD, CurCodeSize);
354   sprintf(s,"~>\n");                            put_string;
355 }
356 
357 /***********************************************************************
358  *                                                                     *
359  * Name: PS_LZWencode                                Date:    02.02.93 *
360  * Author: E.Chernyaev (IHEP/Protvino)               Revised: 02.11.93 *
361  *                                                                     *
362  * Function: Output image in PostScript format                         *
363  *           (Lelpel-Ziv Welch encoding)                               *
364  *                                                                     *
365  * Input: iwhat      - 0 - PostScript                           (PS)   *
366  *                     1 - encapsulated PostScript              (EPS)  *
367  *                     2 - encapsulated PostScript with preview (EPSI) *
368  *                    10 - PostScript (Gray)                    (PS)   *
369  *                    11 - encapsulated PostScript (Gray)       (EPS)  *
370  *                    12 - encapsulated PostScript with preview (EPSI) *
371  *        Width      - image width                                     *
372  *        Height     - image height                                    *
373  *        Ncol       - number of colors                                *
374  *        R[]        - red components                                  *
375  *        G[]        - green components                                *
376  *        B[]        - blue components                                 *
377  *        ScLine[]   - array for scan line (byte per pixel)            *
378  *        get_scline - user routine to read scan line:                 *
379  *                       get_scline(y, Width, ScLine)                  *
380  *        pb         - user routine for "put_byte": pb(b)              *
381  *                                                                     *
382  * Return: size of PS                                                  *
383  *                                                                     *
384  ***********************************************************************/
PS_LZWencode(iwhat,Width,Height,Ncol,R,G,B,ScLine,get_scline,pb)385 long PS_LZWencode(iwhat, Width, Height, Ncol, R, G, B, ScLine, get_scline, pb)
386              int  iwhat, Width, Height, Ncol;
387              byte R[], G[], B[], ScLine[];
388              void (*get_scline) ARGS((int, int, byte *)), (*pb) ARGS((byte));
389 {
390   extern char ProgName[];
391   extern char ProgVers[];
392   extern char FileName[];
393 
394   int        ifeps, ifgray, i, nc;
395   char       **q;
396   time_t     clock;
397 
398   static char *HeaderPS[] = {
399     "%***********************************************************************",
400     "%*                                                                     *",
401     "%* Function: Display a Lempel-Ziv Welch (LZW) encoded color image.     *",
402     "%*           This file is suitable for any kind of PostScript printer: *",
403     "%*           Level I/II, color/grayscale, format A4/A3/...             *",
404     "%*           By default the image will be centered, rotated and scaled *",
405     "%*           to fill the maximum space on a page.                      *",
406     "%*           If you want to use this file as an Encapsulated PostScript*",
407     "%*           file (for example inside a LaTeX document), then just     *",
408     "%*           uncomment line '/EPSneeded true def'.                     *",
409     "%*           To optimize output on GrayScale printers you may uncomment*",
410     "%*           line '/GRAYneeded true def'.                              *",
411     "%*                                                                     *",
412     "%* Author: Evgeni CHERNYAEV (chernaev@mx.ihep.su)                      *",
413     "%*                                                                     *",
414     "%***********************************************************************",
415     "gsave",
416     "userdict begin",
417     "%/EPSneeded true def",
418     NULL,
419   };
420   static char *HeaderEPS[] = {
421     "%***********************************************************************",
422     "%*                                                                     *",
423     "%* Function: Display a Lempel-Ziv Welch (LZW) encoded color image.     *",
424     "%*           This is an Encapsulated PostScript file suitable for any  *",
425     "%            kind of PostScript printer: Level I/II, color/grayscale...*",
426     "%*           To optimize output on GrayScale printers you may uncomment*",
427     "%*           line '/GRAYneeded true def'.                              *",
428     "%*                                                                     *",
429     "%* Author: Evgeni CHERNYAEV (chernaev@vxcern.cern.ch)                  *",
430     "%*                                                                     *",
431     "%***********************************************************************",
432     "gsave",
433     "userdict begin",
434     "/EPSneeded true def",
435     NULL,
436   };
437   static char *HeaderCol[] = {
438     "%/GRAYneeded true def",
439     "end",
440     "%***********************************************************************",
441     "%*                              Image Description                      *",
442     "%***********************************************************************",
443     NULL,
444   };
445   static char *HeaderGray[] = {
446     "/GRAYneeded true def",
447     "end",
448     "%***********************************************************************",
449     "%*                              Image Description                      *",
450     "%***********************************************************************",
451     NULL,
452   };
453   static char *CommonPart[] = {
454     "/mm {2.835 mul} def",
455     "userdict /EPSneeded known {",
456     "  /EPSneeded userdict /EPSneeded get def",
457     "}{",
458     "  /EPSneeded false def",
459     "} ifelse",
460     "userdict /GRAYneeded known {",
461     "  /GRAYneeded userdict /GRAYneeded get def",
462     "}{",
463     "  /GRAYneeded false def",
464     "} ifelse",
465     "EPSneeded {",
466     "  /IfRotate false def",
467     "  /MarginX 0 def /MarginY 0 def",
468     "  /Ymax rows def /Xmax colomns def /Ymin 0 def /Xmin 0 def",
469     "}{",
470     "  /IfRotate colomns rows gt {true} {false} ifelse def",
471     "  /MarginX 8 mm def /MarginY 18 mm def",
472     "  0 0 moveto clippath pathbbox",
473     "  /Ymax exch def /Xmax exch def /Ymin exch def /Xmin exch def",
474     "} ifelse",
475     "/IfColor systemdict /colorimage known {true} {false} ifelse def",
476     "GRAYneeded {/IfColor false def} if",
477     "/IfLevel2 systemdict /filter known systemdict /setcolorspace known and",
478     "  {true} {false} ifelse def",
479     "%***********************************************************************",
480     "%                               Procedures                             *",
481     "%***********************************************************************",
482     "/Table 4096 array def",
483     "/StrArray 10 array def",
484     "/InLine 70 string def",
485     "/BinCodes 112 string def",
486     "/CurBit 0 def /FreeCode 258 def /CurCodeSize 9 def /CurMask 511 def",
487     "/incr IfColor {3} {1} ifelse def",
488     "IfLevel2 not {/setcolorspace null def /filter null def} if",
489     "%***********************************************************************",
490     "/ReadLine {                     % Read Next Data Line (ASCII85 decode) *",
491     "%***********************************************************************",
492     "  BinCodes 0 BinCodes 56 56 getinterval putinterval",
493     "  currentfile InLine readline pop pop",
494     "  1 1 14 {",
495     "    /i exch 1 sub def",
496     "    /k i 5 mul def",
497     "    /c1 InLine k get 33 sub 255 and def",
498     "    /rest c1 1868977 mul",
499     "      InLine k 1 add get 33 sub 255 and 614125 mul add",
500     "      InLine k 2 add get 33 sub 255 and 7225 mul add",
501     "      InLine k 3 add get 33 sub 255 and 85 mul add",
502     "      InLine k 4 add get 33 sub 255 and add def",
503     "    /k i 4 mul 56 add def",
504     "    BinCodes k c1 3 mul rest 16777216 idiv add 255 and put",
505     "    /rest rest 16777216 mod def",
506     "    BinCodes k 1 add rest 65536 idiv put",
507     "    BinCodes k 2 add rest 256 idiv 255 and put",
508     "    BinCodes k 3 add rest 255 and put",
509     "  } for",
510     "} bind def",
511     "%***********************************************************************",
512     "/ReadCode {                     % Read next code                       *",
513     "%***********************************************************************",
514     "  /CurByte CurBit 8 idiv def",
515     "  /CurCode",
516     "    BinCodes CurByte get 8 bitshift",
517     "    BinCodes CurByte 1 add get add 8 bitshift",
518     "    BinCodes CurByte 2 add get add",
519     "    CurCodeSize CurBit 7 and add 24 sub bitshift CurMask and def",
520     "  /CurBit CurBit CurCodeSize add dup 448 ge {ReadLine 448 sub} if def",
521     "} bind def",
522     "%***********************************************************************",
523     "/DecodeCode {                   % Decode CurCode                       *",
524     "%***********************************************************************",
525     "  ReadCode CurCode 256 eq {",
526     "    /FreeCode 258 def /CurCodeSize 9 def /CurMask 511 def",
527     "    /StrInd -1 def /Lrest 0 def ReadCode",
528     "  }{",
529     "    L Lrest gt {",
530     "      /StrInd StrInd 1 add def /Lrest 65535 def",
531     "      StrArray StrInd get null eq {StrArray StrInd 65535 string put} if",
532     "      /CurStr StrArray StrInd get def",
533     "    } if",
534     "    Table FreeCode CurStr 65535 Lrest sub L getinterval",
535     "    dup 0 Table OldCode get putinterval",
536     "    dup L incr sub Table",
537     "      CurCode FreeCode lt {CurCode} {OldCode} ifelse get",
538     "    0 incr getinterval putinterval put",
539     "    /Lrest Lrest L sub def /FreeCode FreeCode 1 add def",
540     "    FreeCode CurMask ge CurCodeSize 12 lt and {",
541     "      /CurCodeSize CurCodeSize 1 add def",
542     "      /CurMask CurMask 1 bitshift 1 add def",
543     "    } if",
544     "  } ifelse",
545     "  /OldCode CurCode def",
546     "  Table CurCode get dup length incr add /L exch def",
547     "} bind def",
548     "%***********************************************************************",
549     "/DisplayImage {          % Display a LZW-encoded color image           *",
550     "%***********************************************************************",
551     "  /DelX Xmax Xmin sub MarginX 2 mul sub def",
552     "  /DelY Ymax Ymin sub MarginY 2 mul sub def",
553     "  /SizeX IfRotate {rows} {colomns} ifelse def",
554     "  /SizeY IfRotate {colomns} {rows} ifelse def",
555     "  /FactorX DelX SizeX div def /FactorY DelY SizeY div def",
556     "  /Factor FactorX FactorY le {FactorX} {FactorY} ifelse def",
557     "  /ScaleX SizeX Factor mul def /ScaleY SizeY Factor mul def",
558     "  Xmin DelX ScaleX sub 2 div MarginX add add",
559     "  Ymin DelY ScaleY sub 2 div MarginY add add translate",
560     "  IfRotate {ScaleY ScaleX} {ScaleX ScaleY} ifelse scale",
561     "  /Palette currentfile 768 string readhexstring pop def",
562     "  currentfile InLine readline pop pop",
563     "  IfColor not {",
564     "    0 1 255 {",
565     "      Palette exch dup /i exch 3 mul def",
566     "      Palette i 0 add get 0.299 mul",
567     "      Palette i 1 add get 0.587 mul add",
568     "      Palette i 2 add get 0.114 mul add cvi put",
569     "    } for",
570     "    /Palette Palette 0 256 getinterval def",
571     "  } if",
572     "  /Matr IfRotate",
573     "    {[0 colomns rows 0 0 0]} {[colomns 0 0 rows neg 0 rows]} ifelse def",
574     "  IfLevel2 {",
575     "    [/Indexed IfColor {/DeviceRGB} {/DeviceGray} ifelse 255 Palette]",
576     "    setcolorspace",
577     "    /infile currentfile /ASCII85Decode filter /LZWDecode filter def",
578     "    8 dict",
579     "    dup /ImageType 1 put",
580     "    dup /Width colomns put",
581     "    dup /Height rows put",
582     "    dup /BitsPerComponent 8 put",
583     "    dup /ImageMatrix Matr put",
584     "    dup /Interpolate false put",
585     "    dup /Decode [0 255] put",
586     "    dup /DataSource infile put image",
587     "  }{",
588     "    0 1 255 {",
589     "      Table exch dup incr mul Palette exch incr getinterval put",
590     "    } for",
591     "    ReadLine ReadLine",
592     "    colomns rows 8 Matr {DecodeCode}",
593     "    IfColor {false 3 colorimage} {image} ifelse",
594     "  } ifelse",
595     "} bind def",
596     "%***********************************************************************",
597     "%*                              Image decoding                         *",
598     "%***********************************************************************",
599     "DisplayImage",
600     NULL,
601   };
602 
603   /*   C H E C K   P A R A M E T E R S   */
604 
605   if (Width <= 0 || Width > MAXWIDTH || Height <= 0 || Height > MAXWIDTH) {
606     fprintf(stderr,
607       "\n%s: incorrect image size: %d x %d\n", ProgName, Width, Height);
608     return 0;
609   }
610 
611   if (Ncol <= 0 || Ncol > 256) {
612     fprintf(stderr,"\n%s: wrong number of colors: %d\n", ProgName, Ncol);
613     return 0;
614   }
615 
616   /*   I N I T I A L I S A T I O N   */
617 
618   if (iwhat < 10)
619     ifeps = iwhat;
620   else
621     ifeps = iwhat - 10;
622   put_b  = pb;
623   Nbyte  = 0;
624 
625   /*   O U T P U T   H E A D E R   */
626 
627   sprintf(s,"%%!PS-Adobe-2.0 EPSF-2.0\n");                      put_string;
628   sprintf(s,"%%%%Title: %s\n", FileName);                       put_string;
629   sprintf(s,"%%%%Creator: %s %s\n", ProgName, ProgVers);        put_string;
630   sprintf(s,"%%%%CreationDate: %s",(time(&clock),ctime(&clock))); put_string;
631   sprintf(s,"%%%%BoundingBox: 0 0 %d %d\n", Width, Height);     put_string;
632   sprintf(s,"%%%%EndComments\n");                               put_string;
633 
634   /*   O U T P U T   P R E V I E W   */
635 
636   if (ifeps == 2)
637     PutPreview(Width, Height, R, G, B, ScLine, get_scline);
638 
639   /*   O U T P U T   P O S T S C R I P T   P R O G R A M M   */
640 
641   if (ifeps == 0)
642     q = HeaderPS;
643   else
644     q = HeaderEPS;
645   for ( ; *q; q++) {
646     sprintf(s,"%s\n",*q);                               put_string;
647   }
648   if (iwhat < 10)
649     q = HeaderCol;
650   else
651     q = HeaderGray;
652   for ( ; *q; q++) {
653     sprintf(s,"%s\n",*q);                               put_string;
654   }
655 
656   sprintf(s,"/colomns %d def\n",Width);                 put_string;
657   sprintf(s,"/rows %d def\n",Height);                   put_string;
658   for (q=CommonPart; *q; q++) {
659     sprintf(s,"%s\n",*q);                               put_string;
660   }
661 
662   /*   O U T P U T   E N C O D E D   D A T A   */
663 
664   EncodeData(Width, Height, Ncol, R, G, B, ScLine, get_scline);
665 
666   sprintf(s,"showpage grestore\n");                     put_string;
667   sprintf(s,"%%%%Trailer\n");                           put_string;
668   return (Nbyte);
669 }
670