ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/ra_gif.c
Revision: 2.13
Committed: Fri Jul 19 17:37:56 2019 UTC (4 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4, rad5R3, HEAD
Changes since 2.12: +2 -3 lines
Log Message:
Moved declarations and definitions for header.c from resolu.h to rtio.h

File Contents

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