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

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

E-mail: