--- parser3/src/classes/gd/Attic/gifio.C 2001/04/11 17:00:55 1.2 +++ parser3/src/classes/gd/Attic/gifio.C 2003/03/18 15:14:15 1.21.2.2.2.1 @@ -1,6 +1,20 @@ /** @file -Code drawn from ppmtogif.c, from the pbmplus package + Parser: image manipulations impl2. + Copyright (c) 2001-2003 ArtLebedev Group (http://www.artlebedev.com) + Author: Alexandr Petrosian (http://paf.design.ru) + + based on: gd + + Written by Tom Boutell, 5/94. + Copyright 1994, Cold Spring Harbor Labs. + Permission granted to use this code in any fashion provided + that this notice is retained and any alterations are + labeled as such. It is requested, but not required, that + you share extensions to this module with us so that we + can incorporate them into new versions. + + based on: ** ** Based on GIFENCOD by David Rowley . A ** Lempel-Zim compression based on "compress". @@ -21,19 +35,20 @@ Code drawn from ppmtogif.c, from the pbm ** CompuServe Incorporated. */ +static const char* IDENT_GIFIO_C="$Date: 2003/03/18 15:14:15 $"; + #include "gif.h" static int colorstobpp(int colors); -static void Putword(int w, FILE *fp); -void gdImage::Gif(FILE *out) +void gdImage::GifString& out) { int BitsPerPixel = colorstobpp(colorsTotal); /* Clear any old values in statics strewn through the GIF code */ - gdGifEncoder encoder(pool(), *this); + gdGifEncoder encoder(pool, *this, out); /* All set, let's do it. */ encoder.encode( - out, sx, sy, interlace, 0, transparent, BitsPerPixel, + sx, sy, interlace, 0, transparent, BitsPerPixel, red, green, blue); } @@ -70,8 +85,12 @@ colorstobpp(int colors) * *****************************************************************************/ +#ifndef TRUE #define TRUE 1 +#endif +#ifndef FALSE #define FALSE 0 +#endif /* * Bump the 'curx' and 'cury' to point to the next pixel @@ -152,7 +171,9 @@ gdGifEncoder::GIFNextPixel() /* public */ void -gdGifEncoder::encode(FILE *fp, int GWidth, int GHeight, int GInterlace, int Background, int Transparent, int BitsPerPixel, int *Red, int *Green, int *Blue) +gdGifEncoder::encode(int GWidth, int GHeight, + int GInterlace, int Background, int Transparent, int BitsPerPixel, + int *Red, int *Green, int *Blue) { int B; int RWidth, RHeight; @@ -198,13 +219,13 @@ gdGifEncoder::encode(FILE *fp, int GWidt /* * Write the Magic header */ - fwrite( Transparent < 0 ? "GIF87a" : "GIF89a", 1, 6, fp ); + fp << (Transparent < 0 ? "GIF87a" : "GIF89a"); /* * Write out the screen width and height */ - Putword( RWidth, fp ); - Putword( RHeight, fp ); + Putword( RWidth); + Putword( RHeight); /* * Indicate that there is a global colour map @@ -224,94 +245,110 @@ gdGifEncoder::encode(FILE *fp, int GWidt /* * Write it out */ - fputc( B, fp ); + Putbyte(B); /* * Write out the Background colour */ - fputc( Background, fp ); + Putbyte(Background); /* * Byte of 0's(future expansion) */ - fputc( 0, fp ); + Putbyte(0); /* * Write out the Global Colour Map */ for( i=0; i= 0 ) { - fputc( '!', fp ); - fputc( 0xf9, fp ); - fputc( 4, fp ); - fputc( 1, fp ); - fputc( 0, fp ); - fputc( 0, fp ); - fputc((unsigned char) Transparent, fp ); - fputc( 0, fp ); + Putbyte( '!'); + Putbyte( 0xf9); + Putbyte( 4); + Putbyte( 1); + Putbyte( 0); + Putbyte( 0); + Putbyte((unsigned char) Transparent); + Putbyte( 0); } /* * Write an Image separator */ - fputc( ',', fp ); + Putbyte( ','); /* * Write the Image header */ - Putword( LeftOfs, fp ); - Putword( TopOfs, fp ); - Putword( Width, fp ); - Putword( Height, fp ); + Putword( LeftOfs); + Putword( TopOfs); + Putword( Width); + Putword( Height); /* * Write out whether or not the image is interlaced */ if( Interlace ) - fputc( 0x40, fp ); + Putbyte( 0x40); else - fputc( 0x00, fp ); + Putbyte( 0x00); /* * Write out the initial code size */ - fputc( InitCodeSize, fp ); + Putbyte( InitCodeSize); /* * Go and actually compress the data */ - compress( InitCodeSize+1, fp); + compress( InitCodeSize+1 ); /* * Write out a Zero-length packet(to end the series) */ - fputc( 0, fp ); + Putbyte( 0); /* * Write the GIF file terminator */ - fputc( ';', fp ); + Putbyte( ';'); } /* +* Write out a byte to the GIF file +*/ +void +gdGifEncoder::Putbyte(int c) { + char *p=new char[1]; + *p=c; + fp.APPEND_AS_IS(p, 1, 0, 0); +} +/* * Write out a word to the GIF file */ -static void -Putword(int w, FILE *fp) +void +gdGifEncoder::Putword(int w) { - fputc( w & 0xff, fp ); - fputc((w / 256) & 0xff, fp ); + char *p=new char[2]; + p[0]=w & 0xff; + p[1]=(w / 256) & 0xff; + fp.APPEND_AS_IS(p, 2, 0, 0); } +void gdGifEncoder::Write(void *buf, size_t size) { + char *p=new char[size]; + memcpy(p, buf, size); + fp.APPEND_AS_IS(p, size, 0, 0); +} /*************************************************************************** * @@ -330,9 +367,9 @@ Putword(int w, FILE *fp) #ifdef NO_UCHAR typedef char char_type; -#else /*NO_UCHAR*/ +#else typedef unsigned char char_type; -#endif /*NO_UCHAR*/ +#endif /* * @@ -348,13 +385,11 @@ typedef unsigned char char_type * Joe Orost (decvax!vax135!petsd!joe) * */ -#include - #ifdef COMPATIBLE /* But wrong! */ # define MAXCODE(n_bits) ((code_int) 1 <<(n_bits) - 1) -#else /*COMPATIBLE*/ +#else # define MAXCODE(n_bits) (((code_int) 1 <<(n_bits)) - 1) -#endif /*COMPATIBLE*/ +#endif #define HashTabOf(i) htab[i] #define CodeTabOf(i) codetab[i] @@ -388,7 +423,7 @@ typedef unsigned char char_type */ void -gdGifEncoder::compress(int init_bits, FILE *outfile) +gdGifEncoder::compress(int init_bits) { register long fcode; register code_int i /* = 0 */; @@ -403,7 +438,6 @@ gdGifEncoder::compress(int init_bits, FI * g_outfile - pointer to output file */ g_init_bits = init_bits; - g_outfile = outfile; /* * Set up the necessary values @@ -434,272 +468,271 @@ gdGifEncoder::compress(int init_bits, FI #ifdef SIGNED_COMPARE_SLOW while((c = GIFNextPixel( )) !=(unsigned) EOF ) { -#else /*SIGNED_COMPARE_SLOW*/ +#else while((c = GIFNextPixel( )) != EOF ) { /* } */ -#endif /*SIGNED_COMPARE_SLOW*/ - - ++in_count; - - fcode =(long)(((long) c << maxbits) + ent); - i =(((code_int)c << hshift) ^ ent); /* xor hashing */ +#endif - if( HashTabOf(i) == fcode ) { - ent = CodeTabOf(i); - continue; - } else if((long)HashTabOf(i) < 0 ) /* empty slot */ - goto nomatch; - disp = hsize_reg - i; /* secondary hash(after G. Knott) */ - if( i == 0 ) - disp = 1; + ++in_count; + + fcode =(long)(((long) c << maxbits) + ent); + i =(((code_int)c << hshift) ^ ent); /* xor hashing */ + + if( HashTabOf(i) == fcode ) { + ent = CodeTabOf(i); + continue; + } else if((long)HashTabOf(i) < 0 ) /* empty slot */ + goto nomatch; + disp = hsize_reg - i; /* secondary hash(after G. Knott) */ + if( i == 0 ) + disp = 1; probe: - if((i -= disp) < 0 ) - i += hsize_reg; - - if( HashTabOf(i) == fcode ) { - ent = CodeTabOf(i); - continue; - } - if((long)HashTabOf(i) > 0 ) - goto probe; + if((i -= disp) < 0 ) + i += hsize_reg; + + if( HashTabOf(i) == fcode ) { + ent = CodeTabOf(i); + continue; + } + if((long)HashTabOf(i) > 0 ) + goto probe; nomatch: - output((code_int) ent ); - ++out_count; - ent = c; + output((code_int) ent ); + ++out_count; + ent = c; #ifdef SIGNED_COMPARE_SLOW - if((unsigned) free_ent <(unsigned) maxmaxcode) { -#else /*SIGNED_COMPARE_SLOW*/ - if( free_ent < maxmaxcode ) { /* } */ -#endif /*SIGNED_COMPARE_SLOW*/ - CodeTabOf(i) = free_ent++; /* code -> hashtable */ - HashTabOf(i) = fcode; - } else - cl_block(); - } - /* - * Put out the final code. - */ - output((code_int)ent ); - ++out_count; - output((code_int) EOFCode ); - } - - /***************************************************************** - * TAG( output ) - * - * Output the given code. - * Inputs: - * code: A n_bits-bit integer. If == -1, then EOF. This assumes - * that n_bits =<(long)wordsize - 1. - * Outputs: - * Outputs code to the file. - * Assumptions: - * Chars are 8 bits long. - * Algorithm: - * Maintain a GIFBITS character long buffer(so that 8 codes will - * fit in it exactly). Use the VAX insv instruction to insert each - * code in turn. When the buffer fills up empty it and start over. - */ - - static unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, - 0x001F, 0x003F, 0x007F, 0x00FF, - 0x01FF, 0x03FF, 0x07FF, 0x0FFF, - 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; - - void - gdGifEncoder::output(code_int code) - { - cur_accum &= masks[ cur_bits ]; - - if( cur_bits > 0 ) - cur_accum |=((long)code << cur_bits); - else - cur_accum = code; - - cur_bits += n_bits; - - while( cur_bits >= 8 ) { - char_out((unsigned int)(cur_accum & 0xff) ); - cur_accum >>= 8; - cur_bits -= 8; - } - - /* - * If the next entry is going to be too big for the code size, - * then increase it, if possible. - */ - if( free_ent > maxcode || clear_flg ) { - - if( clear_flg ) { - - maxcode = MAXCODE(n_bits = g_init_bits); - clear_flg = 0; - - } else { - - ++n_bits; - if( n_bits == maxbits ) - maxcode = maxmaxcode; - else - maxcode = MAXCODE(n_bits); - } - } - - if( code == EOFCode ) { - /* - * At EOF, write the rest of the buffer. - */ - while( cur_bits > 0 ) { - char_out((unsigned int)(cur_accum & 0xff) ); - cur_accum >>= 8; - cur_bits -= 8; - } - - flush_char(); - - fflush( g_outfile ); - - if( ferror( g_outfile ) ) - return; - } + if((unsigned) free_ent <(unsigned) maxmaxcode) { +#else + if( free_ent < maxmaxcode ) { /* } */ +#endif + CodeTabOf(i) = free_ent++; /* code -> hashtable */ + HashTabOf(i) = fcode; + } else + cl_block(); } - /* - * Clear out the hash table + * Put out the final code. */ - void - gdGifEncoder::cl_block(void) /* table clear for block compress */ - { - - cl_hash((count_int) hsize ); - free_ent = ClearCode + 2; - clear_flg = 1; - - output((code_int)ClearCode ); - } + output((code_int)ent ); + ++out_count; + output((code_int) EOFCode ); +} + +/***************************************************************** +* TAG( output ) +* +* Output the given code. +* Inputs: +* code: A n_bits-bit integer. If == -1, then EOF. This assumes +* that n_bits =<(long)wordsize - 1. +* Outputs: +* Outputs code to the file. +* Assumptions: +* Chars are 8 bits long. +* Algorithm: +* Maintain a GIFBITS character long buffer(so that 8 codes will +* fit in it exactly). Use the VAX insv instruction to insert each +* code in turn. When the buffer fills up empty it and start over. +*/ + +static unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, + 0x001F, 0x003F, 0x007F, 0x00FF, + 0x01FF, 0x03FF, 0x07FF, 0x0FFF, + 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; + +void + gdGifEncoder::output(code_int code) +{ + cur_accum &= masks[ cur_bits ]; - void - gdGifEncoder::cl_hash(register count_int hsize) /* reset code table */ - - { - - register count_int *htab_p = htab+hsize; - - register long i; - register long m1 = -1; - - i = hsize - 16; - do { /* might use Sys V memset(3) here */ - *(htab_p-16) = m1; - *(htab_p-15) = m1; - *(htab_p-14) = m1; - *(htab_p-13) = m1; - *(htab_p-12) = m1; - *(htab_p-11) = m1; - *(htab_p-10) = m1; - *(htab_p-9) = m1; - *(htab_p-8) = m1; - *(htab_p-7) = m1; - *(htab_p-6) = m1; - *(htab_p-5) = m1; - *(htab_p-4) = m1; - *(htab_p-3) = m1; - *(htab_p-2) = m1; - *(htab_p-1) = m1; - htab_p -= 16; - } while((i -= 16) >= 0); - - for( i += 16; i > 0; --i ) - *--htab_p = m1; - } + if( cur_bits > 0 ) + cur_accum |=((long)code << cur_bits); + else + cur_accum = code; - /****************************************************************************** - * - * GIF Specific routines - * - ******************************************************************************/ + cur_bits += n_bits; - /* - * Set up the 'byte output' routine - */ - void - gdGifEncoder::char_init(void) - { - a_count = 0; + while( cur_bits >= 8 ) { + char_out((unsigned int)(cur_accum & 0xff) ); + cur_accum >>= 8; + cur_bits -= 8; } /* - * Add a character to the end of the current packet, and if it is 254 - * characters, flush the packet to disk. + * If the next entry is going to be too big for the code size, + * then increase it, if possible. */ - void - gdGifEncoder::char_out(int c) - { - accum[ a_count++ ] = c; - if( a_count >= 254 ) - flush_char(); + if( free_ent > maxcode || clear_flg ) { + + if( clear_flg ) { + + maxcode = MAXCODE(n_bits = g_init_bits); + clear_flg = 0; + + } else { + + ++n_bits; + if( n_bits == maxbits ) + maxcode = maxmaxcode; + else + maxcode = MAXCODE(n_bits); + } } + if( code == EOFCode ) { /* - * Flush the packet to disk, and reset the accumulator - */ - void - gdGifEncoder::flush_char(void) - { - if( a_count > 0 ) { - fputc( a_count, g_outfile ); - fwrite( accum, 1, a_count, g_outfile ); - a_count = 0; + * At EOF, write the rest of the buffer. + */ + while( cur_bits > 0 ) { + char_out((unsigned int)(cur_accum & 0xff) ); + cur_accum >>= 8; + cur_bits -= 8; } - } + + flush_char(); + } +} + +/* +* Clear out the hash table +*/ +void + gdGifEncoder::cl_block(void) /* table clear for block compress */ +{ - gdGifEncoder::gdGifEncoder(Pool& pool, gdImage& aim) : Pooled(pool), - im(aim) { - /* Some of these are properly initialized later. What I'm doing - here is making sure code that depends on C's initialization - of statics doesn't break when the code gets called more - than once. */ - Width = 0; - Height = 0; - curx = 0; - cury = 0; - CountDown = 0; - Pass = 0; - Interlace = 0; - a_count = 0; - cur_accum = 0; - cur_bits = 0; - g_init_bits = 0; - g_outfile = 0; - ClearCode = 0; - EOFCode = 0; - free_ent = 0; - clear_flg = 0; - offset = 0; - in_count = 1; - out_count = 0; - hsize = HSIZE; - n_bits = 0; - maxbits = GIFBITS; - maxcode = 0; - maxmaxcode =(code_int)1 << GIFBITS; - } + cl_hash((count_int) hsize ); + free_ent = ClearCode + 2; + clear_flg = 1; + + output((code_int)ClearCode ); +} + +void + gdGifEncoder::cl_hash(count_int hsize) /* reset code table */ + +{ + register count_int *htab_p = htab+hsize; - /* +-------------------------------------------------------------------+ */ - /* | Copyright 1990, 1991, 1993, David Koblas.(koblas@netcom.com) | */ - /* | Permission to use, copy, modify, and distribute this software | */ - /* | and its documentation for any purpose and without fee is hereby | */ - /* | granted, provided that the above copyright notice appear in all | */ - /* | copies and that both that copyright notice and this permission | */ - /* | notice appear in supporting documentation. This software is | */ - /* | provided "as is" without express or implied warranty. | */ - /* +-------------------------------------------------------------------+ */ + register long i; + register long m1 = -1; + i = hsize - 16; + do { /* might use Sys V memset(3) here */ + *(htab_p-16) = m1; + *(htab_p-15) = m1; + *(htab_p-14) = m1; + *(htab_p-13) = m1; + *(htab_p-12) = m1; + *(htab_p-11) = m1; + *(htab_p-10) = m1; + *(htab_p-9) = m1; + *(htab_p-8) = m1; + *(htab_p-7) = m1; + *(htab_p-6) = m1; + *(htab_p-5) = m1; + *(htab_p-4) = m1; + *(htab_p-3) = m1; + *(htab_p-2) = m1; + *(htab_p-1) = m1; + htab_p -= 16; + } while((i -= 16) >= 0); + for( i += 16; i > 0; --i ) + *--htab_p = m1; +} + +/****************************************************************************** +* +* GIF Specific routines +* +******************************************************************************/ + +/* +* Set up the 'byte output' routine +*/ +void + gdGifEncoder::char_init(void) +{ + a_count = 0; +} + +/* +* Add a character to the end of the current packet, and if it is 254 +* characters, flush the packet to disk. +*/ +void + gdGifEncoder::char_out(int c) +{ + accum[ a_count++ ] = c; + if( a_count >= 254 ) + flush_char(); +} + +/* +* Flush the packet to disk, and reset the accumulator +*/ +void + gdGifEncoder::flush_char(void) +{ + if( a_count > 0 ) { + Putbyte( a_count ); + Write( accum, a_count); + a_count = 0; + } +} + +gdGifEncoder::gdGifEncoder(gdImage& aim, String& afp): pool(), + im(aim), + fp(afp) { + /* Some of these are properly initialized later. What I'm doing + here is making sure code that depends on C's initialization + of statics doesn't break when the code gets called more + than once. */ + Width = 0; + Height = 0; + curx = 0; + cury = 0; + CountDown = 0; + Pass = 0; + Interlace = 0; + a_count = 0; + cur_accum = 0; + cur_bits = 0; + g_init_bits = 0; + ClearCode = 0; + EOFCode = 0; + free_ent = 0; + clear_flg = 0; + offset = 0; + in_count = 1; + out_count = 0; + hsize = HSIZE; + n_bits = 0; + maxbits = GIFBITS; + maxcode = 0; + maxmaxcode =(code_int)1 << GIFBITS; +} + + +/* +-------------------------------------------------------------------+ */ +/* | Copyright 1990, 1991, 1993, David Koblas.(koblas@netcom.com) | */ +/* | Permission to use, copy, modify, and distribute this software | */ +/* | and its documentation for any purpose and without fee is hereby | */ +/* | granted, provided that the above copyright notice appear in all | */ +/* | copies and that both that copyright notice and this permission | */ +/* | notice appear in supporting documentation. This software is | */ +/* | provided "as is" without express or implied warranty. | */ +/* +-------------------------------------------------------------------+ */ + + #define MAXCOLORMAPSIZE 256 +#ifndef TRUE #define TRUE 1 +#endif +#ifndef FALSE #define FALSE 0 +#endif #define CM_RED 0 #define CM_GREEN 1 @@ -727,14 +760,16 @@ nomatch: unsigned int AspectRatio; }; #endif - + +/// Graphic Control Extension struct +#ifndef DOXYGEN struct Gif89 { int transparent; int delayTime; int inputFlag; int disposal; }; - +#endif static int ReadColorMap(FILE *fd, int number, unsigned char(*buffer)[256]); static int GetCode(FILE *fd, int code_size, int flag);