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

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

E-mail: