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