ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/ra_gif.c
Revision: 2.1
Committed: Wed Mar 30 14:24:52 1994 UTC (30 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Initial revision

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