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