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

# Content
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 }