Path: utzoo!attcan!utgpu!utstat!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!ucbvax!hplabs!felix!dhw68k!macintosh From: SXWRR@ALASKA.BITNET (Reed Rector) Newsgroups: comp.sources.mac Subject: GIF Image Compression Routines Message-ID: <22931@dhw68k.cts.com> Date: 13 May 89 15:00:29 GMT Sender: macintosh@dhw68k.cts.com Lines: 750 Approved: info-mac@sumex-aim.stanford.edu [GIF Image Compression Routines] Well, I finally got around to it... This set of 'C' routines will create a GIF file from image data. It is a SHAR type archive, so if you don't have a UNIX machine, you will have to de-archive it by hand (pretty straigtforward process). -Reed --- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # # gifcompr.c # gifencod.c # # This archive created: Fri May 12 20:26:46 1989 # By: Roger L. Long (bytebug@dhw68k.cts.com) export PATH; PATH=/bin:$PATH echo shar: extracting "'gifcompr.c'" '(11182 characters)' if test -f 'gifcompr.c' then echo shar: will not over-write existing file "'gifcompr.c'" else sed 's/^X//' << \SHAR_EOF > 'gifcompr.c' X/*************************************************************************** X * X * GIFENCOD.C - GIF Image compression routines X * X * Lempel-Ziv compression based on 'compress'. GIF modifications by X * David Rowley (mgardi@watdcsu.waterloo.edu) X * X ***************************************************************************/ X X/* X * General DEFINEs X */ X#define min(a,b) ((a>b) ? b : a) X X#define BITS 12 X#define MSDOS 1 X X#define HSIZE 5003 /* 80% occupancy */ X X/* X * Pointer to function returning an int X */ Xtypedef int (* ifunptr)(); X X/* X * a code_int must be able to hold 2**BITS values of type int, and also -1 X */ Xtypedef int code_int; X X#ifdef SIGNED_COMPARE_SLOW Xtypedef unsigned long int count_int; Xtypedef unsigned short int count_short; X#else Xtypedef long int count_int; X#endif X X#ifdef NO_UCHAR X typedef char char_type; X#else X typedef unsigned char char_type; X#endif /* UCHAR */ X X/* X * X * GIF Image compression - modified 'compress' X * X * Based on: compress.c - File compression ala IEEE Computer, June 1984. X * X * By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas) X * Jim McKie (decvax!mcvax!jim) X * Steve Davies (decvax!vax135!petsd!peora!srd) X * Ken Turkowski (decvax!decwrl!turtlevax!ken) X * James A. Woods (decvax!ihnp4!ames!jaw) X * Joe Orost (decvax!vax135!petsd!joe) X * X */ X#include X#include X#include X X#define ARGVAL() (*++(*argv) || (--argc && *++argv)) X Xstatic int n_bits; /* number of bits/code */ Xstatic int maxbits = BITS; /* user settable max # bits/code */ Xstatic code_int maxcode; /* maximum code, given n_bits */ Xstatic code_int maxmaxcode = (code_int)1 << BITS; /* should NEVER generate this Xcode */ X#ifdef COMPATIBLE /* But wrong! */ X# define MAXCODE(n_bits) ((code_int) 1 << (n_bits) - 1) X#else X# define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1) X#endif /* COMPATIBLE */ X Xstatic count_int htab [HSIZE]; Xstatic unsigned short codetab [HSIZE]; X#define HashTabOf(i) htab[i] X#define CodeTabOf(i) codetab[i] X Xstatic code_int hsize = HSIZE; /* for dynamic table sizing */ Xstatic count_int fsize; X X/* X * To save much memory, we overlay the table used by compress() with those X * used by decompress(). The tab_prefix table is the same size and type X * as the codetab. The tab_suffix table needs 2**BITS characters. We X * get this from the beginning of htab. The output stack uses the rest X * of htab, and contains characters. There is plenty of room for any X * possible stack (stack used to be 8000 characters). X */ X X#define tab_prefixof(i) CodeTabOf(i) X#define tab_suffixof(i) ((char_type *)(htab))[i] X#define de_stack ((char_type *)&tab_suffixof((code_int)1< 0 ) X goto probe; Xnomatch: X output ( (code_int) ent ); X out_count++; X ent = c; X#ifdef SIGNED_COMPARE_SLOW X if ( (unsigned) free_ent < (unsigned) maxmaxcode) { X#else X if ( free_ent < maxmaxcode ) { X#endif X CodeTabOf (i) = free_ent++; /* code -> hashtable */ X HashTabOf (i) = fcode; X } else X cl_block(); X } X /* X * Put out the final code. X */ X output( (code_int)ent ); X out_count++; X output( (code_int) EOFCode ); X X return; X} X X/***************************************************************** X * TAG( output ) X * X * Output the given code. X * Inputs: X * code: A n_bits-bit integer. If == -1, then EOF. This assumes X * that n_bits =< (long)wordsize - 1. X * Outputs: X * Outputs code to the file. X * Assumptions: X * Chars are 8 bits long. X * Algorithm: X * Maintain a BITS character long buffer (so that 8 codes will X * fit in it exactly). Use the VAX insv instruction to insert each X * code in turn. When the buffer fills up empty it and start over. X */ X Xstatic unsigned long cur_accum = 0; Xstatic int cur_bits = 0; X Xstatic Xunsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, X 0x001F, 0x003F, 0x007F, 0x00FF, X 0x01FF, 0x03FF, 0x07FF, 0x0FFF, X 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; X Xstatic Xoutput( code ) Xcode_int code; X{ X cur_accum &= masks[ cur_bits ]; X X if( cur_bits > 0 ) X cur_accum |= ((long)code << cur_bits); X else X cur_accum = code; X X cur_bits += n_bits; X X while( cur_bits >= 8 ) { X char_out( (unsigned int)(cur_accum & 0xff) ); X cur_accum >>= 8; X cur_bits -= 8; X } X X /* X * If the next entry is going to be too big for the code size, X * then increase it, if possible. X */ X if ( free_ent > maxcode || clear_flg ) { X X if( clear_flg ) { X X maxcode = MAXCODE (n_bits = g_init_bits); X clear_flg = 0; X X } else { X X n_bits++; X if ( n_bits == maxbits ) X maxcode = maxmaxcode; X else X maxcode = MAXCODE(n_bits); X } X } X X if( code == EOFCode ) { X /* X * At EOF, write the rest of the buffer. X */ X while( cur_bits > 0 ) { X char_out( (unsigned int)(cur_accum & 0xff) ); X cur_accum >>= 8; X cur_bits -= 8; X } X X flush_char(); X X fflush( g_outfile ); X X if( ferror( g_outfile ) ) X writeerr(); X } X} X X/* X * Clear out the hash table X */ Xstatic Xcl_block () /* table clear for block compress */ X{ X X cl_hash ( (count_int) hsize ); X free_ent = ClearCode + 2; X clear_flg = 1; X X output( (code_int)ClearCode ); X} X Xstatic Xcl_hash(hsize) /* reset code table */ Xregister count_int hsize; X{ X X register count_int *htab_p = htab+hsize; X X register long i; X register long m1 = -1; X X i = hsize - 16; X do { /* might use Sys V memset(3) here */ X *(htab_p-16) = m1; X *(htab_p-15) = m1; X *(htab_p-14) = m1; X *(htab_p-13) = m1; X *(htab_p-12) = m1; X *(htab_p-11) = m1; X *(htab_p-10) = m1; X *(htab_p-9) = m1; X *(htab_p-8) = m1; X *(htab_p-7) = m1; X *(htab_p-6) = m1; X *(htab_p-5) = m1; X *(htab_p-4) = m1; X *(htab_p-3) = m1; X *(htab_p-2) = m1; X *(htab_p-1) = m1; X htab_p -= 16; X } while ((i -= 16) >= 0); X X for ( i += 16; i > 0; i-- ) X *--htab_p = m1; X} X Xstatic Xwriteerr() X{ X printf( "error writing output file\n" ); X exit(1); X} X X/****************************************************************************** X * X * GIF Specific routines X * X ******************************************************************************/ X X/* X * Number of characters so far in this 'packet' X */ Xstatic int a_count; X X/* X * Set up the 'byte output' routine X */ Xstatic Xchar_init() X{ X a_count = 0; X} X X/* X * Define the storage for the packet accumulator X */ Xstatic char accum[ 256 ]; X X/* X * Add a character to the end of the current packet, and if it is 254 X * characters, flush the packet to disk. X */ Xstatic Xchar_out( c ) Xint c; X{ X accum[ a_count++ ] = c; X if( a_count >= 254 ) X flush_char(); X} X X/* X * Flush the packet to disk, and reset the accumulator X */ Xstatic Xflush_char() X{ X if( a_count > 0 ) { X fputc( a_count, g_outfile ); X fwrite( accum, 1, a_count, g_outfile ); X a_count = 0; X } X} X X/* The End */ SHAR_EOF if test 11182 -ne "`wc -c < 'gifcompr.c'`" then echo shar: error transmitting "'gifcompr.c'" '(should have been 11182 characters)' fi fi # end of overwriting check echo shar: extracting "'gifencod.c'" '(5916 characters)' if test -f 'gifencod.c' then echo shar: will not over-write existing file "'gifencod.c'" else sed 's/^X//' << \SHAR_EOF > 'gifencod.c' X X/***************************************************************************** X * X * GIFENCODE.C - GIF Image compression interface X * X * GIFEncode( FName, GHeight, GWidth, GInterlace, Background, X * BitsPerPixel, Red, Green, Blue, GetPixel ) X * X *****************************************************************************/ X X#include X X/* X * Pointer to function returning an int X */ Xtypedef int (* ifunptr)(); X X#define TRUE 1 X#define FALSE 0 X Xstatic int Width, Height; Xstatic int curx, cury; Xstatic long CountDown; Xstatic int Pass = 0; Xstatic int Interlace; X X/* X * Bump the 'curx' and 'cury' to point to the next pixel X */ Xstatic XBumpPixel() X{ X /* X * Bump the current X position X */ X curx++; X X /* X * If we are at the end of a scan line, set curx back to the beginning X * If we are interlaced, bump the cury to the appropriate spot, X * otherwise, just increment it. X */ X if( curx == Width ) { X curx = 0; X X if( !Interlace ) X cury++; X else { X switch( Pass ) { X X case 0: X cury += 8; X if( cury >= Height ) { X Pass++; X cury = 4; X } X break; X X case 1: X cury += 8; X if( cury >= Height ) { X Pass++; X cury = 2; X } X break; X X case 2: X cury += 4; X if( cury >= Height ) { X Pass++; X cury = 1; X } X break; X X case 3: X cury += 2; X break; X } X } X } X} X X/* X * Return the next pixel from the image X */ XGIFNextPixel( getpixel ) Xifunptr getpixel; X{ X int r; X X if( CountDown == 0 ) X return EOF; X X CountDown--; X X r = ( * getpixel )( curx, cury ); X X BumpPixel(); X X return r; X} X X/* public */ X XGIFEncode( FName, GWidth, GHeight, GInterlace, Background, X BitsPerPixel, Red, Green, Blue, GetPixel ) X Xchar *FName; Xint GWidth, GHeight; Xint GInterlace; Xint Background; Xint BitsPerPixel; Xint Red[], Green[], Blue[]; Xifunptr GetPixel; X X{ X FILE *fp; X int B; X int RWidth, RHeight; X int LeftOfs, TopOfs; X int Resolution; X int ColorMapSize; X int InitCodeSize; X int i; X X Interlace = GInterlace; X X ColorMapSize = 1 << BitsPerPixel; X X RWidth = Width = GWidth; X RHeight = Height = GHeight; X LeftOfs = TopOfs = 0; X X Resolution = BitsPerPixel; X X /* X * Calculate number of bits we are expecting X */ X CountDown = (long)Width * (long)Height; X X /* X * Indicate which pass we are on (if interlace) X */ X Pass = 0; X X /* X * The initial code size X */ X if( BitsPerPixel <= 1 ) X InitCodeSize = 2; X else X InitCodeSize = BitsPerPixel; X X /* X * Set up the current x and y position X */ X curx = cury = 0; X X /* X * Open the GIF file for binary write X */ X fp = fopen( FName, "wb" ); X X if( fp == (FILE *)0 ) { X printf( "error: could not open output file\n" ); X exit(1); X } X X /* X * Write the Magic header X */ X fwrite( "GIF87a", 1, 6, fp ); X X /* X * Write out the screen width and height X */ X Putword( RWidth, fp ); X Putword( RHeight, fp ); X X /* X * Indicate that there is a global colour map X */ X B = 0x80; /* Yes, there is a color map */ X X /* X * OR in the resolution X */ X B |= (Resolution - 1) << 5; X X /* X * OR in the Bits per Pixel X */ X B |= (BitsPerPixel - 1); X X /* X * Write it out X */ X fputc( B, fp ); X X /* X * Write out the Background colour X */ X fputc( Background, fp ); X X /* X * Byte of 0's (future expansion) X */ X fputc( 0, fp ); X X /* X * Write out the Global Colour Map X */ X for( i=0; i