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

# 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 BYTE *pixscan;
42
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 int dither = 1; /* dither colors? */
50
51 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 case 'd':
81 dither = !dither;
82 break;
83 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 if (pixscan != NULL)
164 dith_colrs(pixscan, scanln, xmax);
165 }
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 if (dither && (pixscan = (BYTE *)malloc(xmax)) == NULL) {
185 fprintf(stderr, "%s: out of memory\n", progname);
186 exit(1);
187 }
188 }
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 if (pixscan != NULL)
214 return(pixscan[x]);
215 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 }