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