1 #include <stdio.h>
2 
3 #ifdef __STDC__
4 #define ARGS(alist) alist
5 #else
6 #define ARGS(alist) ()
7 #endif
8 
9 #define HEADER_SIZE          512
10 #define MAXCOLORS            256
11 
12 #define PICT_clipRgn         0x01       /* PICT opcodes */
13 #define PICT_picVersion      0x11
14 #define PICT_PackBitsRect    0x98
15 #define PICT_EndOfPicture    0xFF
16 #define PICT_headerOp        0x0C00
17 
18 #define put_byte(A) (*put_b)((byte)(A)); Nbyte++
19 
20 typedef unsigned char byte;
21 
22 static long      Nbyte;
23 static void     (*put_b) ARGS ((byte));
24 
25 static void     put_scline ARGS((byte *, int));
26 static void     put_short ARGS((int));
27 static void     put_long ARGS((long));
28 static void     put_fixed ARGS((int, int));
29 static void     put_rect ARGS((int, int, int, int));
30 static void     put_fill ARGS((int));
31 
32 /***********************************************************************
33  *                                                                     *
34  * Name: PICTencode                                  Date:    20.11.92 *
35  * Author: E.Chernyaev (IHEP/Protvino)               Revised:          *
36  *                                                                     *
37  * Function: PICT (Macintosh) compression of the image                 *
38  *                                                                     *
39  * Input: Width      - image width  (must be >= 8)                     *
40  *        Height     - image height (must be >= 8)                     *
41  *        Ncol       - number of colors                                *
42  *        R[]        - red components                                  *
43  *        G[]        - green components                                *
44  *        B[]        - blue components                                 *
45  *        ScLine[]   - array for scan line (byte per pixel)            *
46  *        get_scline - user routine to read scan line:                 *
47  *                       get_scline(y, Width, ScLine)                  *
48  *        pb         - user routine for "put_byte": pb(b)              *
49  *                                                                     *
50  * Return: size of PICT                                                *
51  *                                                                     *
52  ***********************************************************************/
PICTencode(Width,Height,Ncol,R,G,B,ScLine,get_scline,pb)53 long PICTencode(Width, Height, Ncol, R, G, B, ScLine, get_scline, pb)
54            int  Width, Height, Ncol;
55            byte R[], G[], B[], ScLine[];
56            void (*get_scline) ARGS((int, int, byte *)), (*pb) ARGS((byte));
57 {
58   int        i;
59 
60   /*   C H E C K   P A R A M E T E R S   */
61 
62   if (Width < 8 || Height < 8) {
63     fprintf(stderr,"\nPICTencode: very small image, must be >= 8x8\n");
64     return 0;
65   }
66 
67   if (Width > 4096 || Height > 4096) {
68     fprintf(stderr,"\nPICTencode: too big image: %d x %d\n", Width, Height);
69     return 0;
70   }
71 
72   if (Ncol <= 0 || Ncol > 256) {
73     fprintf(stderr,"\nPICTencode: wrong number of colors: %d\n", Ncol);
74     return 0;
75   }
76 
77   /*   I N I T I A L I S A T I O N   */
78 
79   put_b   = pb;
80   Nbyte   = 0;
81 
82   /*   W R I T E   O U T   T H E   H E A D E R   */
83 
84   put_fill(HEADER_SIZE);                /* write the header */
85 
86   put_short(0xffff);                    /* write picSize(?) and picFrame */
87   put_rect(0, 0, Height, Width);
88 
89   put_short(PICT_picVersion);           /* write version op and version */
90   put_short(0x02FF);
91   put_short(PICT_headerOp);
92   put_long(-1L);
93   put_fixed(0, 0);
94   put_fixed(0, 0);
95   put_fixed(Width, 0);
96   put_fixed(Height, 0);
97   put_fill(4);
98 
99   put_short(PICT_clipRgn);              /* needed by many PICT2 programs */
100   put_short(10);
101   put_rect(0, 0, Height, Width);
102 
103   put_short(PICT_PackBitsRect);         /* write picture */
104   put_short(Width | 0x8000);
105   put_rect(0, 0, Height, Width);
106   put_short(0);                         /* pmVersion */
107   put_short(0);                         /* packType */
108   put_long(0L);                         /* packSize */
109   put_fixed(72, 0);                     /* hRes */
110   put_fixed(72, 0);                     /* vRes */
111   put_short(0);                         /* pixelType */
112   put_short(8);                         /* pixelSize */
113   put_short(1);                         /* cmpCount */
114   put_short(8);                         /* cmpSize */
115   put_long(0L);                         /* planeBytes */
116   put_long(0L);                         /* pmTable */
117   put_long(0L);                         /* pmReserved */
118   put_long(0L);                         /* ctSeed */
119   put_short(0);                         /* ctFlags */
120   put_short(Ncol-1);                    /* ctSize */
121 
122   /*   W R I T E   O U T   T H E   C O L O R M A P   */
123 
124   for (i = 0; i < Ncol; i++) {
125     put_short(i);
126     put_short((int)(R[i]*65535L/255L));
127     put_short((int)(G[i]*65535L/255L));
128     put_short((int)(B[i]*65535L/255L));
129   }
130 
131   put_rect(0, 0, Height, Width);        /* srcRect */
132   put_rect(0, 0, Height, Width);        /* dstRect */
133   put_short(0);                         /* mode */
134 
135 
136   /*   W R I T E   O U T   T H E   I M A G E   */
137 
138   for (i = 0; i < Height; i++) {
139     (*get_scline)(i, Width, ScLine);
140     put_scline(ScLine, Width);
141   }
142 
143   if (Nbyte & 1) { put_byte(0); }       /* if we wrote odd # of bytes */
144 
145   put_short(PICT_EndOfPicture);
146   return (Nbyte);
147 }
148 
149 #define RUN_THRESH        3
150 #define MAX_RUN          128            /* 0xff = 2, 0xfe = 3, etc */
151 #define MAX_COUNT        128            /* 0x00 = 1, 0x01 = 2, etc */
152 
153 #define RunToChar(c)     (257-(c))
154 #define CountToChar(c)   ((c)-1)
155 
put_scline(buf,size)156 static void put_scline(buf, size)
157                  byte *buf;
158                  int  size;
159 {
160   byte       *ptr, *end;
161   int        current, previous, run, count, rep;
162 
163   /*   F I N D   N U M B E R   O F   B Y T E S   TO BE WRITTEN   */
164 
165   ptr      = buf;
166   end      = ptr + size;
167   previous = *ptr++;
168   run      = 1;
169   count    = 0;
170   rep      = 0;
171   while (ptr < end) {
172     current = *ptr++;
173     if (current == previous && run < MAX_RUN) {
174       run++;
175       continue;
176     }
177     if (run < RUN_THRESH) {
178       count   += run;
179       previous = current;
180       run      = 1;
181       continue;
182     }
183     rep += count + (count+MAX_COUNT-1)/MAX_COUNT + 2;
184     previous = current;
185     run      = 1;
186     count    = 0;
187   }
188   if (run < RUN_THRESH) {               /* scan line finished */
189     count += run;
190     run    = 0;
191   }
192   rep += count + (count+MAX_COUNT-1)/MAX_COUNT;
193   if (run > 0) rep += 2;
194 
195   /*   W R I T E    B Y T E   C O U N T E R   */
196 
197   if (size > 250)
198     put_short(rep);
199   else
200     { put_byte(rep); }
201 
202   /*   R U N   L E N G T H   E N C O D I N G   */
203 
204   ptr      = buf;
205   previous = *ptr++;
206   run      = 1;
207   count    = 0;
208   while (ptr < end) {
209     current = *ptr++;
210     if (current == previous && run < MAX_RUN) {
211       run++;
212       continue;
213     }
214     if (run < RUN_THRESH) {
215       count += run;
216       previous = current;
217       run = 1;
218       continue;
219     }
220     ptr   -= run + count;
221     while (count > 0) {
222       rep = count > MAX_COUNT ? MAX_COUNT : count;
223       put_byte(CountToChar(rep));
224       count -= rep;
225       while (rep > 0) {
226         put_byte(*ptr++);
227         rep--;
228       }
229     }
230     ptr   += run;
231     put_byte(RunToChar(run));
232     put_byte(previous);
233     previous = current;
234     run = 1;
235   }
236   if (run < RUN_THRESH) {               /* scan line finished */
237     count += run;
238     run    = 0;
239   }
240   ptr   -= run + count;
241   while (count > 0) {
242     rep = count > MAX_COUNT ? MAX_COUNT : count;
243     put_byte(CountToChar(rep));
244     count -= rep;
245     while (rep > 0) {
246       put_byte(*ptr++);
247       rep--;
248     }
249   }
250   if (run > 0) {
251     put_byte(RunToChar(run));
252     put_byte(previous);
253   }
254 }
255 
put_short(k)256 static void put_short(k)
257                   int k;
258 {
259   put_byte((k >> 8) & 0xFF);
260   put_byte(k & 0xFF);
261 }
262 
put_long(k)263 static void put_long(k)
264                 long k;
265 {
266   put_byte((k >> 24) & 0xFF);
267   put_byte((k >> 16) & 0xFF);
268   put_byte((k >>  8) & 0xFF);
269   put_byte(k & 0xFF);
270 }
271 
put_fixed(in,frac)272 static void put_fixed(in, frac)
273                   int in, frac;
274 {
275   put_short(in);
276   put_short(frac);
277 }
278 
put_rect(x1,x2,y1,y2)279 static void put_rect(x1, x2, y1, y2)
280                  int x1, x2, y1, y2;
281 {
282   put_short(x1);
283   put_short(x2);
284   put_short(y1);
285   put_short(y2);
286 }
287 
put_fill(n)288 static void put_fill(n)
289                  int n;
290 {
291   int i;
292 
293    for (i=0; i<n; i++) { put_byte(0); }
294 }
295