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

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

E-mail: