"Fossies" - the Fresh Open Source Software Archive 
Member "xearth-1.1/gifout.c" (7 Nov 1999, 12059 Bytes) of package /linux/misc/old/xearth-1.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*
2 * giflib/gifout.c
3 * kirk johnson
4 * may 1990
5 *
6 * Copyright (C) 1989, 1990, 1993-1995, 1999 Kirk Lauritz Johnson
7 *
8 * Parts of the source code (as marked) are:
9 * Copyright (C) 1989, 1990, 1991 by Jim Frost
10 * Copyright (C) 1992 by Jamie Zawinski <jwz@lucid.com>
11 *
12 * Permission to use, copy, modify and freely distribute xearth for
13 * non-commercial and not-for-profit purposes is hereby granted
14 * without fee, provided that both the above copyright notice and this
15 * permission notice appear in all copies and in supporting
16 * documentation.
17 *
18 * Unisys Corporation holds worldwide patent rights on the Lempel Zev
19 * Welch (LZW) compression technique employed in the CompuServe GIF
20 * image file format as well as in other formats. Unisys has made it
21 * clear, however, that it does not require licensing or fees to be
22 * paid for freely distributed, non-commercial applications (such as
23 * xearth) that employ LZW/GIF technology. Those wishing further
24 * information about licensing the LZW patent should contact Unisys
25 * directly at (lzw_info@unisys.com) or by writing to
26 *
27 * Unisys Corporation
28 * Welch Licensing Department
29 * M/S-C1SW19
30 * P.O. Box 500
31 * Blue Bell, PA 19424
32 *
33 * The author makes no representations about the suitability of this
34 * software for any purpose. It is provided "as is" without express or
35 * implied warranty.
36 *
37 * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
38 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
39 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT
40 * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
41 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
42 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
43 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
44 */
45
46 #include <stdio.h>
47 #include "port.h"
48 #include "gifint.h"
49 #include "kljcpyrt.h"
50
51
52 /****
53 **
54 ** local #defines
55 **
56 ****/
57
58 #define HASHSZ (2048)
59 #define HASH(p, e) (((p)&(HASHSZ-1))^(e))
60
61 #define PUT_CODE(val) \
62 { \
63 work_data |= ((long) (val) << work_bits); \
64 work_bits += code_size; \
65 while (work_bits >= 8) \
66 { \
67 PUT_BYTE(work_data & 0xFF); \
68 work_data >>= 8; \
69 work_bits -= 8; \
70 } \
71 }
72
73 #define PUT_BYTE(val) \
74 { \
75 buf[buf_idx++] = (val); \
76 if (buf_idx == 255) \
77 { \
78 write_data_block(255, buf, outs); \
79 buf_idx = 0; \
80 } \
81 }
82
83
84 /****
85 **
86 ** local variables
87 **
88 ****/
89
90 static int cmap_bits _P((int));
91 static int root_bits _P((int));
92 static void put_clr_code _P((void));
93 static void write_data_block _P((int, BYTE *, FILE *));
94 static void reset_string_out _P((void));
95 static void add_string_out _P((int, int));
96 static int find_string_out _P((int, int));
97 static void gifout_fatal _P((const char *)) _noreturn;
98
99
100 static BYTE file_open = 0; /* status flags */
101 static BYTE image_open = 0;
102
103 static int rast_width; /* raster width */
104 static int rast_height; /* raster height */
105 static int ncolors; /* number of colors */
106 static int img_width; /* image width */
107 static int img_height; /* image height */
108
109 static FILE *outs; /* output file */
110
111 static int root_size; /* root code size */
112 static int clr_code; /* clear code */
113 static int eoi_code; /* end of info code */
114 static int code_size; /* current code size */
115 static int code_mask; /* current code mask */
116 static int old_code; /* previous code */
117
118 static long work_data; /* working bits */
119 static int work_bits; /* working bit count */
120
121 static BYTE buf[256]; /* byte buffer */
122 static int buf_idx; /* buffer index */
123
124 static int table_size; /* string table size */
125 static int htable[HASHSZ];
126 static int pref_extn[STAB_SIZE]; /* (prefix << 16) | extension */
127 static int next[STAB_SIZE];
128
129
130 /****
131 **
132 ** exported procedures
133 **
134 ****/
135
136 /*
137 * open a GIF file for writing on stream s
138 */
139 int gifout_open_file(s, w, h, sz, cmap, bg)
140 FILE *s;
141 int w; /* raster width (in pixels) */
142 int h; /* raster height (in pixels) */
143 int sz; /* number of colors */
144 BYTE cmap[3][256]; /* global colormap */
145 int bg; /* background color index */
146 {
147 int i;
148 int pixel_bits;
149
150 /* make sure there isn't already a file open */
151 if (file_open)
152 return GIFLIB_ERR_FAO;
153
154 /* remember that we've got this file open */
155 file_open = 1;
156 outs = s;
157 rast_width = w;
158 rast_height = h;
159
160 /* write GIF signature */
161 if (fwrite(GIF_SIG, sizeof(char), GIF_SIG_LEN, outs) != GIF_SIG_LEN)
162 return GIFLIB_ERR_OUT;
163
164 /* write screen descriptor */
165 pixel_bits = cmap_bits(sz);
166 ncolors = 1 << pixel_bits;
167
168 buf[0] = (w & 0x00FF);
169 buf[1] = (w & 0xFF00) >> 8;
170 buf[2] = (h & 0x00FF);
171 buf[3] = (h & 0xFF00) >> 8;
172 buf[4] = (pixel_bits - 1) | 0x80;
173 buf[5] = bg;
174 buf[6] = 0;
175
176 if (fwrite(buf, sizeof(char), GIF_SD_SIZE, outs) != GIF_SD_SIZE)
177 return GIFLIB_ERR_OUT;
178
179 /* write (global) color map */
180 for (i=0; i<sz; i++)
181 {
182 buf[GIFLIB_RED] = cmap[GIFLIB_RED][i];
183 buf[GIFLIB_GRN] = cmap[GIFLIB_GRN][i];
184 buf[GIFLIB_BLU] = cmap[GIFLIB_BLU][i];
185
186 if (fwrite(buf, sizeof(BYTE), (unsigned) 3, outs) != 3)
187 return GIFLIB_ERR_OUT;
188 }
189
190 for (i=sz; i<ncolors; i++)
191 {
192 buf[GIFLIB_RED] = 0;
193 buf[GIFLIB_GRN] = 0;
194 buf[GIFLIB_BLU] = 0;
195
196 if (fwrite(buf, sizeof(BYTE), (unsigned) 3, outs) != 3)
197 return GIFLIB_ERR_OUT;
198 }
199
200 /* done! */
201 return GIFLIB_SUCCESS;
202 }
203
204
205 /*
206 * open a new GIF image for writing in the current GIF file
207 */
208 int gifout_open_image(left, top, w, h)
209 int left; /* column index for left edge */
210 int top; /* row index for top edge */
211 int w; /* image width (in pixels) */
212 int h; /* image height (in pixels) */
213 {
214 /* make sure there's a file open */
215 if (!file_open)
216 return GIFLIB_ERR_NFO;
217
218 /* make sure there isn't already an image open */
219 if (image_open)
220 return GIFLIB_ERR_IAO;
221
222 /* remember that we've got this image open */
223 image_open = 1;
224 img_width = w;
225 img_height = h;
226
227 /* write image separator */
228 putc(GIF_SEPARATOR, outs);
229
230 /* write image descriptor */
231 buf[0] = (left & 0x00FF);
232 buf[1] = (left & 0xFF00) >> 8;
233 buf[2] = (top & 0x00FF);
234 buf[3] = (top & 0xFF00) >> 8;
235 buf[4] = (w & 0x00FF);
236 buf[5] = (w & 0xFF00) >> 8;
237 buf[6] = (h & 0x00FF);
238 buf[7] = (h & 0xFF00) >> 8;
239 buf[8] = 0;
240
241 if (fwrite(buf, sizeof(BYTE), GIF_ID_SIZE, outs) != GIF_ID_SIZE)
242 return GIFLIB_ERR_OUT;
243
244 /* initialize raster data stream */
245 root_size = root_bits(ncolors);
246 putc(root_size, outs);
247
248 clr_code = 1 << root_size;
249 eoi_code = clr_code + 1;
250 code_size = root_size + 1;
251 code_mask = (1 << code_size) - 1;
252 old_code = NULL_CODE;
253
254 work_bits = 0;
255 work_data = 0;
256
257 buf_idx = 0;
258
259 /* initialize string table */
260 reset_string_out();
261
262 /* output initial clear code */
263 put_clr_code();
264
265 /* done! */
266 return GIFLIB_SUCCESS;
267 }
268
269
270 /*
271 * write a pixel into the current image
272 */
273 void gifout_put_pixel(val)
274 int val; /* pixel color index */
275 {
276 int idx;
277
278 /* see if string is in table already */
279 idx = find_string_out(old_code, val);
280
281 if (idx != NULL_CODE)
282 {
283 /* found a match */
284 old_code = idx;
285 }
286 else
287 {
288 /* no match */
289 PUT_CODE(old_code);
290 add_string_out(old_code, val);
291 old_code = val;
292
293 /* check for full string table */
294 if (table_size == STAB_SIZE)
295 {
296 /* output remaining code */
297 PUT_CODE(old_code);
298
299 /* reset encoder */
300 put_clr_code();
301 }
302 }
303 }
304
305
306 /*
307 * write a row of pixels into the current image
308 */
309 void gifout_put_row(row)
310 int *row; /* array of size img_width */
311 {
312 int col;
313 int idx;
314
315 for (col=0; col<img_width; col++)
316 {
317 /* see if string is in table already */
318 idx = find_string_out(old_code, row[col]);
319
320 if (idx != NULL_CODE)
321 {
322 /* found a match */
323 old_code = idx;
324 }
325 else
326 {
327 /* no match */
328 PUT_CODE(old_code);
329 add_string_out(old_code, row[col]);
330 old_code = row[col];
331
332 /* check for full string table */
333 if (table_size == STAB_SIZE)
334 {
335 /* output remaining code */
336 PUT_CODE(old_code);
337
338 /* reset encoder */
339 put_clr_code();
340 }
341 }
342 }
343 }
344
345
346 /*
347 * close an open GIF image
348 */
349 int gifout_close_image()
350 {
351 /* make sure there's an image open */
352 if (!image_open)
353 return GIFLIB_ERR_NIO;
354
355 /* flush any remaining code */
356 if (old_code != NULL_CODE)
357 PUT_CODE(old_code);
358
359 /* output end of info code */
360 PUT_CODE(eoi_code);
361
362 /* flush any extra bits */
363 while (work_bits > 0)
364 {
365 PUT_BYTE(work_data & 0xFF);
366 work_data >>= 8;
367 work_bits -= 8;
368 }
369
370 /* flush any extra bytes */
371 if (buf_idx > 0)
372 write_data_block(buf_idx, buf, outs);
373
374 /* trailing zero byte */
375 putc(0, outs);
376
377 /* mark image as closed */
378 image_open = 0;
379
380 /* done! */
381 return GIFLIB_SUCCESS;
382 }
383
384
385 /*
386 * close an open GIF file
387 */
388 int gifout_close_file()
389 {
390 /* make sure there's a file open */
391 if (!file_open)
392 return GIFLIB_ERR_NFO;
393
394 /* make sure there isn't an image open */
395 if (image_open)
396 return GIFLIB_ERR_ISO;
397
398 /* write gif terminator */
399 putc(GIF_TERMINATOR, outs);
400
401 /* mark file as closed */
402 file_open = 0;
403
404 /* done! */
405 return GIFLIB_SUCCESS;
406 }
407
408
409 /****
410 **
411 ** internal procedures
412 **
413 ****/
414
415 static int cmap_bits(n)
416 int n;
417 {
418 int nbits;
419
420 if (n < 2)
421 gifout_fatal("cmap_bits(): argument out of range");
422
423 n -= 1;
424 nbits = 0;
425
426 while (n != 0)
427 {
428 n >>= 1;
429 nbits += 1;
430 }
431
432 return nbits;
433 }
434
435
436 static int root_bits(n)
437 int n;
438 {
439 int rslt;
440
441 rslt = cmap_bits(n);
442 if (rslt < 2)
443 rslt = 2;
444
445 return rslt;
446 }
447
448
449 static void put_clr_code()
450 {
451 /* output clear code */
452 PUT_CODE(clr_code);
453
454 /* reset raster data stream */
455 code_size = root_size + 1;
456 code_mask = (1 << code_size) - 1;
457 old_code = NULL_CODE;
458
459 /* clear the string table */
460 reset_string_out();
461 }
462
463
464 static void write_data_block(cnt, outbuf, s)
465 int cnt;
466 BYTE *outbuf;
467 FILE *s;
468 {
469 putc(cnt, s);
470
471 if (fwrite(outbuf, sizeof(BYTE), (unsigned) cnt, s) != cnt)
472 gifout_fatal("write_data_block(): problems writing data block");
473 }
474
475
476 static void reset_string_out()
477 {
478 int i;
479
480 for (i=0; i<HASHSZ; i++)
481 htable[i] = NULL_CODE;
482
483 table_size = eoi_code + 1;
484 }
485
486
487 static void add_string_out(p, e)
488 int p;
489 int e;
490 {
491 int idx;
492
493 idx = HASH(p, e);
494
495 pref_extn[table_size] = (p << 16) | e;
496 next[table_size] = htable[idx];
497 htable[idx] = table_size;
498
499 if ((table_size > code_mask) && (code_size < 12))
500 {
501 code_size += 1;
502 code_mask = (1 << code_size) - 1;
503 }
504
505 table_size += 1;
506 }
507
508
509 static int find_string_out(p, e)
510 int p;
511 int e;
512 {
513 int idx;
514 int tmp;
515 int rslt;
516
517 if (p == NULL_CODE)
518 {
519 /* a lone symbol is always in table */
520 rslt = e;
521 }
522 else
523 {
524 rslt = NULL_CODE;
525
526 /* search the hash table */
527 idx = htable[HASH(p, e)];
528 tmp = (p << 16) | e;
529 while (idx != NULL_CODE)
530 {
531 if (pref_extn[idx] == tmp)
532 {
533 rslt = idx;
534 break;
535 }
536 else
537 {
538 idx = next[idx];
539 }
540 }
541 }
542
543 return rslt;
544 }
545
546
547 /*
548 * semi-graceful fatal error mechanism
549 */
550 static void gifout_fatal(msg)
551 const char *msg;
552 {
553 fprintf(stderr, "\n");
554 fprintf(stderr, "gifout.c: fatal error\n");
555 fprintf(stderr, " %s\n", msg);
556 exit(1);
557 }