ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/ra_gif.c
Revision: 2.11
Committed: Sun Mar 28 20:33:14 2004 UTC (20 years ago) by schorsch
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R7P2, rad3R7P1, rad4R0, rad3R6, rad3R6P1, rad3R8, rad3R9
Changes since 2.10: +113 -70 lines
Log Message:
Continued ANSIfication, and other fixes and clarifications.

File Contents

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