1 #include <stdio.h>
2 
3 /*
4  *
5  * Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>.A
6  * Lempel-Zim compression based on "compress".
7  *
8  * The Graphics Interchange Format(c) is the Copyright property of
9  * CompuServe Incorporated.  GIF(sm) is a Service Mark property of
10  * CompuServe Incorporated.
11  *
12  */
13 
14 /*
15  * Pointer to function returning an int
16  */
17 typedef int (* ifunptr)();
18 
19 /*
20  * a code_int must be able to hold 2**BITS values of type int, and also -1
21  */
22 typedef int             code_int;
23 
24 #ifdef SIGNED_COMPARE_SLOW
25 typedef unsigned long int count_int;
26 typedef unsigned short int count_short;
27 #else /*SIGNED_COMPARE_SLOW*/
28 typedef long int          count_int;
29 #endif /*SIGNED_COMPARE_SLOW*/
30 
31 static int colorstobpp();
32 static int GetPixel();
33 static void BumpPixel();
34 static int GIFNextPixel();
35 static void GIFEncode();
36 static void Putword();
37 static void compress();
38 static void output();
39 static void cl_block();
40 static void cl_hash();
41 static void writeerr();
42 static void char_init();
43 static void char_out();
44 static void flush_char();
45 
46 static unsigned char *pixels;
47 static unsigned int pwidth;
48 
49 struct rgb_color {
50 	unsigned int red, green, blue;
51 };
52 
53 void
WriteGif(filename,data,width,height,colrs)54 WriteGif(filename, data, width, height, colrs)
55 	char *filename;
56 	unsigned char *data;
57 	unsigned int width, height;
58 	struct rgb_color *colrs;
59 {
60 	FILE *fp;
61 	int i;
62 	int Red[256];
63 	int Green[256];
64 	int Blue[256];
65 
66 	if (strcmp(filename, "") == 0)
67 	{
68 		fp = NULL;
69 	}
70 	else
71 	{
72 		fp = fopen(filename, "w");
73 	}
74 	if (fp == NULL)
75 	{
76 		fprintf(stderr, "Cannot open %s for writing\n", filename);
77 		fclose(fp);
78 	}
79 	else
80 	{
81 
82 
83 		for (i = 0; i < 256; ++i)
84 		{
85 			Red[i] = colrs[i].red;
86 			Green[i] = colrs[i].green;
87 			Blue[i] = colrs[i].blue;
88 		}
89 		pixels = data;
90 		pwidth = width;
91 
92 		GIFEncode(fp, width, height, 0, 0, 8, Red, Green, Blue,
93 				GetPixel);
94 		fclose(fp);
95 	}
96 }
97 
98 
99 static int
GetPixel(x,y)100 GetPixel(x, y)
101 	int x, y;
102 {
103 	int color;
104 	unsigned char *ptr;
105 
106 	ptr = (unsigned char *)(pixels + (y * pwidth) + x);
107 	color = (int)(*ptr);
108 
109 	return(color);
110 }
111 
112 
113 /*****************************************************************************
114  *
115  * GIFENCODE.C    - GIF Image compression interface
116  *
117  * GIFEncode( FName, GWidth, GHeight, GInterlace, Background,
118  *            BitsPerPixel, Red, Green, Blue, GetPixel )
119  *
120  *****************************************************************************/
121 
122 #define TRUE 1
123 #define FALSE 0
124 
125 static int Width, Height;
126 static int curx, cury;
127 static long CountDown;
128 static int Pass = 0;
129 static int Interlace;
130 
131 /*
132  * Bump the 'curx' and 'cury' to point to the next pixel
133  */
134 static void
BumpPixel()135 BumpPixel()
136 {
137         /*
138          * Bump the current X position
139          */
140         ++curx;
141 
142         /*
143          * If we are at the end of a scan line, set curx back to the beginning
144          * If we are interlaced, bump the cury to the appropriate spot,
145          * otherwise, just increment it.
146          */
147         if( curx == Width ) {
148                 curx = 0;
149 
150                 if( !Interlace )
151                         ++cury;
152                 else {
153                      switch( Pass ) {
154 
155                        case 0:
156                           cury += 8;
157                           if( cury >= Height ) {
158                                 ++Pass;
159                                 cury = 4;
160                           }
161                           break;
162 
163                        case 1:
164                           cury += 8;
165                           if( cury >= Height ) {
166                                 ++Pass;
167                                 cury = 2;
168                           }
169                           break;
170 
171                        case 2:
172                           cury += 4;
173                           if( cury >= Height ) {
174                              ++Pass;
175                              cury = 1;
176                           }
177                           break;
178 
179                        case 3:
180                           cury += 2;
181                           break;
182                         }
183                 }
184         }
185 }
186 
187 /*
188  * Return the next pixel from the image
189  */
190 static int
GIFNextPixel(getpixel)191 GIFNextPixel( getpixel )
192 ifunptr getpixel;
193 {
194         int r;
195 
196         if( CountDown == 0 )
197                 return EOF;
198 
199         --CountDown;
200 
201         r = ( * getpixel )( curx, cury );
202 
203         BumpPixel();
204 
205         return r;
206 }
207 
208 /* public */
209 
210 static void
GIFEncode(fp,GWidth,GHeight,GInterlace,Background,BitsPerPixel,Red,Green,Blue,GetPixel)211 GIFEncode( fp, GWidth, GHeight, GInterlace, Background,
212            BitsPerPixel, Red, Green, Blue, GetPixel )
213 
214 FILE* fp;
215 int GWidth, GHeight;
216 int GInterlace;
217 int Background;
218 int BitsPerPixel;
219 int Red[], Green[], Blue[];
220 ifunptr GetPixel;
221 {
222         int B;
223         int RWidth, RHeight;
224         int LeftOfs, TopOfs;
225         int Resolution;
226         int ColorMapSize;
227         int InitCodeSize;
228         int i;
229 
230         Interlace = GInterlace;
231 
232         ColorMapSize = 1 << BitsPerPixel;
233 
234         RWidth = Width = GWidth;
235         RHeight = Height = GHeight;
236         LeftOfs = TopOfs = 0;
237 
238         Resolution = BitsPerPixel;
239 
240         /*
241          * Calculate number of bits we are expecting
242          */
243         CountDown = (long)Width * (long)Height;
244 
245         /*
246          * Indicate which pass we are on (if interlace)
247          */
248         Pass = 0;
249 
250         /*
251          * The initial code size
252          */
253         if( BitsPerPixel <= 1 )
254                 InitCodeSize = 2;
255         else
256                 InitCodeSize = BitsPerPixel;
257 
258         /*
259          * Set up the current x and y position
260          */
261         curx = cury = 0;
262 
263         /*
264          * Write the Magic header
265          */
266         fwrite( "GIF87a", 1, 6, fp );
267 
268         /*
269          * Write out the screen width and height
270          */
271         Putword( RWidth, fp );
272         Putword( RHeight, fp );
273 
274         /*
275          * Indicate that there is a global colour map
276          */
277         B = 0x80;       /* Yes, there is a color map */
278 
279         /*
280          * OR in the resolution
281          */
282         B |= (Resolution - 1) << 5;
283 
284         /*
285          * OR in the Bits per Pixel
286          */
287         B |= (BitsPerPixel - 1);
288 
289         /*
290          * Write it out
291          */
292         fputc( B, fp );
293 
294         /*
295          * Write out the Background colour
296          */
297         fputc( Background, fp );
298 
299         /*
300          * Byte of 0's (future expansion)
301          */
302         fputc( 0, fp );
303 
304         /*
305          * Write out the Global Colour Map
306          */
307         for( i=0; i<ColorMapSize; ++i ) {
308                 fputc( Red[i], fp );
309                 fputc( Green[i], fp );
310                 fputc( Blue[i], fp );
311         }
312 
313         /*
314          * Write an Image separator
315          */
316         fputc( ',', fp );
317 
318         /*
319          * Write the Image header
320          */
321 
322         Putword( LeftOfs, fp );
323         Putword( TopOfs, fp );
324         Putword( Width, fp );
325         Putword( Height, fp );
326 
327         /*
328          * Write out whether or not the image is interlaced
329          */
330         if( Interlace )
331                 fputc( 0x40, fp );
332         else
333                 fputc( 0x00, fp );
334 
335         /*
336          * Write out the initial code size
337          */
338         fputc( InitCodeSize, fp );
339 
340         /*
341          * Go and actually compress the data
342          */
343         compress( InitCodeSize+1, fp, GetPixel );
344 
345         /*
346          * Write out a Zero-length packet (to end the series)
347          */
348         fputc( 0, fp );
349 
350         /*
351          * Write the GIF file terminator
352          */
353         fputc( ';', fp );
354 
355         /*
356          * And close the file
357          */
358         fclose( fp );
359 }
360 
361 /*
362  * Write out a word to the GIF file
363  */
364 static void
Putword(w,fp)365 Putword( w, fp )
366 int w;
367 FILE* fp;
368 {
369         fputc( w & 0xff, fp );
370         fputc( (w / 256) & 0xff, fp );
371 }
372 
373 
374 /***************************************************************************
375  *
376  *  GIFCOMPR.C       - GIF Image compression routines
377  *
378  *  Lempel-Ziv compression based on 'compress'.  GIF modifications by
379  *  David Rowley (mgardi@watdcsu.waterloo.edu)
380  *
381  ***************************************************************************/
382 
383 /*
384  * General DEFINEs
385  */
386 
387 #define BITS    12
388 
389 #define HSIZE  5003            /* 80% occupancy */
390 
391 #ifdef NO_UCHAR
392  typedef char   char_type;
393 #else /*NO_UCHAR*/
394  typedef        unsigned char   char_type;
395 #endif /*NO_UCHAR*/
396 
397 /*
398  *
399  * GIF Image compression - modified 'compress'
400  *
401  * Based on: compress.c - File compression ala IEEE Computer, June 1984.
402  *
403  * By Authors:  Spencer W. Thomas       (decvax!harpo!utah-cs!utah-gr!thomas)
404  *              Jim McKie               (decvax!mcvax!jim)
405  *              Steve Davies            (decvax!vax135!petsd!peora!srd)
406  *              Ken Turkowski           (decvax!decwrl!turtlevax!ken)
407  *              James A. Woods          (decvax!ihnp4!ames!jaw)
408  *              Joe Orost               (decvax!vax135!petsd!joe)
409  *
410  */
411 #include <ctype.h>
412 
413 #define ARGVAL() (*++(*argv) || (--argc && *++argv))
414 
415 static int n_bits;                        /* number of bits/code */
416 static int maxbits = BITS;                /* user settable max # bits/code */
417 static code_int maxcode;                  /* maximum code, given n_bits */
418 static code_int maxmaxcode = (code_int)1 << BITS; /* should NEVER generate this code */
419 #ifdef COMPATIBLE               /* But wrong! */
420 # define MAXCODE(n_bits)        ((code_int) 1 << (n_bits) - 1)
421 #else /*COMPATIBLE*/
422 # define MAXCODE(n_bits)        (((code_int) 1 << (n_bits)) - 1)
423 #endif /*COMPATIBLE*/
424 
425 static count_int htab [HSIZE];
426 static unsigned short codetab [HSIZE];
427 #define HashTabOf(i)       htab[i]
428 #define CodeTabOf(i)    codetab[i]
429 
430 static code_int hsize = HSIZE;                 /* for dynamic table sizing */
431 
432 /*
433  * To save much memory, we overlay the table used by compress() with those
434  * used by decompress().  The tab_prefix table is the same size and type
435  * as the codetab.  The tab_suffix table needs 2**BITS characters.  We
436  * get this from the beginning of htab.  The output stack uses the rest
437  * of htab, and contains characters.  There is plenty of room for any
438  * possible stack (stack used to be 8000 characters).
439  */
440 
441 #define tab_prefixof(i) CodeTabOf(i)
442 #define tab_suffixof(i)        ((char_type*)(htab))[i]
443 #define de_stack               ((char_type*)&tab_suffixof((code_int)1<<BITS))
444 
445 static code_int free_ent = 0;                  /* first unused entry */
446 
447 /*
448  * block compression parameters -- after all codes are used up,
449  * and compression rate changes, start over.
450  */
451 static int clear_flg = 0;
452 
453 static int offset;
454 static long int in_count = 1;            /* length of input */
455 static long int out_count = 0;           /* # of codes output (for debugging) */
456 
457 /*
458  * compress stdin to stdout
459  *
460  * Algorithm:  use open addressing double hashing (no chaining) on the
461  * prefix code / next character combination.  We do a variant of Knuth's
462  * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
463  * secondary probe.  Here, the modular division first probe is gives way
464  * to a faster exclusive-or manipulation.  Also do block compression with
465  * an adaptive reset, whereby the code table is cleared when the compression
466  * ratio decreases, but after the table fills.  The variable-length output
467  * codes are re-sized at this point, and a special CLEAR code is generated
468  * for the decompressor.  Late addition:  construct the table according to
469  * file size for noticeable speed improvement on small files.  Please direct
470  * questions about this implementation to ames!jaw.
471  */
472 
473 static int g_init_bits;
474 static FILE* g_outfile;
475 
476 static int ClearCode;
477 static int EOFCode;
478 
479 static unsigned long cur_accum = 0;
480 static int cur_bits = 0;
481 
482 static void
compress(init_bits,outfile,ReadValue)483 compress( init_bits, outfile, ReadValue )
484 int init_bits;
485 FILE* outfile;
486 ifunptr ReadValue;
487 {
488     register long fcode;
489     register code_int i /* = 0 */;
490     register int c;
491     register code_int ent;
492     register code_int disp;
493     register code_int hsize_reg;
494     register int hshift;
495 
496     /*
497      * Set up the globals:  g_init_bits - initial number of bits
498      *                      g_outfile   - pointer to output file
499      */
500     g_init_bits = init_bits;
501     g_outfile = outfile;
502 
503     /*
504      * Set up the necessary values
505      */
506 {
507 int i;
508 for (i=0; i<HSIZE; i++)
509 {
510 	codetab[i] = 0;
511 }
512 }
513 cur_accum = 0;
514 cur_bits = 0;
515     offset = 0;
516     out_count = 0;
517     clear_flg = 0;
518     in_count = 1;
519     maxcode = MAXCODE(n_bits = g_init_bits);
520 
521     ClearCode = (1 << (init_bits - 1));
522     EOFCode = ClearCode + 1;
523     free_ent = ClearCode + 2;
524 
525     char_init();
526 
527     ent = GIFNextPixel( ReadValue );
528 
529     hshift = 0;
530     for ( fcode = (long) hsize;  fcode < 65536L; fcode *= 2L )
531         ++hshift;
532     hshift = 8 - hshift;                /* set hash code range bound */
533 
534     hsize_reg = hsize;
535     cl_hash( (count_int) hsize_reg);            /* clear hash table */
536 
537     output( (code_int)ClearCode );
538 
539 #ifdef SIGNED_COMPARE_SLOW
540     while ( (c = GIFNextPixel( ReadValue )) != (unsigned) EOF ) {
541 #else /*SIGNED_COMPARE_SLOW*/
542     while ( (c = GIFNextPixel( ReadValue )) != EOF ) {	/* } */
543 #endif /*SIGNED_COMPARE_SLOW*/
544 
545         ++in_count;
546 
547         fcode = (long) (((long) c << maxbits) + ent);
548         i = (((code_int)c << hshift) ^ ent);    /* xor hashing */
549 
550         if ( HashTabOf (i) == fcode ) {
551             ent = CodeTabOf (i);
552             continue;
553         } else if ( (long)HashTabOf (i) < 0 )      /* empty slot */
554             goto nomatch;
555         disp = hsize_reg - i;           /* secondary hash (after G. Knott) */
556         if ( i == 0 )
557             disp = 1;
558 probe:
559         if ( (i -= disp) < 0 )
560             i += hsize_reg;
561 
562         if ( HashTabOf (i) == fcode ) {
563             ent = CodeTabOf (i);
564             continue;
565         }
566         if ( (long)HashTabOf (i) > 0 )
567             goto probe;
568 nomatch:
569         output ( (code_int) ent );
570         ++out_count;
571         ent = c;
572 #ifdef SIGNED_COMPARE_SLOW
573         if ( (unsigned) free_ent < (unsigned) maxmaxcode) {
574 #else /*SIGNED_COMPARE_SLOW*/
575         if ( free_ent < maxmaxcode ) {	/* } */
576 #endif /*SIGNED_COMPARE_SLOW*/
577             CodeTabOf (i) = free_ent++; /* code -> hashtable */
578             HashTabOf (i) = fcode;
579         } else
580                 cl_block();
581     }
582     /*
583      * Put out the final code.
584      */
585     output( (code_int)ent );
586     ++out_count;
587     output( (code_int) EOFCode );
588 }
589 
590 /*****************************************************************
591  * TAG( output )
592  *
593  * Output the given code.
594  * Inputs:
595  *      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
596  *              that n_bits =< (long)wordsize - 1.
597  * Outputs:
598  *      Outputs code to the file.
599  * Assumptions:
600  *      Chars are 8 bits long.
601  * Algorithm:
602  *      Maintain a BITS character long buffer (so that 8 codes will
603  * fit in it exactly).  Use the VAX insv instruction to insert each
604  * code in turn.  When the buffer fills up empty it and start over.
605  */
606 
607 static unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
608                                   0x001F, 0x003F, 0x007F, 0x00FF,
609                                   0x01FF, 0x03FF, 0x07FF, 0x0FFF,
610                                   0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
611 
612 static void
output(code)613 output( code )
614 code_int  code;
615 {
616     cur_accum &= masks[ cur_bits ];
617 
618     if( cur_bits > 0 )
619         cur_accum |= ((long)code << cur_bits);
620     else
621         cur_accum = code;
622 
623     cur_bits += n_bits;
624 
625     while( cur_bits >= 8 ) {
626         char_out( (unsigned int)(cur_accum & 0xff) );
627         cur_accum >>= 8;
628         cur_bits -= 8;
629     }
630 
631     /*
632      * If the next entry is going to be too big for the code size,
633      * then increase it, if possible.
634      */
635    if ( free_ent > maxcode || clear_flg ) {
636 
637             if( clear_flg ) {
638 
639                 maxcode = MAXCODE (n_bits = g_init_bits);
640                 clear_flg = 0;
641 
642             } else {
643 
644                 ++n_bits;
645                 if ( n_bits == maxbits )
646                     maxcode = maxmaxcode;
647                 else
648                     maxcode = MAXCODE(n_bits);
649             }
650         }
651 
652     if( code == EOFCode ) {
653         /*
654          * At EOF, write the rest of the buffer.
655          */
656         while( cur_bits > 0 ) {
657                 char_out( (unsigned int)(cur_accum & 0xff) );
658                 cur_accum >>= 8;
659                 cur_bits -= 8;
660         }
661 
662         flush_char();
663 
664         fflush( g_outfile );
665 
666         if( ferror( g_outfile ) )
667                 writeerr();
668     }
669 }
670 
671 /*
672  * Clear out the hash table
673  */
674 static void
cl_block()675 cl_block ()             /* table clear for block compress */
676 {
677 
678         cl_hash ( (count_int) hsize );
679         free_ent = ClearCode + 2;
680         clear_flg = 1;
681 
682         output( (code_int)ClearCode );
683 }
684 
685 static void
cl_hash(hsize)686 cl_hash(hsize)          /* reset code table */
687 register count_int hsize;
688 {
689 
690         register count_int *htab_p = htab+hsize;
691 
692         register long i;
693         register long m1 = -1;
694 
695         i = hsize - 16;
696         do {                            /* might use Sys V memset(3) here */
697                 *(htab_p-16) = m1;
698                 *(htab_p-15) = m1;
699                 *(htab_p-14) = m1;
700                 *(htab_p-13) = m1;
701                 *(htab_p-12) = m1;
702                 *(htab_p-11) = m1;
703                 *(htab_p-10) = m1;
704                 *(htab_p-9) = m1;
705                 *(htab_p-8) = m1;
706                 *(htab_p-7) = m1;
707                 *(htab_p-6) = m1;
708                 *(htab_p-5) = m1;
709                 *(htab_p-4) = m1;
710                 *(htab_p-3) = m1;
711                 *(htab_p-2) = m1;
712                 *(htab_p-1) = m1;
713                 htab_p -= 16;
714         } while ((i -= 16) >= 0);
715 
716         for ( i += 16; i > 0; --i )
717                 *--htab_p = m1;
718 }
719 
720 static void
writeerr()721 writeerr()
722 {
723         fprintf(stderr,  "Error writing GIF output file");
724 }
725 
726 /******************************************************************************
727  *
728  * GIF Specific routines
729  *
730  ******************************************************************************/
731 
732 /*
733  * Number of characters so far in this 'packet'
734  */
735 static int a_count;
736 
737 /*
738  * Set up the 'byte output' routine
739  */
740 static void
char_init()741 char_init()
742 {
743         a_count = 0;
744 }
745 
746 /*
747  * Define the storage for the packet accumulator
748  */
749 static char accum[ 256 ];
750 
751 /*
752  * Add a character to the end of the current packet, and if it is 254
753  * characters, flush the packet to disk.
754  */
755 static void
char_out(c)756 char_out( c )
757 int c;
758 {
759         accum[ a_count++ ] = c;
760         if( a_count >= 254 )
761                 flush_char();
762 }
763 
764 /*
765  * Flush the packet to disk, and reset the accumulator
766  */
767 static void
flush_char()768 flush_char()
769 {
770         if( a_count > 0 ) {
771                 fputc( a_count, g_outfile );
772                 fwrite( accum, 1, a_count, g_outfile );
773                 a_count = 0;
774         }
775 }
776 
777 /* The End */
778