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