ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/ra_gif.c
Revision: 2.3
Committed: Fri May 20 11:44:19 1994 UTC (29 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.2: +1 -0 lines
Log Message:
fixed bug in read error handling

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