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

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

E-mail: