#ifndef lint static const char RCSid[] = "$Id: ra_gif.c,v 2.11 2004/03/28 20:33:14 schorsch Exp $"; #endif /* * Convert from Radiance picture file to Compuserve GIF. * Currently, we don't know how to get back. */ #include #include #include #include "platform.h" #include "color.h" #include "resolu.h" #include "clrtab.h" #define MAXCOLORS 256 int rmap[MAXCOLORS]; int gmap[MAXCOLORS]; int bmap[MAXCOLORS]; int currow; long picstart; BYTE clrtab[256][3]; extern int samplefac; COLR *scanln; BYTE *pixscan; int xmax, ymax; /* picture size */ double gamv = 2.2; /* gamma correction */ int greyscale = 0; /* convert to B&W? */ int dither = 1; /* dither colors? */ int bradj = 0; /* brightness adjustment */ int ncolors = 0; /* number of colors requested */ char *progname; typedef int ifun_t(int x, int y); /* required by the GIF code below */ static void getrow(int y); static void mkclrmap(int nc); static void mkgrymap(int nc); static ifun_t getgifpix; static void GIFEncode(FILE *fp, int GWidth, int GHeight, int GInterlace, int Background, int BitsPerPixel, int Red[], int Green[], int Blue[], ifun_t* GetPixel); int main(int argc, char *argv[]) { int bitsperpix; int i; SET_DEFAULT_BINARY(); SET_FILE_BINARY(stdin); SET_FILE_BINARY(stdout); progname = argv[0]; samplefac = 0; for (i = 1; i < argc; i++) if (argv[i][0] == '-') switch (argv[i][1]) { case 'g': gamv = atof(argv[++i]); break; case 'b': greyscale = 1; break; case 'd': dither = !dither; break; case 'c': ncolors = atoi(argv[++i]); break; case 'e': if (argv[i+1][0] != '+' && argv[i+1][0] != '-') goto userr; bradj = atoi(argv[++i]); break; case 'n': samplefac = atoi(argv[++i]); break; default: goto userr; } else break; if (i < argc-2) goto userr; if (i <= argc-1 && freopen(argv[i], "r", stdin) == NULL) { fprintf(stderr, "%s: cannot open input \"%s\"\n", progname, argv[i]); exit(1); } if (i == argc-2 && freopen(argv[i+1], "w", stdout) == NULL) { fprintf(stderr, "%s: cannot open output \"%s\"\n", progname, argv[i+1]); exit(1); } if (checkheader(stdin, COLRFMT, NULL) < 0 || fgetresolu(&xmax, &ymax, stdin) < 0) { fprintf(stderr, "%s: bad picture format\n", progname); exit(1); } picstart = ftell(stdin); currow = -1; scanln = (COLR *)malloc(xmax*sizeof(COLR)); if (scanln == NULL) { fprintf(stderr, "%s: out of memory\n", progname); exit(1); } /* set up gamma correction */ setcolrgam(gamv); /* figure out the bits per pixel */ if ((ncolors < 2) | (ncolors > MAXCOLORS)) ncolors = MAXCOLORS; for (bitsperpix = 1; ncolors > 1<>8); if (pixscan != NULL) return(pixscan[x]); return(samplefac ? neu_map_pixel(scanln[x]) : map_pixel(scanln[x])); } /* * SCARY GIF code follows . . . . sorry. * * Based on GIFENCOD by David Rowley .A * Lempel-Ziv compression based on "compress". * */ /***************************************************************************** * * GIFENCODE.C - GIF Image compression interface * * GIFEncode( FName, GHeight, GWidth, GInterlace, Background, * BitsPerPixel, Red, Green, Blue, GetPixel ) * *****************************************************************************/ #define TRUE 1 #define FALSE 0 int Width, Height; int curx, cury; long CountDown; int Pass; int Interlace; unsigned long cur_accum = 0; int cur_bits = 0; static void BumpPixel(void); static int GIFNextPixel(ifun_t* getpixel); static void Putword(int w, FILE *fp); static void compress(int init_bits, FILE *outfile, ifun_t* ReadValue); /* a code_int must be able to hold 2**CBITS values of type int, and also -1 */ typedef int code_int; typedef long int count_int; typedef unsigned char char_type; static void output(code_int code); static void cl_block(void); static void cl_hash(count_int hsize); static void writeerr(void); static void char_init(void); static void char_out(int c); static void flush_char(void); static void gammawarp(short *sbuf, float gam, int n); /* * Bump the 'curx' and 'cury' to point to the next pixel */ static void BumpPixel(void) { curx++; if( curx == Width ) { curx = 0; if( !Interlace ) { cury++; } else { switch( Pass ) { case 0: cury += 8; if( cury >= Height ) { Pass++; cury = 4; } break; case 1: cury += 8; if( cury >= Height ) { Pass++; cury = 2; } break; case 2: cury += 4; if( cury >= Height ) { Pass++; cury = 1; } break; case 3: cury += 2; break; } } } } /* * Return the next pixel from the image */ static int GIFNextPixel( ifun_t* getpixel ) { int r; if( CountDown == 0 ) return EOF; CountDown--; r = (*getpixel)( curx, cury ); BumpPixel(); return r; } /* * public GIFEncode */ static void GIFEncode( FILE *fp, int GWidth, int GHeight, int GInterlace, int Background, int BitsPerPixel, int Red[], int Green[], int Blue[], ifun_t* GetPixel ) { int B; int RWidth, RHeight; int LeftOfs, TopOfs; int Resolution; int ColorMapSize; int InitCodeSize; int i; cur_accum = 0; /* globals */ cur_bits = 0; Interlace = GInterlace; ColorMapSize = 1 << BitsPerPixel; RWidth = Width = GWidth; RHeight = Height = GHeight; LeftOfs = TopOfs = 0; Resolution = BitsPerPixel; CountDown = (long)Width * (long)Height; Pass = 0; if( BitsPerPixel <= 1 ) InitCodeSize = 2; else InitCodeSize = BitsPerPixel; curx = cury = 0; fwrite( "GIF87a", 1, 6, fp ); Putword( RWidth, fp ); Putword( RHeight, fp ); B = 0x80; /* Yes, there is a color map */ B |= (Resolution - 1) << 5; B |= (BitsPerPixel - 1); fputc( B, fp ); fputc( Background, fp ); fputc( 0, fp ); for( i=0; i #define ARGVAL() (*++(*argv) || (--argc && *++argv)) int n_bits; /* number of bits/code */ int maxbits = CBITS; /* user settable max # bits/code */ code_int maxcode; /* maximum code, given n_bits */ code_int maxmaxcode = (code_int)1 << CBITS; /* should NEVER generate this code */ # define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1) count_int htab [HSIZE]; unsigned short codetab [HSIZE]; #define HashTabOf(i) htab[i] #define CodeTabOf(i) codetab[i] code_int hsize = HSIZE; /* for dynamic table sizing */ /* * To save much memory, we overlay the table used by compress() with those * used by decompress(). The tab_prefix table is the same size and type * as the codetab. The tab_suffix table needs 2**CBITS characters. We * get this from the beginning of htab. The output stack uses the rest * of htab, and contains characters. There is plenty of room for any * possible stack (stack used to be 8000 characters). */ #define tab_prefixof(i) CodeTabOf(i) #define tab_suffixof(i) ((char_type *)(htab))[i] #define de_stack ((char_type *)&tab_suffixof((code_int)1< 0 ) goto probe; nomatch: output ( (code_int) ent ); out_count++; ent = c; if ( free_ent < maxmaxcode ) { 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 ); return; } /***************************************************************** * 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 CBITS 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. */ unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; static void 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 ) ) writeerr(); } } /* * Clear out the hash table */ static void cl_block (void) /* table clear for block compress */ { cl_hash ( (count_int) hsize ); free_ent = ClearCode + 2; clear_flg = 1; output( (code_int)ClearCode ); } static void cl_hash( /* reset code table */ register count_int hsize ) { 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; } static void writeerr(void) { printf( "error writing output file\n" ); exit(1); } /****************************************************************************** * * GIF Specific routines * ******************************************************************************/ /* * Number of characters so far in this 'packet' */ int a_count; /* * Set up the 'byte output' routine */ static void char_init(void) { a_count = 0; } /* * Define the storage for the packet accumulator */ char accum[256]; /* * Add a character to the end of the current packet, and if it is 254 * characters, flush the packet to disk. */ static void char_out( int c ) { accum[ a_count++ ] = c; if( a_count >= 254 ) flush_char(); } /* * Flush the packet to disk, and reset the accumulator */ static void flush_char(void) { if( a_count > 0 ) { fputc( a_count, g_outfile ); fwrite( accum, 1, a_count, g_outfile ); a_count = 0; } } static float curgamma; static short gamtab[256]; static void gammawarp( short *sbuf, float gam, int n ) { int i; if(gam!=curgamma) { for(i=0; i<256; i++) gamtab[i] = 255*pow(i/255.0,gam)+0.5; curgamma = gam; } while(n--) { *sbuf = gamtab[*sbuf]; sbuf++; } }