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