/tags/Root-branch-php-utl/SWIG/Examples/GIFPlot/Lib/gif.c
C | 668 lines | 346 code | 119 blank | 203 comment | 52 complexity | e08ae7c2a38e812105b59d5fe8dd8ec1 MD5 | raw file
Possible License(s): LGPL-2.1, Cube, GPL-3.0, 0BSD, GPL-2.0
1
2/**********************************************************************
3 * GIFPlot 0.0
4 *
5 * Dave Beazley
6 *
7 * Department of Computer Science Theoretical Division (T-11)
8 * University of Utah Los Alamos National Laboratory
9 * Salt Lake City, Utah 84112 Los Alamos, New Mexico 87545
10 * beazley@cs.utah.edu beazley@lanl.gov
11 *
12 * Copyright (c) 1996
13 * The Regents of the University of California and the University of Utah
14 * All Rights Reserved
15 *
16 * Permission is hereby granted, without written agreement and without
17 * license or royalty fees, to use, copy, modify, and distribute this
18 * software and its documentation for any purpose, provided that
19 * (1) The above copyright notice and the following two paragraphs
20 * appear in all copies of the source code and (2) redistributions
21 * including binaries reproduces these notices in the supporting
22 * documentation. Substantial modifications to this software may be
23 * copyrighted by their authors and need not follow the licensing terms
24 * described here, provided that the new terms are clearly indicated in
25 * all files where they apply.
26 *
27 * IN NO EVENT SHALL THE AUTHOR, THE UNIVERSITY OF CALIFORNIA, THE
28 * UNIVERSITY OF UTAH OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY
29 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
30 * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
31 * EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 * THE AUTHOR, THE UNIVERSITY OF CALIFORNIA, AND THE UNIVERSITY OF UTAH
35 * SPECIFICALLY DISCLAIM ANY WARRANTIES,INCLUDING, BUT NOT LIMITED TO,
36 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
37 * PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND
38 * THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE,
39 * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
40 *
41 **************************************************************************/
42
43/*******************************************************************
44 * Creates a GIF format file.
45 *
46 * Dave Beazley (T-11)
47 * August 11, 1995
48 *
49 * Rather than writing directly to files, this module fills out
50 * output buffer.
51 *
52 * Note : To save memory, this routine uses approximately 50K of the
53 * output buffer as temporary storage (for hash tables and compression codes).
54 * The remainder of the output buffer is used to store the final image.
55 * This feature allows GIF images to be created with no additional
56 * memory overhead.
57 *
58 * -- Revision History
59 * $Log$
60 * Revision 1.2 2003/09/01 16:23:31 beazley
61 * Restored the 'mojo'.
62 *
63 * Revision 1.2 1996/09/25 22:39:30 dmb
64 * Fixed prototypes and use of void pointers for compatibility with the Cray T3D
65 *
66 * Revision 1.1 1996/09/10 17:44:00 dmb
67 * Initial revision
68 *
69 * Revision 1.2 1995/08/31 14:46:07 beazley
70 * Minor changes to support comments and a few bug fixes.
71 *
72 *
73 ******************************************************************/
74
75
76/*
77 * xvgifwr.c - handles writing of GIF files. based on flgife.c and
78 * flgifc.c from the FBM Library, by Michael Maudlin
79 *
80 * Contains:
81 * WriteGIF(fp, pic, ptype, w, h, rmap, gmap, bmap, numcols, colorstyle,
82 * comment)
83 *
84 * Note: slightly brain-damaged, in that it'll only write non-interlaced
85 * GIF files (in the interests of speed, or something)
86 *
87 */
88
89
90
91/*****************************************************************
92 * Portions of this code Copyright (C) 1989 by Michael Mauldin.
93 * Permission is granted to use this file in whole or in
94 * part for any purpose, educational, recreational or commercial,
95 * provided that this copyright notice is retained unchanged.
96 * This software is available to all free of charge by anonymous
97 * FTP and in the UUNET archives.
98 *
99 *
100 * Authors: Michael Mauldin (mlm@cs.cmu.edu)
101 * David Rowley (mgardi@watdcsu.waterloo.edu)
102 *
103 * Based on: compress.c - File compression ala IEEE Computer, June 1984.
104 *
105 * Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
106 * Jim McKie (decvax!mcvax!jim)
107 * Steve Davies (decvax!vax135!petsd!peora!srd)
108 * Ken Turkowski (decvax!decwrl!turtlevax!ken)
109 * James A. Woods (decvax!ihnp4!ames!jaw)
110 * Joe Orost (decvax!vax135!petsd!joe)
111 *****************************************************************/
112
113#include "gifplot.h"
114#include <string.h>
115typedef long int count_int;
116typedef unsigned char byte;
117
118static int gif_error;
119static unsigned char *op;
120static int Width, Height;
121static int curx, cury;
122static int Interlace;
123
124static void putgifword(int);
125static void compress(int, byte **, int);
126static void output_GIF(int);
127static void cl_block(void);
128static void cl_hash(count_int);
129static void char_init(void);
130static void char_out(int);
131static void flush_char(void);
132static void *OutBuffer;
133static int OutBufSize;
134static FrameBuffer *GIF_frame;
135
136static unsigned char pc2nc[256],r1[256],g1[256],b1[256];
137
138/*************************************************************/
139int FrameBuffer_makeGIF(FrameBuffer *f, ColorMap *c, void *outbuffer, unsigned int outbufsize)
140{
141 int RWidth, RHeight;
142 int LeftOfs, TopOfs;
143 int ColorMapSize, InitCodeSize, Background, BitsPerPixel;
144 int i,j,nc;
145 char *rmap, *gmap, *bmap;
146 char *cmap;
147 int count;
148
149 Interlace = 0;
150 Background = 0;
151 OutBuffer = outbuffer;
152 OutBufSize = outbufsize;
153 GIF_frame = f;
154 cmap = (char *) c->cmap;
155
156 op = (unsigned char *) outbuffer;
157 gif_error = 0;
158 for (i=0; i<256; i++) { pc2nc[i] = r1[i] = g1[i] = b1[i] = 0; }
159
160 /* compute number of unique colors */
161 nc = 0;
162 rmap = &cmap[0];
163 gmap = &cmap[256];
164 bmap = &cmap[512];
165
166 for (i=0; i<256; i++) {
167 /* see if color #i is already used */
168 for (j=0; j<i; j++) {
169 if (rmap[i] == rmap[j] && gmap[i] == gmap[j] &&
170 bmap[i] == bmap[j]) break;
171 }
172
173 if (j==i) { /* wasn't found */
174 pc2nc[i] = nc;
175 r1[nc] = rmap[i];
176 g1[nc] = gmap[i];
177 b1[nc] = bmap[i];
178 nc++;
179 }
180 else pc2nc[i] = pc2nc[j];
181 }
182
183 /* figure out 'BitsPerPixel' */
184 for (i=1; i<8; i++)
185 if ( (1<<i) >= nc) break;
186
187 BitsPerPixel = i;
188
189 ColorMapSize = 1 << BitsPerPixel;
190
191 RWidth = Width = f->width;
192 RHeight = Height = f->height;
193 LeftOfs = TopOfs = 0;
194
195 if (BitsPerPixel <= 1) InitCodeSize = 2;
196 else InitCodeSize = BitsPerPixel;
197
198 curx = 0;
199 cury = f->height - 1;
200
201 strcpy((char *) op,"GIF89a"); /* Put in GIF magic number */
202 op+=6;
203 putgifword(RWidth); /* screen descriptor */
204 putgifword(RHeight);
205
206 i = 0x80; /* Yes, there is a color map */
207 i |= (8-1)<<4; /* OR in the color resolution (hardwired 8) */
208 i |= (BitsPerPixel - 1); /* OR in the # of bits per pixel */
209 *(op++) = i;
210 *(op++) = Background; /* background color */
211 *(op++) = 0;
212 for (i=0; i<ColorMapSize; i++) { /* write out Global colormap */
213 *(op++) = r1[i];
214 *(op++) = g1[i];
215 *(op++) = b1[i];
216 }
217
218 *(op++) = ','; /* image separator */
219
220 /* Write the Image header */
221 putgifword(LeftOfs);
222 putgifword(TopOfs);
223 putgifword(Width);
224 putgifword(Height);
225 *(op++) = 0;
226 *(op++) = InitCodeSize;
227
228 compress(InitCodeSize+1, f->pixels, f->width*f->height);
229
230 *(op++) = 0;
231 *(op++) = ';';
232
233 count = (op - (unsigned char *) OutBuffer);
234 if (gif_error) return -1;
235 else return count;
236}
237
238/******************************/
239static void putgifword(w)
240int w;
241{
242 /* writes a 16-bit integer in GIF order (LSB first) */
243 *(op++) = w & 0xff;
244 *(op++) = (w>>8)&0xff;
245}
246
247/***********************************************************************/
248
249
250static unsigned long cur_accum = 0;
251static int cur_bits = 0;
252
253
254
255
256#define GP_BITS 12 /* BITS was already defined on some systems */
257
258#define HSIZE 5003 /* 80% occupancy */
259
260typedef unsigned char char_type;
261
262static int n_bits; /* number of bits/code */
263static int maxbits = GP_BITS; /* user settable max # bits/code */
264static int maxcode; /* maximum code, given n_bits */
265static int maxmaxcode = 1 << GP_BITS; /* NEVER generate this */
266
267#define MAXCODE(n_bits) ( (1 << (n_bits)) - 1)
268
269static count_int *htab;
270static unsigned short *codetab;
271static GIFOutBufSize;
272
273/* static count_int htab [HSIZE];
274static unsigned short codetab [HSIZE]; */
275
276#define HashTabOf(i) htab[i]
277#define CodeTabOf(i) codetab[i]
278
279static int hsize = HSIZE; /* for dynamic table sizing */
280
281/*
282 * To save much memory, we overlay the table used by compress() with those
283 * used by decompress(). The tab_prefix table is the same size and type
284 * as the codetab. The tab_suffix table needs 2**BITS characters. We
285 * get this from the beginning of htab. The output stack uses the rest
286 * of htab, and contains characters. There is plenty of room for any
287 * possible stack (stack used to be 8000 characters).
288 */
289
290#define tab_prefixof(i) CodeTabOf(i)
291#define tab_suffixof(i) ((char_type *)(htab))[i]
292#define de_stack ((char_type *)&tab_suffixof(1<<GP_BITS))
293
294static int free_ent = 0; /* first unused entry */
295
296/*
297 * block compression parameters -- after all codes are used up,
298 * and compression rate changes, start over.
299 */
300static int clear_flg = 0;
301
302static long int out_count = 0; /* # of codes output (for debugging) */
303
304/*
305 * compress stdin to stdout
306 *
307 * Algorithm: use open addressing double hashing (no chaining) on the
308 * prefix code / next character combination. We do a variant of Knuth's
309 * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
310 * secondary probe. Here, the modular division first probe is gives way
311 * to a faster exclusive-or manipulation. Also do block compression with
312 * an adaptive reset, whereby the code table is cleared when the compression
313 * ratio decreases, but after the table fills. The variable-length output
314 * codes are re-sized at this point, and a special CLEAR code is generated
315 * for the decompressor. Late addition: construct the table according to
316 * file size for noticeable speed improvement on small files. Please direct
317 * questions about this implementation to ames!jaw.
318 */
319
320static int g_init_bits;
321
322static int ClearCode;
323static int EOFCode;
324
325
326/********************************************************/
327static void compress(init_bits, data, len)
328 int init_bits;
329 unsigned char **data;
330 int len;
331{
332 register long fcode;
333 register int i = 0;
334 register int c;
335 register int ent;
336 register int disp;
337 register int hsize_reg;
338 register int hshift;
339 int code_count = 0;
340
341 /* Use the output buffer as temporary storage for GIF data */
342
343 if (OutBufSize < HSIZE*(sizeof(count_int) + sizeof(unsigned short))) {
344 gif_error =1;
345 return;
346 }
347
348 /* Put htab and codetab arrays into the output buffer */
349
350 GIFOutBufSize = OutBufSize - HSIZE*(sizeof(count_int) + sizeof(unsigned short)) - 16;
351 GIFOutBufSize = GIFOutBufSize & (~0x3); /* Make sure it's double word alligned */
352
353 htab = (count_int *) ((char *) OutBuffer + GIFOutBufSize);
354 codetab = (unsigned short *) ((char *) OutBuffer + GIFOutBufSize + HSIZE*sizeof(count_int));
355
356 /*
357 * Set up the globals: g_init_bits - initial number of bits
358 * g_outfile - pointer to output file
359 */
360 g_init_bits = init_bits;
361
362
363 /* initialize 'compress' globals */
364 maxbits = GP_BITS;
365 maxmaxcode = 1<<GP_BITS;
366 memset(htab,0,sizeof(htab));
367 memset(codetab,0,sizeof(codetab));
368 hsize = HSIZE;
369 free_ent = 0;
370 clear_flg = 0;
371 out_count = 0;
372 cur_accum = 0;
373 cur_bits = 0;
374
375 /*
376 * Set up the necessary values
377 */
378 out_count = 0;
379 clear_flg = 0;
380 maxcode = MAXCODE(n_bits = g_init_bits);
381
382 ClearCode = (1 << (init_bits - 1));
383 EOFCode = ClearCode + 1;
384 free_ent = ClearCode + 2;
385
386 char_init();
387 ent = pc2nc[data[cury][curx]];
388 curx++;
389 if (curx >= GIF_frame->width) {
390 curx = 0;
391 cury--;
392 }
393 len--;
394
395 hshift = 0;
396 for ( fcode = (long) hsize; fcode < 65536L; fcode *= 2L )
397 hshift++;
398 hshift = 8 - hshift; /* set hash code range bound */
399
400 hsize_reg = hsize;
401 cl_hash( (count_int) hsize_reg); /* clear hash table */
402
403 output_GIF(ClearCode);
404 while (len) {
405 c = pc2nc[data[cury][curx]];
406 curx++;
407 if (curx >= GIF_frame->width) {
408 curx = 0;
409 cury--;
410 }
411 len--;
412
413 fcode = (long) ( ( (long) c << maxbits) + ent);
414 i = (((int) c << hshift) ^ ent); /* xor hashing */
415
416 if ( HashTabOf (i) == fcode ) {
417 ent = CodeTabOf (i);
418 continue;
419 }
420
421 if ( (long)HashTabOf (i) < 0 ) /* empty slot */
422 goto nomatch;
423
424 disp = hsize_reg - i; /* secondary hash (after G. Knott) */
425 if ( i == 0 )
426 disp = 1;
427
428probe:
429 if ( (i -= disp) < 0 )
430 i += hsize_reg;
431
432 if ( HashTabOf (i) == fcode ) {
433 ent = CodeTabOf (i);
434 continue;
435 }
436
437 if ( (long)HashTabOf (i) >= 0 )
438 goto probe;
439
440nomatch:
441 output_GIF(ent);
442 out_count++;
443 ent = c;
444
445 if ( free_ent < maxmaxcode ) {
446 CodeTabOf (i) = free_ent++; /* code -> hashtable */
447 HashTabOf (i) = fcode;
448 }
449 else
450 cl_block();
451
452 }
453 /* Put out the final code */
454 output_GIF(ent);
455 output_GIF(EOFCode);
456}
457
458
459/*****************************************************************
460 * TAG( output_GIF )
461 *
462 * Output the given code.
463 * Inputs:
464 * code: A n_bits-bit integer. If == -1, then EOF. This assumes
465 * that n_bits =< (long)wordsize - 1.
466 * Outputs:
467 * Outputs code to the file.
468 * Assumptions:
469 * Chars are 8 bits long.
470 * Algorithm:
471 * Maintain a BITS character long buffer (so that 8 codes will
472 * fit in it exactly). Use the VAX insv instruction to insert each
473 * code in turn. When the buffer fills up empty it and start over.
474 */
475
476static
477unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
478 0x001F, 0x003F, 0x007F, 0x00FF,
479 0x01FF, 0x03FF, 0x07FF, 0x0FFF,
480 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
481
482static void output_GIF(code)
483int code;
484{
485 cur_accum &= masks[cur_bits];
486
487 if (cur_bits > 0)
488 cur_accum |= ((long)code << cur_bits);
489 else
490 cur_accum = code;
491
492 cur_bits += n_bits;
493
494 while( cur_bits >= 8 ) {
495 char_out( (int) (cur_accum & 0xff) );
496 cur_accum >>= 8;
497 cur_bits -= 8;
498 }
499
500 /*
501 * If the next entry is going to be too big for the code size,
502 * then increase it, if possible.
503 */
504
505 if (free_ent > maxcode || clear_flg) {
506
507 if( clear_flg ) {
508 maxcode = MAXCODE (n_bits = g_init_bits);
509 clear_flg = 0;
510 }
511 else {
512 n_bits++;
513 if ( n_bits == maxbits )
514 maxcode = maxmaxcode;
515 else
516 maxcode = MAXCODE(n_bits);
517 }
518 }
519
520 if( code == EOFCode ) {
521 /* At EOF, write the rest of the buffer */
522 while( cur_bits > 0 ) {
523 char_out( (int)(cur_accum & 0xff) );
524 cur_accum >>= 8;
525 cur_bits -= 8;
526 }
527
528 flush_char();
529 }
530}
531
532
533/********************************/
534static void cl_block () /* table clear for block compress */
535{
536 /* Clear out the hash table */
537
538 cl_hash ( (count_int) hsize );
539 free_ent = ClearCode + 2;
540 clear_flg = 1;
541
542 output_GIF(ClearCode);
543}
544
545
546/********************************/
547static void cl_hash(hsize) /* reset code table */
548register count_int hsize;
549{
550 register count_int *htab_p = htab+hsize;
551 register long i;
552 register long m1 = -1;
553
554 i = hsize - 16;
555 do { /* might use Sys V memset(3) here */
556 *(htab_p-16) = m1;
557 *(htab_p-15) = m1;
558 *(htab_p-14) = m1;
559 *(htab_p-13) = m1;
560 *(htab_p-12) = m1;
561 *(htab_p-11) = m1;
562 *(htab_p-10) = m1;
563 *(htab_p-9) = m1;
564 *(htab_p-8) = m1;
565 *(htab_p-7) = m1;
566 *(htab_p-6) = m1;
567 *(htab_p-5) = m1;
568 *(htab_p-4) = m1;
569 *(htab_p-3) = m1;
570 *(htab_p-2) = m1;
571 *(htab_p-1) = m1;
572 htab_p -= 16;
573 } while ((i -= 16) >= 0);
574
575 for ( i += 16; i > 0; i-- )
576 *--htab_p = m1;
577}
578
579
580/******************************************************************************
581 *
582 * GIF Specific routines
583 *
584 ******************************************************************************/
585
586/*
587 * Number of characters so far in this 'packet'
588 */
589static int a_count;
590
591/*
592 * Set up the 'byte output' routine
593 */
594static void char_init()
595{
596 a_count = 0;
597}
598
599/*
600 * Define the storage for the packet accumulator
601 */
602static char accum[ 256 ];
603
604/*
605 * Add a character to the end of the current packet, and if it is 254
606 * characters, flush the packet to disk.
607 */
608static void char_out(c)
609int c;
610{
611 accum[ a_count++ ] = c;
612 if( a_count >= 254 )
613 flush_char();
614}
615
616/*
617 * Flush the packet to disk, and reset the accumulator
618 */
619static void flush_char()
620{
621 if (gif_error) return;
622 if( a_count > 0 ) {
623 *(op++) = a_count;
624 memcpy(op,accum,a_count);
625 op+=a_count;
626 a_count = 0;
627
628 if (op > (unsigned char *) ((char *) OutBuffer + (GIFOutBufSize - 2048))) {
629 gif_error = 1;
630 }
631 }
632}
633
634
635/* ----------------------------------------------------------------------
636 int FrameBuffer_writeGIF(char *filename)
637
638 Write a GIF file to filename
639 ----------------------------------------------------------------------- */
640
641int FrameBuffer_writeGIF(FrameBuffer *f, ColorMap *c, char *filename) {
642
643 FILE *file;
644 void *buffer;
645 int nbytes;
646 int bufsize;
647
648 file = fopen(filename,"wb");
649 if (file == NULL) return -1;
650
651 bufsize = (f->width*f->height*3)/2;
652 buffer = (void *) malloc(bufsize);
653 nbytes = FrameBuffer_makeGIF(f,c,buffer,bufsize);
654 if (nbytes == -1) {
655 free(buffer);
656 fclose(file);
657 return -1;
658 }
659 fwrite(buffer,nbytes,1,file);
660 fclose(file);
661 free(buffer);
662 return 0;
663}
664
665
666
667
668