Annotation of parser3/src/classes/gd/gifio.C, revision 1.2
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:
! 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.2 ! 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.2 ! paf 465: output((code_int) ent );
! 466: ++out_count;
! 467: ent = c;
1.1 paf 468: #ifdef SIGNED_COMPARE_SLOW
1.2 ! paf 469: if((unsigned) free_ent <(unsigned) maxmaxcode) {
1.1 paf 470: #else /*SIGNED_COMPARE_SLOW*/
1.2 ! paf 471: if( free_ent < maxmaxcode ) { /* } */
1.1 paf 472: #endif /*SIGNED_COMPARE_SLOW*/
1.2 ! 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;
! 524: }
! 525:
! 526: /*
! 527: * If the next entry is going to be too big for the code size,
! 528: * then increase it, if possible.
! 529: */
! 530: if( free_ent > maxcode || clear_flg ) {
! 531:
! 532: if( clear_flg ) {
! 533:
! 534: maxcode = MAXCODE(n_bits = g_init_bits);
! 535: clear_flg = 0;
! 536:
! 537: } else {
! 538:
! 539: ++n_bits;
! 540: if( n_bits == maxbits )
! 541: maxcode = maxmaxcode;
! 542: else
! 543: maxcode = MAXCODE(n_bits);
! 544: }
! 545: }
! 546:
! 547: if( code == EOFCode ) {
! 548: /*
! 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: }
! 556:
! 557: flush_char();
! 558:
! 559: fflush( g_outfile );
! 560:
! 561: if( ferror( g_outfile ) )
! 562: return;
! 563: }
! 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;
! 652: }
! 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
1.1 paf 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. */
1.2 ! paf 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: