Annotation of parser3/src/classes/gd/gifio.C, revision 1.1

1.1     ! paf         1: /** @file
        !             2:        Code drawn from ppmtogif.c, from the pbmplus package
        !             3: 
        !             4: **
        !             5: ** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>. A
        !             6: ** Lempel-Zim compression based on "compress".
        !             7: **
        !             8: ** Modified by Marcel Wijkstra <wijkstra@fwi.uva.nl>
        !             9: **
        !            10: ** Copyright (C) 1989 by Jef Poskanzer.
        !            11: **
        !            12: ** Permission to use, copy, modify, and distribute this software and its
        !            13: ** documentation for any purpose and without fee is hereby granted, provided
        !            14: ** that the above copyright notice appear in all copies and that both that
        !            15: ** copyright notice and this permission notice appear in supporting
        !            16: ** documentation.  This software is provided "as is" without express or
        !            17: ** implied warranty.
        !            18: **
        !            19: ** The Graphics Interchange Format(c) is the Copyright property of
        !            20: ** CompuServe Incorporated.  GIF(sm) is a Service Mark property of
        !            21: ** CompuServe Incorporated.
        !            22: */
        !            23: 
        !            24: #include "gif.h"
        !            25: 
        !            26: /*
        !            27:  * a code_int must be able to hold 2**GIFBITS values of type int, and also -1
        !            28:  */
        !            29: typedef int             code_int;
        !            30: 
        !            31: #ifdef SIGNED_COMPARE_SLOW
        !            32: typedef unsigned long int count_int;
        !            33: typedef unsigned short int count_short;
        !            34: #else /*SIGNED_COMPARE_SLOW*/
        !            35: typedef long int          count_int;
        !            36: #endif /*SIGNED_COMPARE_SLOW*/
        !            37: 
        !            38: static int colorstobpp(int colors);
        !            39: static void BumpPixel (void);
        !            40: static int GIFNextPixel (gdImagePtr im);
        !            41: static void GIFEncode (FILE *fp, int GWidth, int GHeight, int GInterlace, int Background, int Transparent, int BitsPerPixel, int *Red, int *Green, int *Blue, gdImagePtr im);
        !            42: static void Putword (int w, FILE *fp);
        !            43: static void compress (int init_bits, FILE *outfile, gdImagePtr im);
        !            44: static void output (code_int code);
        !            45: static void cl_block (void);
        !            46: static void cl_hash (register count_int hsize);
        !            47: static void char_init (void);
        !            48: static void char_out (int c);
        !            49: static void flush_char (void);
        !            50: /* Allows for reuse */
        !            51: static void init_statics(void);
        !            52: 
        !            53: void gdImageGif(gdImagePtr im, FILE *out)
        !            54: {
        !            55:        int interlace, transparent, BitsPerPixel;
        !            56:        interlace = im->interlace;
        !            57:        transparent = im->transparent;
        !            58: 
        !            59:        BitsPerPixel = colorstobpp(im->colorsTotal);
        !            60:        /* Clear any old values in statics strewn through the GIF code */
        !            61:        init_statics();
        !            62:        /* All set, let's do it. */
        !            63:        GIFEncode(
        !            64:                out, im->sx, im->sy, interlace, 0, transparent, BitsPerPixel,
        !            65:                im->red, im->green, im->blue, im);
        !            66: }
        !            67: 
        !            68: static int
        !            69: colorstobpp(int colors)
        !            70: {
        !            71:     int bpp = 0;
        !            72: 
        !            73:     if ( colors <= 2 )
        !            74:         bpp = 1;
        !            75:     else if ( colors <= 4 )
        !            76:         bpp = 2;
        !            77:     else if ( colors <= 8 )
        !            78:         bpp = 3;
        !            79:     else if ( colors <= 16 )
        !            80:         bpp = 4;
        !            81:     else if ( colors <= 32 )
        !            82:         bpp = 5;
        !            83:     else if ( colors <= 64 )
        !            84:         bpp = 6;
        !            85:     else if ( colors <= 128 )
        !            86:         bpp = 7;
        !            87:     else if ( colors <= 256 )
        !            88:         bpp = 8;
        !            89:     return bpp;
        !            90:     }
        !            91: 
        !            92: /*****************************************************************************
        !            93:  *
        !            94:  * GIFENCODE.C    - GIF Image compression interface
        !            95:  *
        !            96:  * GIFEncode( FName, GHeight, GWidth, GInterlace, Background, Transparent,
        !            97:  *            BitsPerPixel, Red, Green, Blue, gdImagePtr )
        !            98:  *
        !            99:  *****************************************************************************/
        !           100: 
        !           101: #define TRUE 1
        !           102: #define FALSE 0
        !           103: 
        !           104: static int Width, Height;
        !           105: static int curx, cury;
        !           106: static long CountDown;
        !           107: static int Pass = 0;
        !           108: static int Interlace;
        !           109: 
        !           110: /*
        !           111:  * Bump the 'curx' and 'cury' to point to the next pixel
        !           112:  */
        !           113: static void
        !           114: BumpPixel(void)
        !           115: {
        !           116:         /*
        !           117:          * Bump the current X position
        !           118:          */
        !           119:         ++curx;
        !           120: 
        !           121:         /*
        !           122:          * If we are at the end of a scan line, set curx back to the beginning
        !           123:          * If we are interlaced, bump the cury to the appropriate spot,
        !           124:          * otherwise, just increment it.
        !           125:          */
        !           126:         if( curx == Width ) {
        !           127:                 curx = 0;
        !           128: 
        !           129:                 if( !Interlace )
        !           130:                         ++cury;
        !           131:                 else {
        !           132:                      switch( Pass ) {
        !           133: 
        !           134:                        case 0:
        !           135:                           cury += 8;
        !           136:                           if( cury >= Height ) {
        !           137:                                 ++Pass;
        !           138:                                 cury = 4;
        !           139:                           }
        !           140:                           break;
        !           141: 
        !           142:                        case 1:
        !           143:                           cury += 8;
        !           144:                           if( cury >= Height ) {
        !           145:                                 ++Pass;
        !           146:                                 cury = 2;
        !           147:                           }
        !           148:                           break;
        !           149: 
        !           150:                        case 2:
        !           151:                           cury += 4;
        !           152:                           if( cury >= Height ) {
        !           153:                              ++Pass;
        !           154:                              cury = 1;
        !           155:                           }
        !           156:                           break;
        !           157: 
        !           158:                        case 3:
        !           159:                           cury += 2;
        !           160:                           break;
        !           161:                         }
        !           162:                 }
        !           163:         }
        !           164: }
        !           165: 
        !           166: /*
        !           167:  * Return the next pixel from the image
        !           168:  */
        !           169: static int
        !           170: GIFNextPixel(gdImagePtr im)
        !           171: {
        !           172:         int r;
        !           173: 
        !           174:         if( CountDown == 0 )
        !           175:                 return EOF;
        !           176: 
        !           177:         --CountDown;
        !           178: 
        !           179:         r = gdImageGetPixel(im, curx, cury);
        !           180: 
        !           181:         BumpPixel();
        !           182: 
        !           183:         return r;
        !           184: }
        !           185: 
        !           186: /* public */
        !           187: 
        !           188: static void
        !           189: GIFEncode(FILE *fp, int GWidth, int GHeight, int GInterlace, int Background, int Transparent, int BitsPerPixel, int *Red, int *Green, int *Blue, gdImagePtr im)
        !           190: {
        !           191:         int B;
        !           192:         int RWidth, RHeight;
        !           193:         int LeftOfs, TopOfs;
        !           194:         int Resolution;
        !           195:         int ColorMapSize;
        !           196:         int InitCodeSize;
        !           197:         int i;
        !           198: 
        !           199:         Interlace = GInterlace;
        !           200: 
        !           201:         ColorMapSize = 1 << BitsPerPixel;
        !           202: 
        !           203:         RWidth = Width = GWidth;
        !           204:         RHeight = Height = GHeight;
        !           205:         LeftOfs = TopOfs = 0;
        !           206: 
        !           207:         Resolution = BitsPerPixel;
        !           208: 
        !           209:         /*
        !           210:          * Calculate number of bits we are expecting
        !           211:          */
        !           212:         CountDown = (long)Width * (long)Height;
        !           213: 
        !           214:         /*
        !           215:          * Indicate which pass we are on (if interlace)
        !           216:          */
        !           217:         Pass = 0;
        !           218: 
        !           219:         /*
        !           220:          * The initial code size
        !           221:          */
        !           222:         if( BitsPerPixel <= 1 )
        !           223:                 InitCodeSize = 2;
        !           224:         else
        !           225:                 InitCodeSize = BitsPerPixel;
        !           226: 
        !           227:         /*
        !           228:          * Set up the current x and y position
        !           229:          */
        !           230:         curx = cury = 0;
        !           231: 
        !           232:         /*
        !           233:          * Write the Magic header
        !           234:          */
        !           235:         fwrite( Transparent < 0 ? "GIF87a" : "GIF89a", 1, 6, fp );
        !           236: 
        !           237:         /*
        !           238:          * Write out the screen width and height
        !           239:          */
        !           240:         Putword( RWidth, fp );
        !           241:         Putword( RHeight, fp );
        !           242: 
        !           243:         /*
        !           244:          * Indicate that there is a global colour map
        !           245:          */
        !           246:         B = 0x80;       /* Yes, there is a color map */
        !           247: 
        !           248:         /*
        !           249:          * OR in the resolution
        !           250:          */
        !           251:         B |= (Resolution - 1) << 5;
        !           252: 
        !           253:         /*
        !           254:          * OR in the Bits per Pixel
        !           255:          */
        !           256:         B |= (BitsPerPixel - 1);
        !           257: 
        !           258:         /*
        !           259:          * Write it out
        !           260:          */
        !           261:         fputc( B, fp );
        !           262: 
        !           263:         /*
        !           264:          * Write out the Background colour
        !           265:          */
        !           266:         fputc( Background, fp );
        !           267: 
        !           268:         /*
        !           269:          * Byte of 0's (future expansion)
        !           270:          */
        !           271:         fputc( 0, fp );
        !           272: 
        !           273:         /*
        !           274:          * Write out the Global Colour Map
        !           275:          */
        !           276:         for( i=0; i<ColorMapSize; ++i ) {
        !           277:                 fputc( Red[i], fp );
        !           278:                 fputc( Green[i], fp );
        !           279:                 fputc( Blue[i], fp );
        !           280:         }
        !           281: 
        !           282:        /*
        !           283:         * Write out extension for transparent colour index, if necessary.
        !           284:         */
        !           285:        if ( Transparent >= 0 ) {
        !           286:            fputc( '!', fp );
        !           287:            fputc( 0xf9, fp );
        !           288:            fputc( 4, fp );
        !           289:            fputc( 1, fp );
        !           290:            fputc( 0, fp );
        !           291:            fputc( 0, fp );
        !           292:            fputc( (unsigned char) Transparent, fp );
        !           293:            fputc( 0, fp );
        !           294:        }
        !           295: 
        !           296:         /*
        !           297:          * Write an Image separator
        !           298:          */
        !           299:         fputc( ',', fp );
        !           300: 
        !           301:         /*
        !           302:          * Write the Image header
        !           303:          */
        !           304: 
        !           305:         Putword( LeftOfs, fp );
        !           306:         Putword( TopOfs, fp );
        !           307:         Putword( Width, fp );
        !           308:         Putword( Height, fp );
        !           309: 
        !           310:         /*
        !           311:          * Write out whether or not the image is interlaced
        !           312:          */
        !           313:         if( Interlace )
        !           314:                 fputc( 0x40, fp );
        !           315:         else
        !           316:                 fputc( 0x00, fp );
        !           317: 
        !           318:         /*
        !           319:          * Write out the initial code size
        !           320:          */
        !           321:         fputc( InitCodeSize, fp );
        !           322: 
        !           323:         /*
        !           324:          * Go and actually compress the data
        !           325:          */
        !           326:         compress( InitCodeSize+1, fp, im );
        !           327: 
        !           328:         /*
        !           329:          * Write out a Zero-length packet (to end the series)
        !           330:          */
        !           331:         fputc( 0, fp );
        !           332: 
        !           333:         /*
        !           334:          * Write the GIF file terminator
        !           335:          */
        !           336:         fputc( ';', fp );
        !           337: }
        !           338: 
        !           339: /*
        !           340:  * Write out a word to the GIF file
        !           341:  */
        !           342: static void
        !           343: Putword(int w, FILE *fp)
        !           344: {
        !           345:         fputc( w & 0xff, fp );
        !           346:         fputc( (w / 256) & 0xff, fp );
        !           347: }
        !           348: 
        !           349: 
        !           350: /***************************************************************************
        !           351:  *
        !           352:  *  GIFCOMPR.C       - GIF Image compression routines
        !           353:  *
        !           354:  *  Lempel-Ziv compression based on 'compress'.  GIF modifications by
        !           355:  *  David Rowley (mgardi@watdcsu.waterloo.edu)
        !           356:  *
        !           357:  ***************************************************************************/
        !           358: 
        !           359: /*
        !           360:  * General DEFINEs
        !           361:  */
        !           362: 
        !           363: #define GIFBITS    12
        !           364: 
        !           365: #define HSIZE  5003            /* 80% occupancy */
        !           366: 
        !           367: #ifdef NO_UCHAR
        !           368:  typedef char   char_type;
        !           369: #else /*NO_UCHAR*/
        !           370:  typedef        unsigned char   char_type;
        !           371: #endif /*NO_UCHAR*/
        !           372: 
        !           373: /*
        !           374:  *
        !           375:  * GIF Image compression - modified 'compress'
        !           376:  *
        !           377:  * Based on: compress.c - File compression ala IEEE Computer, June 1984.
        !           378:  *
        !           379:  * By Authors:  Spencer W. Thomas       (decvax!harpo!utah-cs!utah-gr!thomas)
        !           380:  *              Jim McKie               (decvax!mcvax!jim)
        !           381:  *              Steve Davies            (decvax!vax135!petsd!peora!srd)
        !           382:  *              Ken Turkowski           (decvax!decwrl!turtlevax!ken)
        !           383:  *              James A. Woods          (decvax!ihnp4!ames!jaw)
        !           384:  *              Joe Orost               (decvax!vax135!petsd!joe)
        !           385:  *
        !           386:  */
        !           387: #include <ctype.h>
        !           388: 
        !           389: #define ARGVAL() (*++(*argv) || (--argc && *++argv))
        !           390: 
        !           391: static int n_bits;                        /* number of bits/code */
        !           392: static int maxbits = GIFBITS;                /* user settable max # bits/code */
        !           393: static code_int maxcode;                  /* maximum code, given n_bits */
        !           394: static code_int maxmaxcode = (code_int)1 << GIFBITS; /* should NEVER generate this code */
        !           395: #ifdef COMPATIBLE               /* But wrong! */
        !           396: # define MAXCODE(n_bits)        ((code_int) 1 << (n_bits) - 1)
        !           397: #else /*COMPATIBLE*/
        !           398: # define MAXCODE(n_bits)        (((code_int) 1 << (n_bits)) - 1)
        !           399: #endif /*COMPATIBLE*/
        !           400: 
        !           401: static count_int htab [HSIZE];
        !           402: static unsigned short codetab [HSIZE];
        !           403: #define HashTabOf(i)       htab[i]
        !           404: #define CodeTabOf(i)    codetab[i]
        !           405: 
        !           406: static code_int hsize = HSIZE;                 /* for dynamic table sizing */
        !           407: 
        !           408: /*
        !           409:  * To save much memory, we overlay the table used by compress() with those
        !           410:  * used by decompress().  The tab_prefix table is the same size and type
        !           411:  * as the codetab.  The tab_suffix table needs 2**GIFBITS characters.  We
        !           412:  * get this from the beginning of htab.  The output stack uses the rest
        !           413:  * of htab, and contains characters.  There is plenty of room for any
        !           414:  * possible stack (stack used to be 8000 characters).
        !           415:  */
        !           416: 
        !           417: #define tab_prefixof(i) CodeTabOf(i)
        !           418: #define tab_suffixof(i)        ((char_type*)(htab))[i]
        !           419: #define de_stack               ((char_type*)&tab_suffixof((code_int)1<<GIFBITS))
        !           420: 
        !           421: static code_int free_ent = 0;                  /* first unused entry */
        !           422: 
        !           423: /*
        !           424:  * block compression parameters -- after all codes are used up,
        !           425:  * and compression rate changes, start over.
        !           426:  */
        !           427: static int clear_flg = 0;
        !           428: 
        !           429: static int offset;
        !           430: static long int in_count = 1;            /* length of input */
        !           431: static long int out_count = 0;           /* # of codes output (for debugging) */
        !           432: 
        !           433: /*
        !           434:  * compress stdin to stdout
        !           435:  *
        !           436:  * Algorithm:  use open addressing double hashing (no chaining) on the
        !           437:  * prefix code / next character combination.  We do a variant of Knuth's
        !           438:  * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
        !           439:  * secondary probe.  Here, the modular division first probe is gives way
        !           440:  * to a faster exclusive-or manipulation.  Also do block compression with
        !           441:  * an adaptive reset, whereby the code table is cleared when the compression
        !           442:  * ratio decreases, but after the table fills.  The variable-length output
        !           443:  * codes are re-sized at this point, and a special CLEAR code is generated
        !           444:  * for the decompressor.  Late addition:  construct the table according to
        !           445:  * file size for noticeable speed improvement on small files.  Please direct
        !           446:  * questions about this implementation to ames!jaw.
        !           447:  */
        !           448: 
        !           449: static int g_init_bits;
        !           450: static FILE* g_outfile;
        !           451: 
        !           452: static int ClearCode;
        !           453: static int EOFCode;
        !           454: 
        !           455: static void
        !           456: compress(int init_bits, FILE *outfile, gdImagePtr im)
        !           457: {
        !           458:     register long fcode;
        !           459:     register code_int i /* = 0 */;
        !           460:     register int c;
        !           461:     register code_int ent;
        !           462:     register code_int disp;
        !           463:     register code_int hsize_reg;
        !           464:     register int hshift;
        !           465: 
        !           466:     /*
        !           467:      * Set up the globals:  g_init_bits - initial number of bits
        !           468:      *                      g_outfile   - pointer to output file
        !           469:      */
        !           470:     g_init_bits = init_bits;
        !           471:     g_outfile = outfile;
        !           472: 
        !           473:     /*
        !           474:      * Set up the necessary values
        !           475:      */
        !           476:     offset = 0;
        !           477:     out_count = 0;
        !           478:     clear_flg = 0;
        !           479:     in_count = 1;
        !           480:     maxcode = MAXCODE(n_bits = g_init_bits);
        !           481: 
        !           482:     ClearCode = (1 << (init_bits - 1));
        !           483:     EOFCode = ClearCode + 1;
        !           484:     free_ent = ClearCode + 2;
        !           485: 
        !           486:     char_init();
        !           487: 
        !           488:     ent = GIFNextPixel( im );
        !           489: 
        !           490:     hshift = 0;
        !           491:     for ( fcode = (long) hsize;  fcode < 65536L; fcode *= 2L )
        !           492:         ++hshift;
        !           493:     hshift = 8 - hshift;                /* set hash code range bound */
        !           494: 
        !           495:     hsize_reg = hsize;
        !           496:     cl_hash( (count_int) hsize_reg);            /* clear hash table */
        !           497: 
        !           498:     output( (code_int)ClearCode );
        !           499: 
        !           500: #ifdef SIGNED_COMPARE_SLOW
        !           501:     while ( (c = GIFNextPixel( im )) != (unsigned) EOF ) {
        !           502: #else /*SIGNED_COMPARE_SLOW*/
        !           503:     while ( (c = GIFNextPixel( im )) != EOF ) {  /* } */
        !           504: #endif /*SIGNED_COMPARE_SLOW*/
        !           505: 
        !           506:         ++in_count;
        !           507: 
        !           508:         fcode = (long) (((long) c << maxbits) + ent);
        !           509:         i = (((code_int)c << hshift) ^ ent);    /* xor hashing */
        !           510: 
        !           511:         if ( HashTabOf (i) == fcode ) {
        !           512:             ent = CodeTabOf (i);
        !           513:             continue;
        !           514:         } else if ( (long)HashTabOf (i) < 0 )      /* empty slot */
        !           515:             goto nomatch;
        !           516:         disp = hsize_reg - i;           /* secondary hash (after G. Knott) */
        !           517:         if ( i == 0 )
        !           518:             disp = 1;
        !           519: probe:
        !           520:         if ( (i -= disp) < 0 )
        !           521:             i += hsize_reg;
        !           522: 
        !           523:         if ( HashTabOf (i) == fcode ) {
        !           524:             ent = CodeTabOf (i);
        !           525:             continue;
        !           526:         }
        !           527:         if ( (long)HashTabOf (i) > 0 )
        !           528:             goto probe;
        !           529: nomatch:
        !           530:         output ( (code_int) ent );
        !           531:         ++out_count;
        !           532:         ent = c;
        !           533: #ifdef SIGNED_COMPARE_SLOW
        !           534:         if ( (unsigned) free_ent < (unsigned) maxmaxcode) {
        !           535: #else /*SIGNED_COMPARE_SLOW*/
        !           536:         if ( free_ent < maxmaxcode ) {  /* } */
        !           537: #endif /*SIGNED_COMPARE_SLOW*/
        !           538:             CodeTabOf (i) = free_ent++; /* code -> hashtable */
        !           539:             HashTabOf (i) = fcode;
        !           540:         } else
        !           541:                 cl_block();
        !           542:     }
        !           543:     /*
        !           544:      * Put out the final code.
        !           545:      */
        !           546:     output( (code_int)ent );
        !           547:     ++out_count;
        !           548:     output( (code_int) EOFCode );
        !           549: }
        !           550: 
        !           551: /*****************************************************************
        !           552:  * TAG( output )
        !           553:  *
        !           554:  * Output the given code.
        !           555:  * Inputs:
        !           556:  *      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
        !           557:  *              that n_bits =< (long)wordsize - 1.
        !           558:  * Outputs:
        !           559:  *      Outputs code to the file.
        !           560:  * Assumptions:
        !           561:  *      Chars are 8 bits long.
        !           562:  * Algorithm:
        !           563:  *      Maintain a GIFBITS character long buffer (so that 8 codes will
        !           564:  * fit in it exactly).  Use the VAX insv instruction to insert each
        !           565:  * code in turn.  When the buffer fills up empty it and start over.
        !           566:  */
        !           567: 
        !           568: static unsigned long cur_accum = 0;
        !           569: static int cur_bits = 0;
        !           570: 
        !           571: static unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
        !           572:                                   0x001F, 0x003F, 0x007F, 0x00FF,
        !           573:                                   0x01FF, 0x03FF, 0x07FF, 0x0FFF,
        !           574:                                   0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
        !           575: 
        !           576: static void
        !           577: output(code_int code)
        !           578: {
        !           579:     cur_accum &= masks[ cur_bits ];
        !           580: 
        !           581:     if( cur_bits > 0 )
        !           582:         cur_accum |= ((long)code << cur_bits);
        !           583:     else
        !           584:         cur_accum = code;
        !           585: 
        !           586:     cur_bits += n_bits;
        !           587: 
        !           588:     while( cur_bits >= 8 ) {
        !           589:         char_out( (unsigned int)(cur_accum & 0xff) );
        !           590:         cur_accum >>= 8;
        !           591:         cur_bits -= 8;
        !           592:     }
        !           593: 
        !           594:     /*
        !           595:      * If the next entry is going to be too big for the code size,
        !           596:      * then increase it, if possible.
        !           597:      */
        !           598:    if ( free_ent > maxcode || clear_flg ) {
        !           599: 
        !           600:             if( clear_flg ) {
        !           601: 
        !           602:                 maxcode = MAXCODE (n_bits = g_init_bits);
        !           603:                 clear_flg = 0;
        !           604: 
        !           605:             } else {
        !           606: 
        !           607:                 ++n_bits;
        !           608:                 if ( n_bits == maxbits )
        !           609:                     maxcode = maxmaxcode;
        !           610:                 else
        !           611:                     maxcode = MAXCODE(n_bits);
        !           612:             }
        !           613:         }
        !           614: 
        !           615:     if( code == EOFCode ) {
        !           616:         /*
        !           617:          * At EOF, write the rest of the buffer.
        !           618:          */
        !           619:         while( cur_bits > 0 ) {
        !           620:                 char_out( (unsigned int)(cur_accum & 0xff) );
        !           621:                 cur_accum >>= 8;
        !           622:                 cur_bits -= 8;
        !           623:         }
        !           624: 
        !           625:         flush_char();
        !           626: 
        !           627:         fflush( g_outfile );
        !           628: 
        !           629:         if( ferror( g_outfile ) )
        !           630:                return;
        !           631:     }
        !           632: }
        !           633: 
        !           634: /*
        !           635:  * Clear out the hash table
        !           636:  */
        !           637: static void
        !           638: cl_block (void)             /* table clear for block compress */
        !           639: {
        !           640: 
        !           641:         cl_hash ( (count_int) hsize );
        !           642:         free_ent = ClearCode + 2;
        !           643:         clear_flg = 1;
        !           644: 
        !           645:         output( (code_int)ClearCode );
        !           646: }
        !           647: 
        !           648: static void
        !           649: cl_hash(register count_int hsize)          /* reset code table */
        !           650:                          
        !           651: {
        !           652: 
        !           653:         register count_int *htab_p = htab+hsize;
        !           654: 
        !           655:         register long i;
        !           656:         register long m1 = -1;
        !           657: 
        !           658:         i = hsize - 16;
        !           659:         do {                            /* might use Sys V memset(3) here */
        !           660:                 *(htab_p-16) = m1;
        !           661:                 *(htab_p-15) = m1;
        !           662:                 *(htab_p-14) = m1;
        !           663:                 *(htab_p-13) = m1;
        !           664:                 *(htab_p-12) = m1;
        !           665:                 *(htab_p-11) = m1;
        !           666:                 *(htab_p-10) = m1;
        !           667:                 *(htab_p-9) = m1;
        !           668:                 *(htab_p-8) = m1;
        !           669:                 *(htab_p-7) = m1;
        !           670:                 *(htab_p-6) = m1;
        !           671:                 *(htab_p-5) = m1;
        !           672:                 *(htab_p-4) = m1;
        !           673:                 *(htab_p-3) = m1;
        !           674:                 *(htab_p-2) = m1;
        !           675:                 *(htab_p-1) = m1;
        !           676:                 htab_p -= 16;
        !           677:         } while ((i -= 16) >= 0);
        !           678: 
        !           679:         for ( i += 16; i > 0; --i )
        !           680:                 *--htab_p = m1;
        !           681: }
        !           682: 
        !           683: /******************************************************************************
        !           684:  *
        !           685:  * GIF Specific routines
        !           686:  *
        !           687:  ******************************************************************************/
        !           688: 
        !           689: /*
        !           690:  * Number of characters so far in this 'packet'
        !           691:  */
        !           692: static int a_count;
        !           693: 
        !           694: /*
        !           695:  * Set up the 'byte output' routine
        !           696:  */
        !           697: static void
        !           698: char_init(void)
        !           699: {
        !           700:         a_count = 0;
        !           701: }
        !           702: 
        !           703: /*
        !           704:  * Define the storage for the packet accumulator
        !           705:  */
        !           706: static char accum[ 256 ];
        !           707: 
        !           708: /*
        !           709:  * Add a character to the end of the current packet, and if it is 254
        !           710:  * characters, flush the packet to disk.
        !           711:  */
        !           712: static void
        !           713: char_out(int c)
        !           714: {
        !           715:         accum[ a_count++ ] = c;
        !           716:         if( a_count >= 254 )
        !           717:                 flush_char();
        !           718: }
        !           719: 
        !           720: /*
        !           721:  * Flush the packet to disk, and reset the accumulator
        !           722:  */
        !           723: static void
        !           724: flush_char(void)
        !           725: {
        !           726:         if( a_count > 0 ) {
        !           727:                 fputc( a_count, g_outfile );
        !           728:                 fwrite( accum, 1, a_count, g_outfile );
        !           729:                 a_count = 0;
        !           730:         }
        !           731: }
        !           732: 
        !           733: static void init_statics(void) {
        !           734:        /* Some of these are properly initialized later. What I'm doing
        !           735:                here is making sure code that depends on C's initialization
        !           736:                of statics doesn't break when the code gets called more
        !           737:                than once. */
        !           738:        Width = 0;
        !           739:        Height = 0;
        !           740:        curx = 0;
        !           741:        cury = 0;
        !           742:        CountDown = 0;
        !           743:        Pass = 0;
        !           744:        Interlace = 0;
        !           745:        a_count = 0;
        !           746:        cur_accum = 0;
        !           747:        cur_bits = 0;
        !           748:        g_init_bits = 0;
        !           749:        g_outfile = 0;
        !           750:        ClearCode = 0;
        !           751:        EOFCode = 0;
        !           752:        free_ent = 0;
        !           753:        clear_flg = 0;
        !           754:        offset = 0;
        !           755:        in_count = 1;
        !           756:        out_count = 0;  
        !           757:        hsize = HSIZE;
        !           758:        n_bits = 0;
        !           759:        maxbits = GIFBITS;
        !           760:        maxcode = 0;
        !           761:        maxmaxcode = (code_int)1 << GIFBITS;
        !           762: }
        !           763: 
        !           764: 
        !           765: /* +-------------------------------------------------------------------+ */
        !           766: /* | Copyright 1990, 1991, 1993, David Koblas.  (koblas@netcom.com)    | */
        !           767: /* |   Permission to use, copy, modify, and distribute this software   | */
        !           768: /* |   and its documentation for any purpose and without fee is hereby | */
        !           769: /* |   granted, provided that the above copyright notice appear in all | */
        !           770: /* |   copies and that both that copyright notice and this permission  | */
        !           771: /* |   notice appear in supporting documentation.  This software is    | */
        !           772: /* |   provided "as is" without express or implied warranty.           | */
        !           773: /* +-------------------------------------------------------------------+ */
        !           774: 
        !           775: 
        !           776: #define        MAXCOLORMAPSIZE         256
        !           777: 
        !           778: #define        TRUE    1
        !           779: #define        FALSE   0
        !           780: 
        !           781: #define CM_RED         0
        !           782: #define CM_GREEN       1
        !           783: #define CM_BLUE                2
        !           784: 
        !           785: #define        MAX_LWZ_BITS            12
        !           786: 
        !           787: #define INTERLACE              0x40
        !           788: #define LOCALCOLORMAP  0x80
        !           789: #define BitSet(byte, bit)      (((byte) & (bit)) == (bit))
        !           790: 
        !           791: #define        ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
        !           792: 
        !           793: #define LM_to_uint(a,b)                        (((b)<<8)|(a))
        !           794: 
        !           795: /* We may eventually want to use this information, but def it out for now */
        !           796: #if 0
        !           797: static struct {
        !           798:        unsigned int    Width;
        !           799:        unsigned int    Height;
        !           800:        unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
        !           801:        unsigned int    BitPixel;
        !           802:        unsigned int    ColorResolution;
        !           803:        unsigned int    Background;
        !           804:        unsigned int    AspectRatio;
        !           805: } GifScreen;
        !           806: #endif
        !           807: 
        !           808: static struct {
        !           809:        int     transparent;
        !           810:        int     delayTime;
        !           811:        int     inputFlag;
        !           812:        int     disposal;
        !           813: } Gif89 = { -1, -1, -1, 0 };
        !           814: 
        !           815: static int ReadColorMap (FILE *fd, int number, unsigned char (*buffer)[256]);
        !           816: static int DoExtension (FILE *fd, int label, int *Transparent);
        !           817: static int GetDataBlock (FILE *fd, unsigned char *buf);
        !           818: static int GetCode (FILE *fd, int code_size, int flag);
        !           819: static int LWZReadByte (FILE *fd, int flag, int input_code_size);
        !           820: static void ReadImage (gdImagePtr im, FILE *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int ignore);
        !           821: 
        !           822: int ZeroDataBlock;
        !           823: 
        !           824: gdImagePtr
        !           825: gdImageCreateFromGif(FILE *fd)
        !           826: {
        !           827:        int imageNumber;
        !           828:        int BitPixel;
        !           829:        int ColorResolution;
        !           830:        int Background;
        !           831:        int AspectRatio;
        !           832:        int Transparent = (-1);
        !           833:        unsigned char   buf[16];
        !           834:        unsigned char   c;
        !           835:        unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
        !           836:        unsigned char   localColorMap[3][MAXCOLORMAPSIZE];
        !           837:        int             imw, imh;
        !           838:        int             useGlobalColormap;
        !           839:        int             bitPixel;
        !           840:        int             imageCount = 0;
        !           841:        char            version[4];
        !           842:        gdImagePtr im = 0;
        !           843:        ZeroDataBlock = FALSE;
        !           844: 
        !           845:        imageNumber = 1;
        !           846:        if (! ReadOK(fd,buf,6)) {
        !           847:                return 0;
        !           848:        }
        !           849:        if (strncmp((char *)buf,"GIF",3) != 0) {
        !           850:                return 0;
        !           851:        }
        !           852:        strncpy(version, (char *)buf + 3, 3);
        !           853:        version[3] = '\0';
        !           854: 
        !           855:        if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
        !           856:                return 0;
        !           857:        }
        !           858:        if (! ReadOK(fd,buf,7)) {
        !           859:                return 0;
        !           860:        }
        !           861:        BitPixel        = 2<<(buf[4]&0x07);
        !           862:        ColorResolution = (int) (((buf[4]&0x70)>>3)+1);
        !           863:        Background      = buf[5];
        !           864:        AspectRatio     = buf[6];
        !           865: 
        !           866:        if (BitSet(buf[4], LOCALCOLORMAP)) {    /* Global Colormap */
        !           867:                if (ReadColorMap(fd, BitPixel, ColorMap)) {
        !           868:                        return 0;
        !           869:                }
        !           870:        }
        !           871:        for (;;) {
        !           872:                if (! ReadOK(fd,&c,1)) {
        !           873:                        return 0;
        !           874:                }
        !           875:                if (c == ';') {         /* GIF terminator */
        !           876:                        int i;
        !           877:                        if (imageCount < imageNumber) {
        !           878:                                return 0;
        !           879:                        }
        !           880:                        /* Terminator before any image was declared! */
        !           881:                        if (!im) {
        !           882:                               return 0;
        !           883:                        }
        !           884:                       /* Check for open colors at the end, so
        !           885:                           we can reduce colorsTotal and ultimately
        !           886:                           BitsPerPixel */
        !           887:                        for (i=((im->colorsTotal-1)); (i>=0); i--) {
        !           888:                                if (im->open[i]) {
        !           889:                                        im->colorsTotal--;
        !           890:                                } else {
        !           891:                                        break;
        !           892:                                }
        !           893:                        } 
        !           894:                        return im;
        !           895:                }
        !           896: 
        !           897:                if (c == '!') {         /* Extension */
        !           898:                        if (! ReadOK(fd,&c,1)) {
        !           899:                                return 0;
        !           900:                        }
        !           901:                        DoExtension(fd, c, &Transparent);
        !           902:                        continue;
        !           903:                }
        !           904: 
        !           905:                if (c != ',') {         /* Not a valid start character */
        !           906:                        continue;
        !           907:                }
        !           908: 
        !           909:                ++imageCount;
        !           910: 
        !           911:                if (! ReadOK(fd,buf,9)) {
        !           912:                       return 0;
        !           913:                }
        !           914: 
        !           915:                useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
        !           916: 
        !           917:                bitPixel = 1<<((buf[8]&0x07)+1);
        !           918: 
        !           919:                imw = LM_to_uint(buf[4],buf[5]);
        !           920:                imh = LM_to_uint(buf[6],buf[7]);
        !           921:               if (!(im = gdImageCreate(imw, imh))) {
        !           922:                         return 0;
        !           923:               }
        !           924:                im->interlace = BitSet(buf[8], INTERLACE);
        !           925:                if (! useGlobalColormap) {
        !           926:                        if (ReadColorMap(fd, bitPixel, localColorMap)) { 
        !           927:                                  return 0;
        !           928:                        }
        !           929:                        ReadImage(im, fd, imw, imh, localColorMap, 
        !           930:                                  BitSet(buf[8], INTERLACE), 
        !           931:                                  imageCount != imageNumber);
        !           932:                } else {
        !           933:                        ReadImage(im, fd, imw, imh,
        !           934:                                  ColorMap, 
        !           935:                                  BitSet(buf[8], INTERLACE), 
        !           936:                                  imageCount != imageNumber);
        !           937:                }
        !           938:                if (Transparent != (-1)) {
        !           939:                        gdImageColorTransparent(im, Transparent);
        !           940:                }          
        !           941:        }
        !           942: }
        !           943: 
        !           944: static int
        !           945: ReadColorMap(FILE *fd, int number, unsigned char (*buffer)[256])
        !           946: {
        !           947:        int             i;
        !           948:        unsigned char   rgb[3];
        !           949: 
        !           950: 
        !           951:        for (i = 0; i < number; ++i) {
        !           952:                if (! ReadOK(fd, rgb, sizeof(rgb))) {
        !           953:                        return TRUE;
        !           954:                }
        !           955:                buffer[CM_RED][i] = rgb[0] ;
        !           956:                buffer[CM_GREEN][i] = rgb[1] ;
        !           957:                buffer[CM_BLUE][i] = rgb[2] ;
        !           958:        }
        !           959: 
        !           960: 
        !           961:        return FALSE;
        !           962: }
        !           963: 
        !           964: static int
        !           965: DoExtension(FILE *fd, int label, int *Transparent)
        !           966: {
        !           967:        static unsigned char     buf[256];
        !           968: 
        !           969:        switch (label) {
        !           970:        case 0xf9:              /* Graphic Control Extension */
        !           971:                (void) GetDataBlock(fd, (unsigned char*) buf);
        !           972:                Gif89.disposal    = (buf[0] >> 2) & 0x7;
        !           973:                Gif89.inputFlag   = (buf[0] >> 1) & 0x1;
        !           974:                Gif89.delayTime   = LM_to_uint(buf[1],buf[2]);
        !           975:                if ((buf[0] & 0x1) != 0)
        !           976:                        *Transparent = buf[3];
        !           977: 
        !           978:                while (GetDataBlock(fd, (unsigned char*) buf) != 0)
        !           979:                        ;
        !           980:                return FALSE;
        !           981:        default:
        !           982:                break;
        !           983:        }
        !           984:        while (GetDataBlock(fd, (unsigned char*) buf) != 0)
        !           985:                ;
        !           986: 
        !           987:        return FALSE;
        !           988: }
        !           989: 
        !           990: static int
        !           991: GetDataBlock(FILE *fd, unsigned char *buf)
        !           992: {
        !           993:        unsigned char   count;
        !           994: 
        !           995:        if (! ReadOK(fd,&count,1)) {
        !           996:                return -1;
        !           997:        }
        !           998: 
        !           999:        ZeroDataBlock = count == 0;
        !          1000: 
        !          1001:        if ((count != 0) && (! ReadOK(fd, buf, count))) {
        !          1002:                return -1;
        !          1003:        }
        !          1004: 
        !          1005:        return count;
        !          1006: }
        !          1007: 
        !          1008: static int
        !          1009: GetCode(FILE *fd, int code_size, int flag)
        !          1010: {
        !          1011:        static unsigned char    buf[280];
        !          1012:        static int              curbit, lastbit, done, last_byte;
        !          1013:        int                     i, j, ret;
        !          1014:        unsigned char           count;
        !          1015: 
        !          1016:        if (flag) {
        !          1017:                curbit = 0;
        !          1018:                lastbit = 0;
        !          1019:                done = FALSE;
        !          1020:                return 0;
        !          1021:        }
        !          1022: 
        !          1023:        if ( (curbit+code_size) >= lastbit) {
        !          1024:                if (done) {
        !          1025:                        if (curbit >= lastbit) {
        !          1026:                                 /* Oh well */
        !          1027:                        }                        
        !          1028:                        return -1;
        !          1029:                }
        !          1030:                buf[0] = buf[last_byte-2];
        !          1031:                buf[1] = buf[last_byte-1];
        !          1032: 
        !          1033:                if ((count = GetDataBlock(fd, &buf[2])) == 0)
        !          1034:                        done = TRUE;
        !          1035: 
        !          1036:                last_byte = 2 + count;
        !          1037:                curbit = (curbit - lastbit) + 16;
        !          1038:                lastbit = (2+count)*8 ;
        !          1039:        }
        !          1040: 
        !          1041:        ret = 0;
        !          1042:        for (i = curbit, j = 0; j < code_size; ++i, ++j)
        !          1043:                ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
        !          1044: 
        !          1045:        curbit += code_size;
        !          1046: 
        !          1047:        return ret;
        !          1048: }
        !          1049: 
        !          1050: static int
        !          1051: LWZReadByte(FILE *fd, int flag, int input_code_size)
        !          1052: {
        !          1053:        static int      fresh = FALSE;
        !          1054:        int             code, incode;
        !          1055:        static int      code_size, set_code_size;
        !          1056:        static int      max_code, max_code_size;
        !          1057:        static int      firstcode, oldcode;
        !          1058:        static int      clear_code, end_code;
        !          1059:        static int      table[2][(1<< MAX_LWZ_BITS)];
        !          1060:        static int      stack[(1<<(MAX_LWZ_BITS))*2], *sp;
        !          1061:        register int    i;
        !          1062: 
        !          1063:        if (flag) {
        !          1064:                set_code_size = input_code_size;
        !          1065:                code_size = set_code_size+1;
        !          1066:                clear_code = 1 << set_code_size ;
        !          1067:                end_code = clear_code + 1;
        !          1068:                max_code_size = 2*clear_code;
        !          1069:                max_code = clear_code+2;
        !          1070: 
        !          1071:                GetCode(fd, 0, TRUE);
        !          1072:                
        !          1073:                fresh = TRUE;
        !          1074: 
        !          1075:                for (i = 0; i < clear_code; ++i) {
        !          1076:                        table[0][i] = 0;
        !          1077:                        table[1][i] = i;
        !          1078:                }
        !          1079:                for (; i < (1<<MAX_LWZ_BITS); ++i)
        !          1080:                        table[0][i] = table[1][0] = 0;
        !          1081: 
        !          1082:                sp = stack;
        !          1083: 
        !          1084:                return 0;
        !          1085:        } else if (fresh) {
        !          1086:                fresh = FALSE;
        !          1087:                do {
        !          1088:                        firstcode = oldcode =
        !          1089:                                GetCode(fd, code_size, FALSE);
        !          1090:                } while (firstcode == clear_code);
        !          1091:                return firstcode;
        !          1092:        }
        !          1093: 
        !          1094:        if (sp > stack)
        !          1095:                return *--sp;
        !          1096: 
        !          1097:        while ((code = GetCode(fd, code_size, FALSE)) >= 0) {
        !          1098:                if (code == clear_code) {
        !          1099:                        for (i = 0; i < clear_code; ++i) {
        !          1100:                                table[0][i] = 0;
        !          1101:                                table[1][i] = i;
        !          1102:                        }
        !          1103:                        for (; i < (1<<MAX_LWZ_BITS); ++i)
        !          1104:                                table[0][i] = table[1][i] = 0;
        !          1105:                        code_size = set_code_size+1;
        !          1106:                        max_code_size = 2*clear_code;
        !          1107:                        max_code = clear_code+2;
        !          1108:                        sp = stack;
        !          1109:                        firstcode = oldcode =
        !          1110:                                        GetCode(fd, code_size, FALSE);
        !          1111:                        return firstcode;
        !          1112:                } else if (code == end_code) {
        !          1113:                        int             count;
        !          1114:                        unsigned char   buf[260];
        !          1115: 
        !          1116:                        if (ZeroDataBlock)
        !          1117:                                return -2;
        !          1118: 
        !          1119:                        while ((count = GetDataBlock(fd, buf)) > 0)
        !          1120:                                ;
        !          1121: 
        !          1122:                        if (count != 0)
        !          1123:                        return -2;
        !          1124:                }
        !          1125: 
        !          1126:                incode = code;
        !          1127: 
        !          1128:                if (code >= max_code) {
        !          1129:                        *sp++ = firstcode;
        !          1130:                        code = oldcode;
        !          1131:                }
        !          1132: 
        !          1133:                while (code >= clear_code) {
        !          1134:                        *sp++ = table[1][code];
        !          1135:                        if (code == table[0][code]) {
        !          1136:                                /* Oh well */
        !          1137:                        }
        !          1138:                        code = table[0][code];
        !          1139:                }
        !          1140: 
        !          1141:                *sp++ = firstcode = table[1][code];
        !          1142: 
        !          1143:                if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
        !          1144:                        table[0][code] = oldcode;
        !          1145:                        table[1][code] = firstcode;
        !          1146:                        ++max_code;
        !          1147:                        if ((max_code >= max_code_size) &&
        !          1148:                                (max_code_size < (1<<MAX_LWZ_BITS))) {
        !          1149:                                max_code_size *= 2;
        !          1150:                                ++code_size;
        !          1151:                        }
        !          1152:                }
        !          1153: 
        !          1154:                oldcode = incode;
        !          1155: 
        !          1156:                if (sp > stack)
        !          1157:                        return *--sp;
        !          1158:        }
        !          1159:        return code;
        !          1160: }
        !          1161: 
        !          1162: static void
        !          1163: ReadImage(gdImagePtr im, FILE *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int ignore)
        !          1164: {
        !          1165:        unsigned char   c;      
        !          1166:        int             v;
        !          1167:        int             xpos = 0, ypos = 0, pass = 0;
        !          1168:        int i;
        !          1169:        /* Stash the color map into the image */
        !          1170:        for (i=0; (i<gdMaxColors); i++) {
        !          1171:                im->red[i] = cmap[CM_RED][i];   
        !          1172:                im->green[i] = cmap[CM_GREEN][i];       
        !          1173:                im->blue[i] = cmap[CM_BLUE][i]; 
        !          1174:                im->open[i] = 1;
        !          1175:        }
        !          1176:        /* Many (perhaps most) of these colors will remain marked open. */
        !          1177:        im->colorsTotal = gdMaxColors;
        !          1178:        /*
        !          1179:        **  Initialize the Compression routines
        !          1180:        */
        !          1181:        if (! ReadOK(fd,&c,1)) {
        !          1182:                return; 
        !          1183:        }
        !          1184:        if (LWZReadByte(fd, TRUE, c) < 0) {
        !          1185:                return;
        !          1186:        }
        !          1187: 
        !          1188:        /*
        !          1189:        **  If this is an "uninteresting picture" ignore it.
        !          1190:        */
        !          1191:        if (ignore) {
        !          1192:                while (LWZReadByte(fd, FALSE, c) >= 0)
        !          1193:                        ;
        !          1194:                return;
        !          1195:        }
        !          1196: 
        !          1197:        while ((v = LWZReadByte(fd,FALSE,c)) >= 0 ) {
        !          1198:                /* This how we recognize which colors are actually used. */
        !          1199:                if (im->open[v]) {
        !          1200:                        im->open[v] = 0;
        !          1201:                }
        !          1202:                gdImageSetPixel(im, xpos, ypos, v);
        !          1203:                ++xpos;
        !          1204:                if (xpos == len) {
        !          1205:                        xpos = 0;
        !          1206:                        if (interlace) {
        !          1207:                                switch (pass) {
        !          1208:                                case 0:
        !          1209:                                case 1:
        !          1210:                                        ypos += 8; break;
        !          1211:                                case 2:
        !          1212:                                        ypos += 4; break;
        !          1213:                                case 3:
        !          1214:                                        ypos += 2; break;
        !          1215:                                }
        !          1216: 
        !          1217:                                if (ypos >= height) {
        !          1218:                                        ++pass;
        !          1219:                                        switch (pass) {
        !          1220:                                        case 1:
        !          1221:                                                ypos = 4; break;
        !          1222:                                        case 2:
        !          1223:                                                ypos = 2; break;
        !          1224:                                        case 3:
        !          1225:                                                ypos = 1; break;
        !          1226:                                        default:
        !          1227:                                                goto fini;
        !          1228:                                        }
        !          1229:                                }
        !          1230:                        } else {
        !          1231:                                ++ypos;
        !          1232:                        }
        !          1233:                }
        !          1234:                if (ypos >= height)
        !          1235:                        break;
        !          1236:        }
        !          1237: 
        !          1238: fini:
        !          1239:        if (LWZReadByte(fd,FALSE,c)>=0) {
        !          1240:                /* Ignore extra */
        !          1241:        }
        !          1242: }
        !          1243: 

E-mail: