Annotation of parser3/src/classes/gd/gifio.C, revision 1.22
1.1 paf 1: /** @file
1.5 paf 2: Parser: image manipulations impl2.
1.1 paf 3:
1.22 ! paf 4: Copyright (c) 2001-2003 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.13 parser 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:
1.5 paf 17: based on:
1.2 paf 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.
1.1 paf 36: */
1.19 paf 37:
1.22 ! paf 38: static const char* IDENT_GIFIO_C="$Date: 2003/03/24 15:08:02 $";
1.1 paf 39:
40: #include "gif.h"
41:
42: static int colorstobpp(int colors);
43:
1.22 ! paf 44: gdBuf gdImage::Gif()
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.22 ! paf 48: gdGifEncoder encoder(*this);
1.1 paf 49: /* All set, let's do it. */
1.22 ! paf 50: return 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.22 ! paf 173: gdBuf
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.22 ! paf 222: Putbyte('G');Putbyte('I');Putbyte('F');
! 223: Putbyte('8');Putbyte(Transparent < 0?'7':'9');Putbyte('a');
1.2 paf 224:
225: /*
226: * Write out the screen width and height
227: */
1.4 paf 228: Putword( RWidth);
229: Putword( RHeight);
1.2 paf 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: */
1.4 paf 249: Putbyte(B);
1.2 paf 250:
251: /*
252: * Write out the Background colour
253: */
1.4 paf 254: Putbyte(Background);
1.2 paf 255:
256: /*
257: * Byte of 0's(future expansion)
258: */
1.4 paf 259: Putbyte(0);
1.2 paf 260:
261: /*
262: * Write out the Global Colour Map
263: */
264: for( i=0; i<ColorMapSize; ++i ) {
1.4 paf 265: Putbyte( Red[i]);
266: Putbyte( Green[i]);
267: Putbyte( Blue[i]);
1.2 paf 268: }
269:
270: /*
271: * Write out extension for transparent colour index, if necessary.
272: */
273: if( Transparent >= 0 ) {
1.4 paf 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);
1.1 paf 282: }
1.2 paf 283:
284: /*
285: * Write an Image separator
286: */
1.4 paf 287: Putbyte( ',');
1.2 paf 288:
289: /*
290: * Write the Image header
291: */
292:
1.4 paf 293: Putword( LeftOfs);
294: Putword( TopOfs);
295: Putword( Width);
296: Putword( Height);
1.2 paf 297:
298: /*
299: * Write out whether or not the image is interlaced
300: */
301: if( Interlace )
1.4 paf 302: Putbyte( 0x40);
1.2 paf 303: else
1.4 paf 304: Putbyte( 0x00);
1.2 paf 305:
306: /*
307: * Write out the initial code size
308: */
1.4 paf 309: Putbyte( InitCodeSize);
1.2 paf 310:
311: /*
312: * Go and actually compress the data
313: */
1.4 paf 314: compress( InitCodeSize+1 );
1.2 paf 315:
316: /*
317: * Write out a Zero-length packet(to end the series)
318: */
1.4 paf 319: Putbyte( 0);
1.2 paf 320:
321: /*
322: * Write the GIF file terminator
323: */
1.4 paf 324: Putbyte( ';');
1.22 ! paf 325:
! 326: return buf;
1.1 paf 327: }
328:
329: /*
1.4 paf 330: * Write out a byte to the GIF file
331: */
332: void
1.22 ! paf 333: gdGifEncoder::Putbyte(unsigned char c) {
! 334: buf.append(&c, 1);
1.4 paf 335: }
336: /*
1.2 paf 337: * Write out a word to the GIF file
338: */
1.4 paf 339: void
340: gdGifEncoder::Putword(int w)
1.1 paf 341: {
1.22 ! paf 342: unsigned char b0=w & 0xff;
! 343: unsigned char b1=w >> 8;
! 344: buf.append(&b0, 1);
! 345: buf.append(&b1, 1);
1.1 paf 346: }
347:
1.22 ! paf 348: void gdGifEncoder::Write(void *abuf, size_t size) {
! 349: buf.append((unsigned char*)abuf, size);
1.4 paf 350: }
1.1 paf 351:
352: /***************************************************************************
1.2 paf 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: ***************************************************************************/
1.1 paf 360:
361: /*
1.2 paf 362: * General DEFINEs
363: */
1.1 paf 364:
365: #define GIFBITS 12
366:
367: #ifdef NO_UCHAR
1.2 paf 368: typedef char char_type;
1.10 parser 369: #else
1.2 paf 370: typedef unsigned char char_type;
1.10 parser 371: #endif
1.1 paf 372:
373: /*
1.2 paf 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: */
1.1 paf 387: #ifdef COMPATIBLE /* But wrong! */
1.2 paf 388: # define MAXCODE(n_bits) ((code_int) 1 <<(n_bits) - 1)
1.10 parser 389: #else
1.2 paf 390: # define MAXCODE(n_bits) (((code_int) 1 <<(n_bits)) - 1)
1.10 parser 391: #endif
1.1 paf 392:
393: #define HashTabOf(i) htab[i]
394: #define CodeTabOf(i) codetab[i]
395: /*
1.2 paf 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: */
1.1 paf 403:
404: #define tab_prefixof(i) CodeTabOf(i)
1.2 paf 405: #define tab_suffixof(i) ((char_type*)(htab))[i]
406: #define de_stack ((char_type*)&tab_suffixof((code_int)1<<GIFBITS))
1.1 paf 407:
408: /*
1.2 paf 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: */
1.1 paf 423:
1.2 paf 424: void
1.4 paf 425: gdGifEncoder::compress(int init_bits)
1.1 paf 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;
1.2 paf 434:
1.1 paf 435: /*
1.2 paf 436: * Set up the globals: g_init_bits - initial number of bits
437: * g_outfile - pointer to output file
438: */
1.1 paf 439: g_init_bits = init_bits;
1.2 paf 440:
1.1 paf 441: /*
1.2 paf 442: * Set up the necessary values
443: */
1.1 paf 444: offset = 0;
445: out_count = 0;
446: clear_flg = 0;
447: in_count = 1;
448: maxcode = MAXCODE(n_bits = g_init_bits);
1.2 paf 449:
450: ClearCode =(1 <<(init_bits - 1));
1.1 paf 451: EOFCode = ClearCode + 1;
452: free_ent = ClearCode + 2;
1.2 paf 453:
1.1 paf 454: char_init();
1.2 paf 455:
456: ent = GIFNextPixel( );
457:
1.1 paf 458: hshift = 0;
1.2 paf 459: for( fcode =(long) hsize; fcode < 65536L; fcode *= 2L )
1.1 paf 460: ++hshift;
461: hshift = 8 - hshift; /* set hash code range bound */
1.2 paf 462:
1.1 paf 463: hsize_reg = hsize;
1.2 paf 464: cl_hash((count_int) hsize_reg); /* clear hash table */
465:
466: output((code_int)ClearCode );
467:
1.1 paf 468: #ifdef SIGNED_COMPARE_SLOW
1.2 paf 469: while((c = GIFNextPixel( )) !=(unsigned) EOF ) {
1.10 parser 470: #else
1.2 paf 471: while((c = GIFNextPixel( )) != EOF ) { /* } */
1.10 parser 472: #endif
1.2 paf 473:
1.3 paf 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;
1.1 paf 487: probe:
1.3 paf 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;
1.1 paf 497: nomatch:
1.3 paf 498: output((code_int) ent );
499: ++out_count;
500: ent = c;
1.1 paf 501: #ifdef SIGNED_COMPARE_SLOW
1.3 paf 502: if((unsigned) free_ent <(unsigned) maxmaxcode) {
1.10 parser 503: #else
1.3 paf 504: if( free_ent < maxmaxcode ) { /* } */
1.10 parser 505: #endif
1.3 paf 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;
1.2 paf 557: }
558:
1.3 paf 559: /*
560: * If the next entry is going to be too big for the code size,
561: * then increase it, if possible.
1.2 paf 562: */
1.3 paf 563: if( free_ent > maxcode || clear_flg ) {
1.2 paf 564:
1.3 paf 565: if( clear_flg ) {
1.2 paf 566:
1.3 paf 567: maxcode = MAXCODE(n_bits = g_init_bits);
568: clear_flg = 0;
1.2 paf 569:
1.3 paf 570: } else {
1.2 paf 571:
1.3 paf 572: ++n_bits;
573: if( n_bits == maxbits )
574: maxcode = maxmaxcode;
575: else
576: maxcode = MAXCODE(n_bits);
1.2 paf 577: }
578: }
579:
1.3 paf 580: if( code == EOFCode ) {
1.2 paf 581: /*
1.3 paf 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: }
1.2 paf 589:
1.3 paf 590: flush_char();
1.4 paf 591: }
1.3 paf 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
1.9 paf 609: gdGifEncoder::cl_hash(count_int hsize) /* reset code table */
1.3 paf 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 ) {
1.4 paf 677: Putbyte( a_count );
678: Write( accum, a_count);
1.3 paf 679: a_count = 0;
1.2 paf 680: }
1.3 paf 681: }
682:
1.22 ! paf 683: gdGifEncoder::gdGifEncoder(gdImage& aim):
! 684: im(aim) {
1.3 paf 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:
1.1 paf 726: #define MAXCOLORMAPSIZE 256
1.2 paf 727:
1.16 paf 728: #ifndef TRUE
1.1 paf 729: #define TRUE 1
1.16 paf 730: #endif
731: #ifndef FALSE
1.1 paf 732: #define FALSE 0
1.16 paf 733: #endif
1.2 paf 734:
1.1 paf 735: #define CM_RED 0
736: #define CM_GREEN 1
737: #define CM_BLUE 2
1.2 paf 738:
1.1 paf 739: #define MAX_LWZ_BITS 12
1.2 paf 740:
1.1 paf 741: #define INTERLACE 0x40
742: #define LOCALCOLORMAP 0x80
1.2 paf 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 */
1.1 paf 750: #if 0
1.2 paf 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: };
1.1 paf 760: #endif
1.8 paf 761:
762: /// Graphic Control Extension struct
1.11 parser 763: #ifndef DOXYGEN
1.2 paf 764: struct Gif89 {
765: int transparent;
766: int delayTime;
767: int inputFlag;
768: int disposal;
769: };
1.11 parser 770: #endif
1.2 paf 771: static int ReadColorMap(FILE *fd, int number, unsigned char(*buffer)[256]);
772: static int GetCode(FILE *fd, int code_size, int flag);
1.1 paf 773:
1.2 paf 774: bool gdImage::CreateFromGif(FILE *fd)
1.1 paf 775: {
1.2 paf 776: int imageNumber;
777: int BitPixel;
778: int ColorResolution;
779: int Background;
780: int AspectRatio;
781: int Transparent =(-1);
782: unsigned char buf[16];
783: unsigned char c;
784: unsigned char ColorMap[3][MAXCOLORMAPSIZE];
785: unsigned char localColorMap[3][MAXCOLORMAPSIZE];
786: int imw, imh;
787: int useGlobalColormap;
788: int bitPixel;
789: int imageCount = 0;
790: char version[4];
791: ZeroDataBlock = FALSE;
792:
793: imageNumber = 1;
794: if(! ReadOK(fd,buf,6)) {
795: return false;
796: }
797: if(strncmp((char *)buf,"GIF",3) != 0) {
798: return false;
799: }
800: strncpy(version,(char *)buf + 3, 3);
801: version[3] = '\0';
802:
803: if((strcmp(version, "87a") != 0) &&(strcmp(version, "89a") != 0)) {
804: return false;
1.1 paf 805: }
1.2 paf 806: if(! ReadOK(fd,buf,7)) {
807: return false;
1.1 paf 808: }
1.2 paf 809: BitPixel = 2<<(buf[4]&0x07);
810: ColorResolution =(int)(((buf[4]&0x70)>>3)+1);
811: Background = buf[5];
812: AspectRatio = buf[6];
813:
814: if(BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */
815: if(ReadColorMap(fd, BitPixel, ColorMap)) {
816: return false;
817: }
1.1 paf 818: }
1.2 paf 819: for(;;) {
820: if(! ReadOK(fd,&c,1)) {
821: return false;
822: }
823: if(c == ';') { /* GIF terminator */
824: int i;
825: if(imageCount < imageNumber) {
826: return false;
827: }
828: /* Check for open colors at the end, so
829: we can reduce colorsTotal and ultimately
830: BitsPerPixel */
831: for(i=((colorsTotal-1));(i>=0); i--) {
832: if(open[i]) {
833: colorsTotal--;
834: } else {
835: break;
836: }
837: }
838: return true;
839: }
840:
841: if(c == '!') { /* Extension */
842: if(! ReadOK(fd,&c,1)) {
843: return false;
844: }
845: DoExtension(fd, c, &Transparent);
846: continue;
847: }
848:
849: if(c != ',') { /* Not a valid start character */
850: continue;
851: }
852:
853: ++imageCount;
854:
855: if(! ReadOK(fd,buf,9)) {
856: return false;
857: }
858:
859: useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
860:
861: bitPixel = 1<<((buf[8]&0x07)+1);
862:
863: imw = LM_to_uint(buf[4],buf[5]);
864: imh = LM_to_uint(buf[6],buf[7]);
865: Create(imw, imh);
866: interlace = BitSet(buf[8], INTERLACE);
867: if(! useGlobalColormap) {
868: if(ReadColorMap(fd, bitPixel, localColorMap)) {
869: return false;
870: }
871: ReadImage(fd, imw, imh, localColorMap,
872: BitSet(buf[8], INTERLACE),
873: imageCount != imageNumber);
874: } else {
875: ReadImage(fd, imw, imh,
876: ColorMap,
877: BitSet(buf[8], INTERLACE),
878: imageCount != imageNumber);
879: }
880: if(Transparent !=(-1)) {
881: SetColorTransparent(Transparent);
882: }
1.1 paf 883: }
884: }
885:
886: static int
1.2 paf 887: ReadColorMap(FILE *fd, int number, unsigned char(*buffer)[256])
1.1 paf 888: {
1.2 paf 889: int i;
890: unsigned char rgb[3];
891:
892:
893: for(i = 0; i < number; ++i) {
894: if(! ReadOK(fd, rgb, sizeof(rgb))) {
895: return TRUE;
896: }
897: buffer[CM_RED][i] = rgb[0] ;
898: buffer[CM_GREEN][i] = rgb[1] ;
899: buffer[CM_BLUE][i] = rgb[2] ;
900: }
901:
902:
903: return FALSE;
1.1 paf 904: }
905:
1.2 paf 906: int gdImage::DoExtension(FILE *fd, int label, int *Transparent)
1.1 paf 907: {
1.2 paf 908: static unsigned char buf[256];
909:
910: switch(label) {
911: case 0xf9: { /* Graphic Control Extension */
912: (void) GetDataBlock(fd,(unsigned char*) buf);
913: Gif89 gif89 = { -1, -1, -1, 0 }; // PAF:huh?
914: gif89.disposal =(buf[0] >> 2) & 0x7;
915: gif89.inputFlag =(buf[0] >> 1) & 0x1;
916: gif89.delayTime = LM_to_uint(buf[1],buf[2]);
917: if((buf[0] & 0x1) != 0)
918: *Transparent = buf[3];
919:
920: while(GetDataBlock(fd,(unsigned char*) buf) != 0)
921: ;
922: return FALSE;
923: }
924: default:
925: break;
926: }
927: while(GetDataBlock(fd,(unsigned char*) buf) != 0)
928: ;
929:
930: return FALSE;
1.1 paf 931: }
932:
1.2 paf 933: int
934: gdImage::GetDataBlock(FILE *fd, unsigned char *buf)
1.1 paf 935: {
1.2 paf 936: unsigned char count;
937:
938: if(! ReadOK(fd,&count,1)) {
939: return -1;
940: }
941:
942: ZeroDataBlock = count == 0;
943:
944: if((count != 0) &&(! ReadOK(fd, buf, count))) {
945: return -1;
946: }
947:
948: return count;
1.1 paf 949: }
950:
1.2 paf 951: int gdImage::GetCode(FILE *fd, int code_size, int flag)
1.1 paf 952: {
1.2 paf 953: static unsigned char buf[280];
954: static int curbit, lastbit, done, last_byte;
955: int i, j, ret;
956: unsigned char count;
957:
958: if(flag) {
959: curbit = 0;
960: lastbit = 0;
961: done = FALSE;
962: return 0;
963: }
964:
965: if((curbit+code_size) >= lastbit) {
966: if(done) {
967: if(curbit >= lastbit) {
968: /* Oh well */
969: }
970: return -1;
971: }
972: buf[0] = buf[last_byte-2];
973: buf[1] = buf[last_byte-1];
974:
975: if((count = GetDataBlock(fd, &buf[2])) == 0)
976: done = TRUE;
977:
978: last_byte = 2 + count;
979: curbit =(curbit - lastbit) + 16;
980: lastbit =(2+count)*8 ;
981: }
982:
983: ret = 0;
984: for(i = curbit, j = 0; j < code_size; ++i, ++j)
985: ret |=((buf[ i / 8 ] &(1 <<(i % 8))) != 0) << j;
986:
987: curbit += code_size;
988:
989: return ret;
1.1 paf 990: }
991:
1.2 paf 992: int gdImage::LWZReadByte(FILE *fd, int flag, int input_code_size)
1.1 paf 993: {
1.2 paf 994: static int fresh = FALSE;
995: int code, incode;
996: static int code_size, set_code_size;
997: static int max_code, max_code_size;
998: static int firstcode, oldcode;
999: static int clear_code, end_code;
1000: static int table[2][(1<< MAX_LWZ_BITS)];
1001: static int stack[(1<<(MAX_LWZ_BITS))*2], *sp;
1002: register int i;
1003:
1004: if(flag) {
1005: set_code_size = input_code_size;
1006: code_size = set_code_size+1;
1007: clear_code = 1 << set_code_size ;
1008: end_code = clear_code + 1;
1009: max_code_size = 2*clear_code;
1010: max_code = clear_code+2;
1011:
1012: GetCode(fd, 0, TRUE);
1013:
1014: fresh = TRUE;
1015:
1016: for(i = 0; i < clear_code; ++i) {
1017: table[0][i] = 0;
1018: table[1][i] = i;
1019: }
1020: for(; i <(1<<MAX_LWZ_BITS); ++i)
1021: table[0][i] = table[1][0] = 0;
1022:
1023: sp = stack;
1024:
1025: return 0;
1026: } else if(fresh) {
1027: fresh = FALSE;
1028: do {
1029: firstcode = oldcode =
1030: GetCode(fd, code_size, FALSE);
1031: } while(firstcode == clear_code);
1032: return firstcode;
1033: }
1034:
1035: if(sp > stack)
1036: return *--sp;
1037:
1038: while((code = GetCode(fd, code_size, FALSE)) >= 0) {
1039: if(code == clear_code) {
1040: for(i = 0; i < clear_code; ++i) {
1041: table[0][i] = 0;
1042: table[1][i] = i;
1043: }
1044: for(; i <(1<<MAX_LWZ_BITS); ++i)
1045: table[0][i] = table[1][i] = 0;
1046: code_size = set_code_size+1;
1047: max_code_size = 2*clear_code;
1048: max_code = clear_code+2;
1049: sp = stack;
1050: firstcode = oldcode =
1051: GetCode(fd, code_size, FALSE);
1052: return firstcode;
1053: } else if(code == end_code) {
1054: int count;
1055: unsigned char buf[260];
1056:
1057: if(ZeroDataBlock)
1058: return -2;
1059:
1060: while((count = GetDataBlock(fd, buf)) > 0)
1061: ;
1062:
1063: if(count != 0)
1064: return -2;
1065: }
1066:
1067: incode = code;
1068:
1069: if(code >= max_code) {
1070: *sp++ = firstcode;
1071: code = oldcode;
1072: }
1073:
1074: while(code >= clear_code) {
1075: *sp++ = table[1][code];
1076: if(code == table[0][code]) {
1077: /* Oh well */
1078: }
1079: code = table[0][code];
1080: }
1081:
1082: *sp++ = firstcode = table[1][code];
1083:
1084: if((code = max_code) <(1<<MAX_LWZ_BITS)) {
1085: table[0][code] = oldcode;
1086: table[1][code] = firstcode;
1087: ++max_code;
1088: if((max_code >= max_code_size) &&
1089: (max_code_size <(1<<MAX_LWZ_BITS))) {
1090: max_code_size *= 2;
1091: ++code_size;
1092: }
1093: }
1094:
1095: oldcode = incode;
1096:
1097: if(sp > stack)
1098: return *--sp;
1099: }
1100: return code;
1.1 paf 1101: }
1102:
1.2 paf 1103: void gdImage::ReadImage(FILE *fd, int len, int height, unsigned char(*cmap)[256], int interlace, int ignore)
1.1 paf 1104: {
1.2 paf 1105: unsigned char c;
1106: int v;
1107: int xpos = 0, ypos = 0, pass = 0;
1108: int i;
1109: /* Stash the color map into the image */
1110: for(i=0;(i<gdMaxColors); i++) {
1111: red[i] = cmap[CM_RED][i];
1112: green[i] = cmap[CM_GREEN][i];
1113: blue[i] = cmap[CM_BLUE][i];
1114: open[i] = 1;
1115: }
1116: /* Many(perhaps most) of these colors will remain marked open. */
1117: colorsTotal = gdMaxColors;
1118: /*
1119: ** Initialize the Compression routines
1120: */
1121: if(! ReadOK(fd,&c,1)) {
1122: return;
1123: }
1124: if(LWZReadByte(fd, TRUE, c) < 0) {
1125: return;
1126: }
1127:
1128: /*
1129: ** If this is an "uninteresting picture" ignore it.
1130: */
1131: if(ignore) {
1132: while(LWZReadByte(fd, FALSE, c) >= 0)
1133: ;
1134: return;
1135: }
1136:
1137: while((v = LWZReadByte(fd,FALSE,c)) >= 0 ) {
1138: /* This how we recognize which colors are actually used. */
1139: if(open[v]) {
1140: open[v] = 0;
1141: }
1142: SetPixel(xpos, ypos, v);
1143: ++xpos;
1144: if(xpos == len) {
1145: xpos = 0;
1146: if(interlace) {
1147: switch(pass) {
1148: case 0:
1149: case 1:
1150: ypos += 8; break;
1151: case 2:
1152: ypos += 4; break;
1153: case 3:
1154: ypos += 2; break;
1155: }
1156:
1157: if(ypos >= height) {
1158: ++pass;
1159: switch(pass) {
1160: case 1:
1161: ypos = 4; break;
1162: case 2:
1163: ypos = 2; break;
1164: case 3:
1165: ypos = 1; break;
1166: default:
1167: goto fini;
1168: }
1169: }
1170: } else {
1171: ++ypos;
1172: }
1173: }
1174: if(ypos >= height)
1175: break;
1176: }
1177:
1.1 paf 1178: fini:
1.2 paf 1179: if(LWZReadByte(fd,FALSE,c)>=0) {
1180: /* Ignore extra */
1181: }
1.1 paf 1182: }
1183:
E-mail: