ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/ra_gif.c
Revision: 2.2
Committed: Tue May 3 10:06:32 1994 UTC (30 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.1: +14 -0 lines
Log Message:
added -d option and made dithering the default

File Contents

# User Rev Content
1 greg 2.1 /* Copyright (c) 1994 Regents of the University of California */
2    
3     #ifndef lint
4     static char SCCSid[] = "$SunId$ LBL";
5     #endif
6    
7     /*
8     * Convert from Radiance picture file to Compuserve GIF.
9     * Currently, we don't know how to get back.
10     */
11    
12     #include <stdio.h>
13    
14     #include "color.h"
15    
16     #include "resolu.h"
17    
18     #ifdef MSDOS
19     #include <fcntl.h>
20     #endif
21    
22     #include <math.h>
23    
24     #define MAXCOLORS 256
25    
26     int rmap[MAXCOLORS];
27     int gmap[MAXCOLORS];
28     int bmap[MAXCOLORS];
29    
30     int currow;
31    
32     extern long ftell();
33    
34     long picstart;
35    
36     extern BYTE clrtab[][3];
37    
38     extern int getgifpix();
39    
40     COLR *scanln;
41 greg 2.2 BYTE *pixscan;
42 greg 2.1
43     int xmax, ymax; /* picture size */
44    
45     double gamv = 2.2; /* gamma correction */
46    
47     int greyscale = 0; /* convert to B&W? */
48    
49 greg 2.2 int dither = 1; /* dither colors? */
50    
51 greg 2.1 int bradj = 0; /* brightness adjustment */
52    
53     char *progname;
54    
55    
56     main(argc, argv)
57     int argc;
58     char *argv[];
59     {
60     int ncolors = 0;
61     int bitsperpix;
62     int i;
63     #ifdef MSDOS
64     extern int _fmode;
65     _fmode = O_BINARY;
66     setmode(fileno(stdin), O_BINARY);
67     setmode(fileno(stdout), O_BINARY);
68     #endif
69     progname = argv[0];
70    
71     for (i = 1; i < argc; i++)
72     if (argv[i][0] == '-')
73     switch (argv[i][1]) {
74     case 'g':
75     gamv = atof(argv[++i]);
76     break;
77     case 'b':
78     greyscale = 1;
79     break;
80 greg 2.2 case 'd':
81     dither = !dither;
82     break;
83 greg 2.1 case 'c':
84     ncolors = atoi(argv[++i]);
85     break;
86     case 'e':
87     if (argv[i+1][0] != '+' && argv[i+1][0] != '-')
88     goto userr;
89     bradj = atoi(argv[++i]);
90     break;
91     default:
92     goto userr;
93     }
94     else
95     break;
96    
97     if (i < argc-2)
98     goto userr;
99     if (i <= argc-1 && freopen(argv[i], "r", stdin) == NULL) {
100     fprintf(stderr, "%s: cannot open input \"%s\"\n",
101     progname, argv[i]);
102     exit(1);
103     }
104     if (i == argc-2 && freopen(argv[i+1], "w", stdout) == NULL) {
105     fprintf(stderr, "%s: cannot open output \"%s\"\n",
106     progname, argv[i+1]);
107     exit(1);
108     }
109     if (checkheader(stdin, COLRFMT, NULL) < 0 ||
110     fgetresolu(&xmax, &ymax, stdin) < 0) {
111     fprintf(stderr, "%s: bad picture format\n", progname);
112     exit(1);
113     }
114     picstart = ftell(stdin);
115     currow = -1;
116     scanln = (COLR *)malloc(xmax*sizeof(COLR));
117     if (scanln == NULL) {
118     fprintf(stderr, "%s: out of memory\n", progname);
119     exit(1);
120     }
121     /* set up gamma correction */
122     setcolrgam(gamv);
123     /* figure out the bits per pixel */
124     if (ncolors < 2 | ncolors > MAXCOLORS)
125     ncolors = MAXCOLORS;
126     for (bitsperpix = 1; ncolors > 1<<bitsperpix; bitsperpix++)
127     ;
128     /* compute color map */
129     if (greyscale)
130     mkgrymap(ncolors);
131     else
132     mkclrmap(ncolors);
133     /* convert image */
134     GIFEncode(stdout, xmax, ymax, 0, 0, bitsperpix,
135     rmap, gmap, bmap, getgifpix);
136     exit(0);
137     userr:
138     fprintf(stderr,
139     "Usage: %s [-b][-c ncolors][-g gamv][-e +/-stops] input [output]\n",
140     progname);
141     exit(1);
142     }
143    
144    
145     getrow(y) /* get the specified row from our image */
146     int y;
147     {
148     if (y == currow)
149     return;
150     if (y < currow) {
151     fseek(stdin, picstart, 0);
152     currow = -1;
153     }
154     do
155     if (freadcolrs(scanln, xmax, stdin) < 0) {
156     fprintf(stderr, "%s: error reading picture (y==%d)\n",
157     progname, ymax-1-y);
158     }
159     while (++currow < y);
160     if (bradj)
161     shiftcolrs(scanln, xmax, bradj);
162     colrs_gambs(scanln, xmax);
163 greg 2.2 if (pixscan != NULL)
164     dith_colrs(pixscan, scanln, xmax);
165 greg 2.1 }
166    
167    
168     mkclrmap(nc) /* make our color map */
169     int nc;
170     {
171     register int i;
172    
173     new_histo();
174     for (i = 0; i < ymax; i++) {
175     getrow(i);
176     cnt_colrs(scanln, xmax);
177     }
178     new_clrtab(nc);
179     for (i = 0; i < nc; i++) {
180     rmap[i] = clrtab[i][RED];
181     gmap[i] = clrtab[i][GRN];
182     bmap[i] = clrtab[i][BLU];
183     }
184 greg 2.2 if (dither && (pixscan = (BYTE *)malloc(xmax)) == NULL) {
185     fprintf(stderr, "%s: out of memory\n", progname);
186     exit(1);
187     }
188 greg 2.1 }
189    
190    
191     mkgrymap(nc)
192     int nc;
193     {
194     register int i;
195    
196     for (i = 0; i < nc; i++) {
197     rmap[i] =
198     gmap[i] =
199     bmap[i] = ((unsigned)i<<8)/nc;
200     }
201     }
202    
203    
204     int
205     getgifpix(x, y) /* get a single pixel from our picture */
206     int x, y;
207     {
208     int pix;
209    
210     getrow(y);
211     if (greyscale)
212     return(normbright(scanln[x]));
213 greg 2.2 if (pixscan != NULL)
214     return(pixscan[x]);
215 greg 2.1 return(map_pixel(scanln[x]));
216     }
217    
218    
219     /*
220     * SCARY GIF code follows . . . . sorry.
221     *
222     * Based on GIFENCOD by David Rowley <[email protected]>.A
223     * Lempel-Zim compression based on "compress".
224     *
225     */
226    
227     /*****************************************************************************
228     *
229     * GIFENCODE.C - GIF Image compression interface
230     *
231     * GIFEncode( FName, GHeight, GWidth, GInterlace, Background,
232     * BitsPerPixel, Red, Green, Blue, GetPixel )
233     *
234     *****************************************************************************/
235     typedef int (* ifunptr)();
236    
237     #define TRUE 1
238     #define FALSE 0
239    
240     int Width, Height;
241     int curx, cury;
242     long CountDown;
243     int Pass;
244     int Interlace;
245     unsigned long cur_accum = 0;
246     int cur_bits = 0;
247    
248     /*
249     * Bump the 'curx' and 'cury' to point to the next pixel
250     */
251     BumpPixel()
252     {
253     curx++;
254     if( curx == Width ) {
255     curx = 0;
256     if( !Interlace ) {
257     cury++;
258     } else {
259     switch( Pass ) {
260     case 0:
261     cury += 8;
262     if( cury >= Height ) {
263     Pass++;
264     cury = 4;
265     }
266     break;
267     case 1:
268     cury += 8;
269     if( cury >= Height ) {
270     Pass++;
271     cury = 2;
272     }
273     break;
274     case 2:
275     cury += 4;
276     if( cury >= Height ) {
277     Pass++;
278     cury = 1;
279     }
280     break;
281     case 3:
282     cury += 2;
283     break;
284     }
285     }
286     }
287     }
288    
289     /*
290     * Return the next pixel from the image
291     */
292     GIFNextPixel( getpixel )
293     ifunptr getpixel;
294     {
295     int r;
296    
297     if( CountDown == 0 )
298     return EOF;
299     CountDown--;
300     r = (*getpixel)( curx, cury );
301     BumpPixel();
302     return r;
303     }
304    
305     /*
306     * public GIFEncode
307     */
308     GIFEncode( fp, GWidth, GHeight, GInterlace, Background,
309     BitsPerPixel, Red, Green, Blue, GetPixel )
310     FILE *fp;
311     int GWidth, GHeight;
312     int GInterlace;
313     int Background;
314     int BitsPerPixel;
315     int Red[], Green[], Blue[];
316     ifunptr GetPixel;
317     {
318     int B;
319     int RWidth, RHeight;
320     int LeftOfs, TopOfs;
321     int Resolution;
322     int ColorMapSize;
323     int InitCodeSize;
324     int i;
325    
326     long cur_accum = 0;
327     cur_bits = 0;
328    
329     Interlace = GInterlace;
330     ColorMapSize = 1 << BitsPerPixel;
331     RWidth = Width = GWidth;
332     RHeight = Height = GHeight;
333     LeftOfs = TopOfs = 0;
334     Resolution = BitsPerPixel;
335    
336     CountDown = (long)Width * (long)Height;
337     Pass = 0;
338     if( BitsPerPixel <= 1 )
339     InitCodeSize = 2;
340     else
341     InitCodeSize = BitsPerPixel;
342     curx = cury = 0;
343     fwrite( "GIF87a", 1, 6, fp );
344     Putword( RWidth, fp );
345     Putword( RHeight, fp );
346     B = 0x80; /* Yes, there is a color map */
347     B |= (Resolution - 1) << 5;
348     B |= (BitsPerPixel - 1);
349     fputc( B, fp );
350     fputc( Background, fp );
351     fputc( 0, fp );
352     for( i=0; i<ColorMapSize; i++ ) {
353     fputc( Red[i], fp );
354     fputc( Green[i], fp );
355     fputc( Blue[i], fp );
356     }
357     fputc( ',', fp );
358     Putword( LeftOfs, fp );
359     Putword( TopOfs, fp );
360     Putword( Width, fp );
361     Putword( Height, fp );
362     if( Interlace )
363     fputc( 0x40, fp );
364     else
365     fputc( 0x00, fp );
366     fputc( InitCodeSize, fp );
367     compress( InitCodeSize+1, fp, GetPixel );
368     fputc( 0, fp );
369     fputc( ';', fp );
370     fclose( fp );
371     }
372    
373     /*
374     * Write out a word to the GIF file
375     */
376     Putword( w, fp )
377     int w;
378     FILE *fp;
379     {
380     fputc( w & 0xff, fp );
381     fputc( (w/256) & 0xff, fp );
382     }
383    
384    
385     /***************************************************************************
386     *
387     * GIFCOMPR.C - GIF Image compression routines
388     *
389     * Lempel-Ziv compression based on 'compress'. GIF modifications by
390     * David Rowley ([email protected])
391     *
392     ***************************************************************************/
393    
394     #define CBITS 12
395     #define HSIZE 5003 /* 80% occupancy */
396    
397     /*
398     * a code_int must be able to hold 2**CBITS values of type int, and also -1
399     */
400     typedef int code_int;
401     typedef long int count_int;
402     typedef unsigned char char_type;
403    
404     /*
405     *
406     * GIF Image compression - modified 'compress'
407     *
408     * Based on: compress.c - File compression ala IEEE Computer, June 1984.
409     *
410     * By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
411     * Jim McKie (decvax!mcvax!jim)
412     * Steve Davies (decvax!vax135!petsd!peora!srd)
413     * Ken Turkowski (decvax!decwrl!turtlevax!ken)
414     * James A. Woods (decvax!ihnp4!ames!jaw)
415     * Joe Orost (decvax!vax135!petsd!joe)
416     *
417     */
418     #include <ctype.h>
419    
420     #define ARGVAL() (*++(*argv) || (--argc && *++argv))
421    
422     int n_bits; /* number of bits/code */
423     int maxbits = CBITS; /* user settable max # bits/code */
424     code_int maxcode; /* maximum code, given n_bits */
425     code_int maxmaxcode = (code_int)1 << CBITS; /* should NEVER generate this code */
426     # define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1)
427    
428     count_int htab [HSIZE];
429     unsigned short codetab [HSIZE];
430     #define HashTabOf(i) htab[i]
431     #define CodeTabOf(i) codetab[i]
432    
433     code_int hsize = HSIZE; /* for dynamic table sizing */
434    
435     /*
436     * To save much memory, we overlay the table used by compress() with those
437     * used by decompress(). The tab_prefix table is the same size and type
438     * as the codetab. The tab_suffix table needs 2**CBITS characters. We
439     * get this from the beginning of htab. The output stack uses the rest
440     * of htab, and contains characters. There is plenty of room for any
441     * possible stack (stack used to be 8000 characters).
442     */
443     #define tab_prefixof(i) CodeTabOf(i)
444     #define tab_suffixof(i) ((char_type *)(htab))[i]
445     #define de_stack ((char_type *)&tab_suffixof((code_int)1<<CBITS))
446    
447     code_int free_ent = 0; /* first unused entry */
448    
449     /*
450     * block compression parameters -- after all codes are used up,
451     * and compression rate changes, start over.
452     */
453     int clear_flg = 0;
454     int offset;
455     long int in_count = 1; /* length of input */
456     long int out_count = 0; /* # of codes output (for debugging) */
457    
458     /*
459     * compress stdin to stdout
460     *
461     * Algorithm: use open addressing double hashing (no chaining) on the
462     * prefix code / next character combination. We do a variant of Knuth's
463     * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
464     * secondary probe. Here, the modular division first probe is gives way
465     * to a faster exclusive-or manipulation. Also do block compression with
466     * an adaptive reset, whereby the code table is cleared when the compression
467     * ratio decreases, but after the table fills. The variable-length output
468     * codes are re-sized at this point, and a special CLEAR code is generated
469     * for the decompressor. Late addition: construct the table according to
470     * file size for noticeable speed improvement on small files. Please direct
471     * questions about this implementation to ames!jaw.
472     */
473    
474     int g_init_bits;
475     FILE *g_outfile;
476     int ClearCode;
477     int EOFCode;
478    
479     compress( init_bits, outfile, ReadValue )
480     int init_bits;
481     FILE *outfile;
482     ifunptr ReadValue;
483     {
484     register long fcode;
485     register code_int i = 0;
486     register int c;
487     register code_int ent;
488     register code_int disp;
489     register code_int hsize_reg;
490     register int hshift;
491    
492     /*
493     * Set up the globals: g_init_bits - initial number of bits
494     * g_outfile - pointer to output file
495     */
496     g_init_bits = init_bits;
497     g_outfile = outfile;
498     /*
499     * Set up the necessary values
500     */
501     offset = 0;
502     out_count = 0;
503     clear_flg = 0;
504     in_count = 1;
505     maxcode = MAXCODE(n_bits = g_init_bits);
506     ClearCode = (1 << (init_bits - 1));
507     EOFCode = ClearCode + 1;
508     free_ent = ClearCode + 2;
509     char_init();
510     ent = GIFNextPixel( ReadValue );
511     hshift = 0;
512     for ( fcode = (long) hsize; fcode < 65536L; fcode *= 2L )
513     hshift++;
514     hshift = 8 - hshift; /* set hash code range bound */
515     hsize_reg = hsize;
516     cl_hash( (count_int) hsize_reg); /* clear hash table */
517     output( (code_int)ClearCode );
518     while ( (c = GIFNextPixel( ReadValue )) != EOF ) {
519     in_count++;
520     fcode = (long) (((long) c << maxbits) + ent);
521     /* i = (((code_int)c << hshift) ~ ent); /* xor hashing */
522     i = (((code_int)c << hshift) ^ ent); /* xor hashing */
523     if ( HashTabOf (i) == fcode ) {
524     ent = CodeTabOf (i);
525     continue;
526     } else if ( (long)HashTabOf (i) < 0 ) /* empty slot */
527     goto nomatch;
528     disp = hsize_reg - i; /* secondary hash (after G. Knott) */
529     if ( i == 0 )
530     disp = 1;
531     probe:
532     if ( (i -= disp) < 0 )
533     i += hsize_reg;
534     if ( HashTabOf (i) == fcode ) {
535     ent = CodeTabOf (i);
536     continue;
537     }
538     if ( (long)HashTabOf (i) > 0 )
539     goto probe;
540     nomatch:
541     output ( (code_int) ent );
542     out_count++;
543     ent = c;
544     if ( free_ent < maxmaxcode ) {
545     CodeTabOf (i) = free_ent++; /* code -> hashtable */
546     HashTabOf (i) = fcode;
547     } else
548     cl_block();
549     }
550     /*
551     * Put out the final code.
552     */
553     output( (code_int)ent );
554     out_count++;
555     output( (code_int) EOFCode );
556     return;
557     }
558    
559     /*****************************************************************
560     * TAG( output )
561     *
562     * Output the given code.
563     * Inputs:
564     * code: A n_bits-bit integer. If == -1, then EOF. This assumes
565     * that n_bits =< (long)wordsize - 1.
566     * Outputs:
567     * Outputs code to the file.
568     * Assumptions:
569     * Chars are 8 bits long.
570     * Algorithm:
571     * Maintain a CBITS character long buffer (so that 8 codes will
572     * fit in it exactly). Use the VAX insv instruction to insert each
573     * code in turn. When the buffer fills up empty it and start over.
574     */
575    
576     unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
577     0x001F, 0x003F, 0x007F, 0x00FF,
578     0x01FF, 0x03FF, 0x07FF, 0x0FFF,
579     0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
580    
581     output( code )
582     code_int code;
583     {
584     cur_accum &= masks[ cur_bits ];
585     if( cur_bits > 0 )
586     cur_accum |= ((long)code << cur_bits);
587     else
588     cur_accum = code;
589     cur_bits += n_bits;
590     while( cur_bits >= 8 ) {
591     char_out( (unsigned int)(cur_accum & 0xff) );
592     cur_accum >>= 8;
593     cur_bits -= 8;
594     }
595    
596     /*
597     * If the next entry is going to be too big for the code size,
598     * then increase it, if possible.
599     */
600     if ( free_ent > maxcode || clear_flg ) {
601     if( clear_flg ) {
602     maxcode = MAXCODE (n_bits = g_init_bits);
603     clear_flg = 0;
604     } else {
605     n_bits++;
606     if ( n_bits == maxbits )
607     maxcode = maxmaxcode;
608     else
609     maxcode = MAXCODE(n_bits);
610     }
611     }
612     if( code == EOFCode ) {
613     /*
614     * At EOF, write the rest of the buffer.
615     */
616     while( cur_bits > 0 ) {
617     char_out( (unsigned int)(cur_accum & 0xff) );
618     cur_accum >>= 8;
619     cur_bits -= 8;
620     }
621     flush_char();
622     fflush( g_outfile );
623     if( ferror( g_outfile ) )
624     writeerr();
625     }
626     }
627    
628     /*
629     * Clear out the hash table
630     */
631     cl_block () /* table clear for block compress */
632     {
633     cl_hash ( (count_int) hsize );
634     free_ent = ClearCode + 2;
635     clear_flg = 1;
636     output( (code_int)ClearCode );
637     }
638    
639     cl_hash(hsize) /* reset code table */
640     register count_int hsize;
641     {
642     register count_int *htab_p = htab+hsize;
643     register long i;
644     register long m1 = -1;
645    
646     i = hsize - 16;
647     do { /* might use Sys V memset(3) here */
648     *(htab_p-16) = m1;
649     *(htab_p-15) = m1;
650     *(htab_p-14) = m1;
651     *(htab_p-13) = m1;
652     *(htab_p-12) = m1;
653     *(htab_p-11) = m1;
654     *(htab_p-10) = m1;
655     *(htab_p-9) = m1;
656     *(htab_p-8) = m1;
657     *(htab_p-7) = m1;
658     *(htab_p-6) = m1;
659     *(htab_p-5) = m1;
660     *(htab_p-4) = m1;
661     *(htab_p-3) = m1;
662     *(htab_p-2) = m1;
663     *(htab_p-1) = m1;
664     htab_p -= 16;
665     } while ((i -= 16) >= 0);
666     for ( i += 16; i > 0; i-- )
667     *--htab_p = m1;
668     }
669    
670     writeerr()
671     {
672     printf( "error writing output file\n" );
673     exit(1);
674     }
675    
676     /******************************************************************************
677     *
678     * GIF Specific routines
679     *
680     ******************************************************************************/
681    
682     /*
683     * Number of characters so far in this 'packet'
684     */
685     int a_count;
686    
687     /*
688     * Set up the 'byte output' routine
689     */
690     char_init()
691     {
692     a_count = 0;
693     }
694    
695     /*
696     * Define the storage for the packet accumulator
697     */
698     char accum[256];
699    
700     /*
701     * Add a character to the end of the current packet, and if it is 254
702     * characters, flush the packet to disk.
703     */
704     char_out( c )
705     int c;
706     {
707     accum[ a_count++ ] = c;
708     if( a_count >= 254 )
709     flush_char();
710     }
711    
712     /*
713     * Flush the packet to disk, and reset the accumulator
714     */
715     flush_char()
716     {
717     if( a_count > 0 ) {
718     fputc( a_count, g_outfile );
719     fwrite( accum, 1, a_count, g_outfile );
720     a_count = 0;
721     }
722     }
723    
724     static float curgamma;
725     static short gamtab[256];
726    
727     gammawarp(sbuf,gam,n)
728     short *sbuf;
729     float gam;
730     int n;
731     {
732     int i;
733     float f;
734    
735     if(gam!=curgamma) {
736     for(i=0; i<256; i++)
737     gamtab[i] = 255*pow(i/255.0,gam)+0.5;
738     curgamma = gam;
739     }
740     while(n--) {
741     *sbuf = gamtab[*sbuf];
742     sbuf++;
743     }
744     }