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