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