🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: comp.sources.mac
1 messages
1 total messages Started by Reed Rector Sat, 13 May 1989 15:00
GIF Image Compression Routines
#76
Author: Reed Rector
Date: Sat, 13 May 1989 15:00
750 lines
20359 bytes
[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 <stdio.h>
X#include <ctype.h>
X#include <signal.h>
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<<BITS))
X
Xstatic code_int free_ent = 0;                  /* first unused entry */
Xstatic int exit_stat = 0;
X
X/*
X * block compression parameters -- after all codes are used up,
X * and compression rate changes, start over.
X */
Xstatic int clear_flg = 0;
X
Xstatic int offset;
Xstatic long int in_count = 1;            /* length of input */
Xstatic long int out_count = 0;           /* # of codes output (for debugging) */
X
X/*
X * compress stdin to stdout
X *
X * Algorithm:  use open addressing double hashing (no chaining) on the
X * prefix code / next character combination.  We do a variant of Knuth's
X * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
X * secondary probe.  Here, the modular division first probe is gives way
X * to a faster exclusive-or manipulation.  Also do block compression with
X * an adaptive reset, whereby the code table is cleared when the compression
X * ratio decreases, but after the table fills.  The variable-length output
X * codes are re-sized at this point, and a special CLEAR code is generated
X * for the decompressor.  Late addition:  construct the table according to
X * file size for noticeable speed improvement on small files.  Please direct
X * questions about this implementation to ames!jaw.
X */
X
Xstatic int g_init_bits;
Xstatic FILE *g_outfile;
X
Xstatic int ClearCode;
Xstatic int EOFCode;
X
Xcompress( init_bits, outfile, ReadValue )
Xint init_bits;
XFILE *outfile;
Xifunptr ReadValue;
X{
X    register long fcode;
X    register code_int i = 0;
X    register int c;
X    register code_int ent;
X    register code_int disp;
X    register code_int hsize_reg;
X    register int hshift;
X
X    /*
X     * Set up the globals:  g_init_bits - initial number of bits
X     *                      g_outfile   - pointer to output file
X     */
X    g_init_bits = init_bits;
X    g_outfile = outfile;
X
X    /*
X     * Set up the necessary values
X     */
X    offset = 0;
X    out_count = 0;
X    clear_flg = 0;
X    in_count = 1;
X    maxcode = MAXCODE(n_bits = g_init_bits);
X
X    ClearCode = (1 << (init_bits - 1));
X    EOFCode = ClearCode + 1;
X    free_ent = ClearCode + 2;
X
X    char_init();
X
X    ent = GIFNextPixel( ReadValue );
X
X    hshift = 0;
X    for ( fcode = (long) hsize;  fcode < 65536L; fcode *= 2L )
X        hshift++;
X    hshift = 8 - hshift;                /* set hash code range bound */
X
X    hsize_reg = hsize;
X    cl_hash( (count_int) hsize_reg);            /* clear hash table */
X
X    output( (code_int)ClearCode );
X
X#ifdef SIGNED_COMPARE_SLOW
X    while ( (c = GIFNextPixel( ReadValue )) != (unsigned) EOF ) {
X#else
X    while ( (c = GIFNextPixel( ReadValue )) != EOF ) {
X#endif
X
X        in_count++;
X
X        fcode = (long) (((long) c << maxbits) + ent);
X        i = (((code_int)c << hshift) ~ ent);    /* xor hashing */
X
X        if ( HashTabOf (i) == fcode ) {
X            ent = CodeTabOf (i);
X            continue;
X        } else if ( (long)HashTabOf (i) < 0 )      /* empty slot */
X            goto nomatch;
X        disp = hsize_reg - i;           /* secondary hash (after G. Knott) */
X        if ( i == 0 )
X            disp = 1;
Xprobe:
X        if ( (i -= disp) < 0 )
X            i += hsize_reg;
X
X        if ( HashTabOf (i) == fcode ) {
X            ent = CodeTabOf (i);
X            continue;
X        }
X        if ( (long)HashTabOf (i) > 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 <stdio.h>
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<ColorMapSize; i++ ) {
X                fputc( Red[i], fp );
X                fputc( Green[i], fp );
X                fputc( Blue[i], fp );
X        }
X
X        /*
X         * Write an Image separator
X         */
X        fputc( ',', fp );
X
X        /*
X         * Write the Image header
X         */
X
X        Putword( LeftOfs, fp );
X        Putword( TopOfs, fp );
X        Putword( Width, fp );
X        Putword( Height, fp );
X
X        /*
X         * Write out whether or not the image is interlaced
X         */
X        if( Interlace )
X                fputc( 0x40, fp );
X        else
X                fputc( 0x00, fp );
X
X        /*
X         * Write out the initial code size
X         */
X        fputc( InitCodeSize, fp );
X
X        /*
X         * Go and actually compress the data
X         */
X        compress( InitCodeSize+1, fp, GetPixel );
X
X        /*
X         * Write out a Zero-length packet (to end the series)
X         */
X        fputc( 0, fp );
X
X        /*
X         * Write the GIF file terminator
X         */
X        fputc( ';', fp );
X
X        /*
X         * And close the file
X         */
X        fclose( fp );
X
X}
X
X/*
X * Write out a word to the GIF file
X */
Xstatic
XPutword( w, fp )
Xint w;
XFILE *fp;
X{
X        fputc( w & 0xff, fp );
X        fputc( (w / 256) & 0xff, fp );
X}
X
SHAR_EOF
if test 5916 -ne "`wc -c < 'gifencod.c'`"
then
	echo shar: error transmitting "'gifencod.c'" '(should have been 5916 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0
---
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads