ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/doc/notes/picture.format
Revision: 1.1
Committed: Sat Mar 15 17:32:55 2003 UTC (21 years, 1 month ago) by greg
Branch: MAIN
CVS Tags: rad3R7P2, rad3R7P1, rad3R5, rad3R6, rad3R6P1
Log Message:
Added and updated documentation for 3.5 release

File Contents

# User Rev Content
1 greg 1.1 The RADIANCE Picture File Format
2    
3     Radiance is a lighting simulation and rendering system available by
4     anonymous ftp from hobbes.lbl.gov (128.3.12.38). The picture file
5     format used by the program uses a floating point representation that
6     provides greater fidelity and numerical accuracy over a 24-bit
7     image, without taking much extra space.
8    
9     At the end of this message I have put a shar file of the routines you
10     need to read and write Radiance pictures. The format has been
11     enhanced slightly for the next release (in an upward compatible
12     way), so you should definitely use these newer routines.
13    
14     The file format, like most binary files used by Radiance, contains
15     an ASCII information header that is terminated by an empty line.
16     This header typically begins with the line "#?RADIANCE", followd
17     by the commands used to generate the file, along with variables
18     indicating exposure, view parameters, and so on. Next there is a
19     single line that indicates the resolution and pixel scanning order of
20     the image. For Radiance pictures, the pixels are order as English
21     text, left to right and top to bottom. This is indicated with a line
22     of the form:
23    
24     -Y M +X N
25    
26     Where M and N are the y and x resolutions, respectively. The x and y
27     image coordinates are always the same, starting with (0,0) at the lower
28     left corner, (N,0) at the lower right, and (0,M) at the upper left.
29     The y resolution appears first in our specification because it is the
30     major sort, and is preceded by a minus sign because it is decreasing in
31     the file.
32    
33     Finally, the floating point scanlines follow. Each pixel is represented by
34     at most 4 bytes. The first three bytes are the red, green and blue mantissas
35     (in that order), and the fourth byte is a common exponent. The floating point
36     color (R,G,B)=(1.,.5,.25) would be represented by the bytes (128,64,32,129).
37     The conversion back to floating point is possible using the ldexp() library
38     routine, or it's better to use the colr_color() routine included in color.c.
39    
40     The scanlines are usually run-length encoded. My previous scheme (release 1.4
41     and earlier) used a simple count for repeated pixels. My new scheme is
42     more complicated and encodes the four components separately. I don't
43     recommend writing your own routine to decode it -- use what's in color.c.
44    
45     A skeletal program to read a Radiance picture file and convert to 24-bit
46     gamma-corrected color looks like this:
47    
48     /* Copyright (c) 1992 Regents of the University of California */
49    
50     #ifndef lint
51     static char SCCSid[] = "@(#)ra_skel.c 2.9 2/27/94 LBL";
52     #endif
53    
54     /*
55     * Skeletal 24-bit image conversion program. Replace "skel"
56     * in this file with a more appropriate image type identifier.
57     *
58     * The Rmakefile entry should look something like this:
59     * ra_skel: ra_skel.o
60     * cc $(CFLAGS) -o ra_skel ra_skel.o -lrt -lm
61     * ra_skel.o: ../common/color.h ../common/resolu.h
62     *
63     * If you like to do things the hard way, you can link directly
64     * to the object files "color.o colrops.o resolu.o header.o" in
65     * the common subdirectory instead of using the -lrt library.
66     */
67    
68     #include <stdio.h>
69     #include <math.h>
70     #ifdef MSDOS
71     #include <fcntl.h>
72     #endif
73     #include "color.h"
74     #include "resolu.h"
75    
76     extern char *malloc();
77    
78     double gamcor = 2.2; /* gamma correction */
79    
80     int bradj = 0; /* brightness adjustment */
81    
82     char *progname;
83    
84     int xmax, ymax;
85    
86    
87     main(argc, argv)
88     int argc;
89     char *argv[];
90     {
91     int reverse = 0;
92     int i;
93    
94     progname = argv[0];
95    
96     for (i = 1; i < argc; i++)
97     if (argv[i][0] == '-')
98     switch (argv[i][1]) {
99     case 'g': /* gamma correction */
100     gamcor = atof(argv[++i]);
101     break;
102     case 'e': /* exposure adjustment */
103     if (argv[i+1][0] != '+' && argv[i+1][0] != '-')
104     goto userr;
105     bradj = atoi(argv[++i]);
106     break;
107     case 'r': /* reverse conversion */
108     reverse = 1;
109     break;
110     default:
111     goto userr;
112     }
113     else
114     break;
115    
116     if (i < argc-2)
117     goto userr;
118     if (i <= argc-1 && freopen(argv[i], "r", stdin) == NULL) {
119     fprintf(stderr, "%s: can't open input \"%s\"\n",
120     progname, argv[i]);
121     exit(1);
122     }
123     if (i == argc-2 && freopen(argv[i+1], "w", stdout) == NULL) {
124     fprintf(stderr, "%s: can't open output \"%s\"\n",
125     progname, argv[i+1]);
126     exit(1);
127     }
128     #ifdef MSDOS
129     setmode(fileno(stdin), O_BINARY);
130     setmode(fileno(stdout), O_BINARY);
131     #endif
132     setcolrgam(gamcor); /* set up gamma correction */
133     if (reverse) {
134     /* get their image resolution */
135     read_skel_head(&xmax, &ymax);
136     /* put our header */
137     newheader("RADIANCE", stdout);
138     printargs(i, argv, stdout);
139     fputformat(COLRFMT, stdout);
140     putchar('\n');
141     fprtresolu(xmax, ymax, stdout);
142     /* convert file */
143     skel2ra();
144     } else {
145     /* get our header */
146     if (checkheader(stdin, COLRFMT, NULL) < 0 ||
147     fgetresolu(&xmax, &ymax, stdin) < 0)
148     quiterr("bad picture format");
149     /* write their header */
150     write_skel_head(xmax, ymax);
151     /* convert file */
152     ra2skel();
153     }
154     exit(0);
155     userr:
156     fprintf(stderr,
157     "Usage: %s [-r][-g gamma][-e +/-stops] [input [output]]\n",
158     progname);
159     exit(1);
160     }
161    
162    
163     quiterr(err) /* print message and exit */
164     char *err;
165     {
166     if (err != NULL) {
167     fprintf(stderr, "%s: %s\n", progname, err);
168     exit(1);
169     }
170     exit(0);
171     }
172    
173    
174     skel2ra() /* convert 24-bit scanlines to Radiance picture */
175     {
176     COLR *scanout;
177     register int x;
178     int y;
179     /* allocate scanline */
180     scanout = (COLR *)malloc(xmax*sizeof(COLR));
181     if (scanout == NULL)
182     quiterr("out of memory in skel2ra");
183     /* convert image */
184     for (y = ymax-1; y >= 0; y--) {
185     for (x = 0; x < xmax; x++) {
186     scanout[x][RED] = getc(stdin);
187     scanout[x][GRN] = getc(stdin);
188     scanout[x][BLU] = getc(stdin);
189     }
190     if (feof(stdin) | ferror(stdin))
191     quiterr("error reading skel image");
192     /* undo gamma */
193     gambs_colrs(scanout, xmax);
194     if (bradj) /* adjust exposure */
195     shiftcolrs(scanout, xmax, bradj);
196     if (fwritecolrs(scanout, xmax, stdout) < 0)
197     quiterr("error writing Radiance picture");
198     }
199     /* free scanline */
200     free((char *)scanout);
201     }
202    
203    
204     ra2skel() /* convert Radiance scanlines to 24-bit */
205     {
206     COLR *scanin;
207     register int x;
208     int y;
209     /* allocate scanline */
210     scanin = (COLR *)malloc(xmax*sizeof(COLR));
211     if (scanin == NULL)
212     quiterr("out of memory in ra2skel");
213     /* convert image */
214     for (y = ymax-1; y >= 0; y--) {
215     if (freadcolrs(scanin, xmax, stdin) < 0)
216     quiterr("error reading Radiance picture");
217     if (bradj) /* adjust exposure */
218     shiftcolrs(scanin, xmax, bradj);
219     colrs_gambs(scanin, xmax); /* gamma correction */
220     for (x = 0; x < xmax; x++) {
221     putc(scanin[x][RED], stdout);
222     putc(scanin[x][GRN], stdout);
223     putc(scanin[x][BLU], stdout);
224     }
225     if (ferror(stdout))
226     quiterr("error writing skel file");
227     }
228     /* free scanline */
229     free((char *)scanin);
230     }
231     --------------------------------------------------------------
232    
233     You will find all the routines you need in ray/src/common. The
234     checkheader() routine is in the module header.c, fgetresolu is in resolu.c,
235     freadcolrs() is in color.c, and setcolrgam() and colrs_gambs() are
236     in the module colrops.c.
237    
238     If you want to convert the file to 8-bit color, the process is quite a
239     bit more complicated. I suggest you take a look at the ra_t8.c program
240     in the ray/src/px directory to get a better idea of what is involved.
241    
242     ------------------------------
243     #! /bin/sh
244     # This is a shell archive, meaning:
245     # 1. Remove everything above the #! /bin/sh line.
246     # 2. Save the resulting text in a file.
247     # 3. Execute the file with /bin/sh (not csh) to create:
248     # color.h
249     # resolu.h
250     # resolu.c
251     # header.c
252     # color.c
253     # colrops.c
254     # This archive created: Tue Apr 5 14:07:02 1994
255     export PATH; PATH=/bin:/usr/bin:$PATH
256     if test -f 'color.h'
257     then
258     echo shar: "will not over-write existing file 'color.h'"
259     else
260     sed 's/^X//' << \SHAR_EOF > 'color.h'
261     X/* Copyright (c) 1991 Regents of the University of California */
262     X
263     X/* SCCSid "@(#)color.h 2.6 8/2/93 LBL" */
264     X
265     X/*
266     X * color.h - header for routines using pixel color values.
267     X *
268     X * 12/31/85
269     X *
270     X * Two color representations are used, one for calculation and
271     X * another for storage. Calculation is done with three floats
272     X * for speed. Stored color values use 4 bytes which contain
273     X * three single byte mantissas and a common exponent.
274     X */
275     X
276     X#define RED 0
277     X#define GRN 1
278     X#define BLU 2
279     X#define EXP 3
280     X#define COLXS 128 /* excess used for exponent */
281     X
282     Xtypedef unsigned char BYTE; /* 8-bit unsigned integer */
283     X
284     Xtypedef BYTE COLR[4]; /* red, green, blue, exponent */
285     X
286     X#define copycolr(c1,c2) (c1[0]=c2[0],c1[1]=c2[1], \
287     X c1[2]=c2[2],c1[3]=c2[3])
288     X
289     Xtypedef float COLOR[3]; /* red, green, blue */
290     X
291     X#define colval(col,pri) ((col)[pri])
292     X
293     X#define setcolor(col,r,g,b) ((col)[RED]=(r),(col)[GRN]=(g),(col)[BLU]=(b))
294     X
295     X#define copycolor(c1,c2) ((c1)[0]=(c2)[0],(c1)[1]=(c2)[1],(c1)[2]=(c2)[2])
296     X
297     X#define scalecolor(col,sf) ((col)[0]*=(sf),(col)[1]*=(sf),(col)[2]*=(sf))
298     X
299     X#define addcolor(c1,c2) ((c1)[0]+=(c2)[0],(c1)[1]+=(c2)[1],(c1)[2]+=(c2)[2])
300     X
301     X#define multcolor(c1,c2) ((c1)[0]*=(c2)[0],(c1)[1]*=(c2)[1],(c1)[2]*=(c2)[2])
302     X
303     X#ifdef NTSC
304     X#define bright(col) (.295*(col)[RED]+.636*(col)[GRN]+.070*(col)[BLU])
305     X#define normbright(c) (int)((74L*(c)[RED]+164L*(c)[GRN]+18L*(c)[BLU])>>8)
306     X#else
307     X#define bright(col) (.263*(col)[RED]+.655*(col)[GRN]+.082*(col)[BLU])
308     X#define normbright(c) (int)((67L*(c)[RED]+168L*(c)[GRN]+21L*(c)[BLU])>>8)
309     X#endif
310     X
311     X /* luminous efficacies over visible spectrum */
312     X#define MAXEFFICACY 683. /* defined maximum at 550 nm */
313     X#define WHTEFFICACY 179. /* uniform white light */
314     X#define D65EFFICACY 203. /* standard illuminant D65 */
315     X#define INCEFFICACY 160. /* illuminant A (incand.) */
316     X#define SUNEFFICACY 208. /* illuminant B (solar dir.) */
317     X#define SKYEFFICACY D65EFFICACY /* skylight */
318     X#define DAYEFFICACY D65EFFICACY /* combined sky and solar */
319     X
320     X#define luminance(col) (WHTEFFICACY * bright(col))
321     X
322     X#define intens(col) ( (col)[0] > (col)[1] \
323     X ? (col)[0] > (col)[2] ? (col)[0] : (col)[2] \
324     X : (col)[1] > (col)[2] ? (col)[1] : (col)[2] )
325     X
326     X#define colrval(c,p) ( (c)[EXP] ? \
327     X ldexp((c)[p]+.5,(int)(c)[EXP]-(COLXS+8)) : \
328     X 0. )
329     X
330     X#define WHTCOLOR {1.0,1.0,1.0}
331     X#define BLKCOLOR {0.0,0.0,0.0}
332     X#define WHTCOLR {128,128,128,COLXS+1}
333     X#define BLKCOLR {0,0,0,0}
334     X
335     X /* picture format identifier */
336     X#define COLRFMT "32-bit_rle_rgbe"
337     X
338     X /* macros for exposures */
339     X#define EXPOSSTR "EXPOSURE="
340     X#define LEXPOSSTR 9
341     X#define isexpos(hl) (!strncmp(hl,EXPOSSTR,LEXPOSSTR))
342     X#define exposval(hl) atof((hl)+LEXPOSSTR)
343     X#define fputexpos(ex,fp) fprintf(fp,"%s%e\n",EXPOSSTR,ex)
344     X
345     X /* macros for pixel aspect ratios */
346     X#define ASPECTSTR "PIXASPECT="
347     X#define LASPECTSTR 10
348     X#define isaspect(hl) (!strncmp(hl,ASPECTSTR,LASPECTSTR))
349     X#define aspectval(hl) atof((hl)+LASPECTSTR)
350     X#define fputaspect(pa,fp) fprintf(fp,"%s%f\n",ASPECTSTR,pa)
351     X
352     X /* macros for color correction */
353     X#define COLCORSTR "COLORCORR="
354     X#define LCOLCORSTR 10
355     X#define iscolcor(hl) (!strncmp(hl,COLCORSTR,LCOLCORSTR))
356     X#define colcorval(cc,hl) sscanf(hl+LCOLCORSTR,"%f %f %f", \
357     X &(cc)[RED],&(cc)[GRN],&(cc)[BLU])
358     X#define fputcolcor(cc,fp) fprintf(fp,"%s %f %f %f\n",COLCORSTR, \
359     X (cc)[RED],(cc)[GRN],(cc)[BLU])
360     X
361     X#ifdef DCL_ATOF
362     Xextern double atof(), ldexp(), frexp();
363     X#endif
364     SHAR_EOF
365     fi
366     if test -f 'resolu.h'
367     then
368     echo shar: "will not over-write existing file 'resolu.h'"
369     else
370     sed 's/^X//' << \SHAR_EOF > 'resolu.h'
371     X/* Copyright (c) 1991 Regents of the University of California */
372     X
373     X/* SCCSid "@(#)resolu.h 2.2 6/4/93 LBL" */
374     X
375     X/*
376     X * Definitions for resolution line in image file.
377     X *
378     X * True image orientation is defined by an xy coordinate system
379     X * whose origin is at the lower left corner of the image, with
380     X * x increasing to the right and y increasing in the upward direction.
381     X * This true orientation is independent of how the pixels are actually
382     X * ordered in the file, which is indicated by the resolution line.
383     X * This line is of the form "{+-}{XY} xyres {+-}{YX} yxres\n".
384     X * A typical line for a 1024x600 image might be "-Y 600 +X 1024\n",
385     X * indicating that the scanlines are in English text order (PIXSTANDARD).
386     X */
387     X
388     X /* flags for scanline ordering */
389     X#define XDECR 1
390     X#define YDECR 2
391     X#define YMAJOR 4
392     X
393     X /* standard scanline ordering */
394     X#define PIXSTANDARD (YMAJOR|YDECR)
395     X#define PIXSTDFMT "-Y %d +X %d\n"
396     X
397     X /* structure for image dimensions */
398     Xtypedef struct {
399     X int or; /* orientation (from flags above) */
400     X int xr, yr; /* x and y resolution */
401     X} RESOLU;
402     X
403     X /* macros to get scanline length and number */
404     X#define scanlen(rs) ((rs)->or & YMAJOR ? (rs)->xr : (rs)->yr)
405     X#define numscans(rs) ((rs)->or & YMAJOR ? (rs)->yr : (rs)->xr)
406     X
407     X /* resolution string buffer and its size */
408     X#define RESOLU_BUFLEN 32
409     Xextern char resolu_buf[RESOLU_BUFLEN];
410     X
411     X /* macros for reading/writing resolution struct */
412     X#define fputsresolu(rs,fp) fputs(resolu2str(resolu_buf,rs),fp)
413     X#define fgetsresolu(rs,fp) str2resolu(rs, \
414     X fgets(resolu_buf,RESOLU_BUFLEN,fp))
415     X
416     X /* reading/writing of standard ordering */
417     X#define fprtresolu(sl,ns,fp) fprintf(fp,PIXSTDFMT,ns,sl)
418     X#define fscnresolu(sl,ns,fp) (fscanf(fp,PIXSTDFMT,ns,sl)==2)
419     X
420     Xextern char *resolu2str();
421     SHAR_EOF
422     fi
423     if test -f 'resolu.c'
424     then
425     echo shar: "will not over-write existing file 'resolu.c'"
426     else
427     sed 's/^X//' << \SHAR_EOF > 'resolu.c'
428     X/* Copyright (c) 1991 Regents of the University of California */
429     X
430     X#ifndef lint
431     Xstatic char SCCSid[] = "@(#)resolu.c 2.2 11/28/91 LBL";
432     X#endif
433     X
434     X/*
435     X * Read and write image resolutions.
436     X */
437     X
438     X#include <stdio.h>
439     X
440     X#include "resolu.h"
441     X
442     X
443     Xchar resolu_buf[RESOLU_BUFLEN]; /* resolution line buffer */
444     X
445     X
446     Xfputresolu(ord, sl, ns, fp) /* put out picture dimensions */
447     Xint ord; /* scanline ordering */
448     Xint sl, ns; /* scanline length and number */
449     XFILE *fp;
450     X{
451     X RESOLU rs;
452     X
453     X if ((rs.or = ord) & YMAJOR) {
454     X rs.xr = sl;
455     X rs.yr = ns;
456     X } else {
457     X rs.xr = ns;
458     X rs.yr = sl;
459     X }
460     X fputsresolu(&rs, fp);
461     X}
462     X
463     X
464     Xint
465     Xfgetresolu(sl, ns, fp) /* get picture dimensions */
466     Xint *sl, *ns; /* scanline length and number */
467     XFILE *fp;
468     X{
469     X RESOLU rs;
470     X
471     X if (!fgetsresolu(&rs, fp))
472     X return(-1);
473     X if (rs.or & YMAJOR) {
474     X *sl = rs.xr;
475     X *ns = rs.yr;
476     X } else {
477     X *sl = rs.yr;
478     X *ns = rs.xr;
479     X }
480     X return(rs.or);
481     X}
482     X
483     X
484     Xchar *
485     Xresolu2str(buf, rp) /* convert resolution struct to line */
486     Xchar *buf;
487     Xregister RESOLU *rp;
488     X{
489     X if (rp->or&YMAJOR)
490     X sprintf(buf, "%cY %d %cX %d\n",
491     X rp->or&YDECR ? '-' : '+', rp->yr,
492     X rp->or&XDECR ? '-' : '+', rp->xr);
493     X else
494     X sprintf(buf, "%cX %d %cY %d\n",
495     X rp->or&XDECR ? '-' : '+', rp->xr,
496     X rp->or&YDECR ? '-' : '+', rp->yr);
497     X return(buf);
498     X}
499     X
500     X
501     Xstr2resolu(rp, buf) /* convert resolution line to struct */
502     Xregister RESOLU *rp;
503     Xchar *buf;
504     X{
505     X register char *xndx, *yndx;
506     X register char *cp;
507     X
508     X if (buf == NULL)
509     X return(0);
510     X xndx = yndx = NULL;
511     X for (cp = buf; *cp; cp++)
512     X if (*cp == 'X')
513     X xndx = cp;
514     X else if (*cp == 'Y')
515     X yndx = cp;
516     X if (xndx == NULL || yndx == NULL)
517     X return(0);
518     X rp->or = 0;
519     X if (xndx > yndx) rp->or |= YMAJOR;
520     X if (xndx[-1] == '-') rp->or |= XDECR;
521     X if (yndx[-1] == '-') rp->or |= YDECR;
522     X if ((rp->xr = atoi(xndx+1)) <= 0)
523     X return(0);
524     X if ((rp->yr = atoi(yndx+1)) <= 0)
525     X return(0);
526     X return(1);
527     X}
528     SHAR_EOF
529     fi
530     if test -f 'header.c'
531     then
532     echo shar: "will not over-write existing file 'header.c'"
533     else
534     sed 's/^X//' << \SHAR_EOF > 'header.c'
535     X/* Copyright (c) 1994 Regents of the University of California */
536     X
537     X#ifndef lint
538     Xstatic char SCCSid[] = "@(#)header.c 2.4 2/27/94 LBL";
539     X#endif
540     X
541     X/*
542     X * header.c - routines for reading and writing information headers.
543     X *
544     X * 8/19/88
545     X *
546     X * newheader(t,fp) start new information header identified by string t
547     X * isheadid(s) returns true if s is a header id line
548     X * headidval(r,s) copy header identifier value in s to r
549     X * printargs(ac,av,fp) print an argument list to fp, followed by '\n'
550     X * isformat(s) returns true if s is of the form "FORMAT=*"
551     X * formatval(r,s) copy the format value in s to r
552     X * fputformat(s,fp) write "FORMAT=%s" to fp
553     X * getheader(fp,f,p) read header from fp, calling f(s,p) on each line
554     X * checkheader(i,p,o) check header format from i against p and copy to o
555     X *
556     X * To copy header from input to output, use getheader(fin, fputs, fout)
557     X */
558     X
559     X#include <stdio.h>
560     X#include <ctype.h>
561     X
562     X#define MAXLINE 512
563     X
564     X#ifndef BSD
565     X#define index strchr
566     X#endif
567     X
568     Xextern char *index();
569     X
570     Xchar HDRSTR[] = "#?"; /* information header magic number */
571     X
572     Xchar FMTSTR[] = "FORMAT="; /* format identifier */
573     X
574     X
575     Xnewheader(s, fp) /* identifying line of information header */
576     Xchar *s;
577     Xregister FILE *fp;
578     X{
579     X fputs(HDRSTR, fp);
580     X fputs(s, fp);
581     X putc('\n', fp);
582     X}
583     X
584     X
585     Xheadidval(r,s) /* get header id (return true if is id) */
586     Xregister char *r, *s;
587     X{
588     X register char *cp = HDRSTR;
589     X
590     X while (*cp) if (*cp++ != *s++) return(0);
591     X if (r == NULL) return(1);
592     X while (*s) *r++ = *s++;
593     X *r = '\0';
594     X return(1);
595     X}
596     X
597     X
598     Xisheadid(s) /* check to see if line is header id */
599     Xchar *s;
600     X{
601     X return(headidval(NULL, s));
602     X}
603     X
604     X
605     Xprintargs(ac, av, fp) /* print arguments to a file */
606     Xint ac;
607     Xchar **av;
608     Xregister FILE *fp;
609     X{
610     X int quote;
611     X
612     X while (ac-- > 0) {
613     X if (index(*av, ' ') != NULL) { /* quote it */
614     X if (index(*av, '\'') != NULL)
615     X quote = '"';
616     X else
617     X quote = '\'';
618     X putc(quote, fp);
619     X fputs(*av++, fp);
620     X putc(quote, fp);
621     X } else
622     X fputs(*av++, fp);
623     X putc(' ', fp);
624     X }
625     X putc('\n', fp);
626     X}
627     X
628     X
629     Xformatval(r, s) /* get format value (return true if format) */
630     Xregister char *r;
631     Xregister char *s;
632     X{
633     X register char *cp = FMTSTR;
634     X
635     X while (*cp) if (*cp++ != *s++) return(0);
636     X while (isspace(*s)) s++;
637     X if (!*s) return(0);
638     X if (r == NULL) return(1);
639     X while(*s) *r++ = *s++;
640     X while (isspace(r[-1])) r--;
641     X *r = '\0';
642     X return(1);
643     X}
644     X
645     X
646     Xisformat(s) /* is line a format line? */
647     Xchar *s;
648     X{
649     X return(formatval(NULL, s));
650     X}
651     X
652     X
653     Xfputformat(s, fp) /* put out a format value */
654     Xchar *s;
655     XFILE *fp;
656     X{
657     X fputs(FMTSTR, fp);
658     X fputs(s, fp);
659     X putc('\n', fp);
660     X}
661     X
662     X
663     Xgetheader(fp, f, p) /* get header from file */
664     XFILE *fp;
665     Xint (*f)();
666     Xchar *p;
667     X{
668     X char buf[MAXLINE];
669     X
670     X for ( ; ; ) {
671     X buf[MAXLINE-2] = '\n';
672     X if (fgets(buf, MAXLINE, fp) == NULL)
673     X return(-1);
674     X if (buf[0] == '\n')
675     X return(0);
676     X#ifdef MSDOS
677     X if (buf[0] == '\r' && buf[1] == '\n')
678     X return(0);
679     X#endif
680     X if (buf[MAXLINE-2] != '\n') {
681     X ungetc(buf[MAXLINE-2], fp); /* prevent false end */
682     X buf[MAXLINE-2] = '\0';
683     X }
684     X if (f != NULL)
685     X (*f)(buf, p);
686     X }
687     X}
688     X
689     X
690     Xstruct check {
691     X FILE *fp;
692     X char fs[64];
693     X};
694     X
695     X
696     Xstatic
697     Xmycheck(s, cp) /* check a header line for format info. */
698     Xchar *s;
699     Xregister struct check *cp;
700     X{
701     X if (!formatval(cp->fs, s) && cp->fp != NULL)
702     X fputs(s, cp->fp);
703     X}
704     X
705     X
706     X/*
707     X * Copymatch(pat,str) checks pat for wildcards, and
708     X * copies str into pat if there is a match (returning true).
709     X */
710     X
711     X#ifdef COPYMATCH
712     Xcopymatch(pat, str)
713     Xchar *pat, *str;
714     X{
715     X int docopy = 0;
716     X register char *p = pat, *s = str;
717     X
718     X do {
719     X switch (*p) {
720     X case '?': /* match any character */
721     X if (!*s++)
722     X return(0);
723     X docopy++;
724     X break;
725     X case '*': /* match any string */
726     X while (p[1] == '*') p++;
727     X do
728     X if ( (p[1]=='?' || p[1]==*s)
729     X && copymatch(p+1,s) ) {
730     X strcpy(pat, str);
731     X return(1);
732     X }
733     X while (*s++);
734     X return(0);
735     X case '\\': /* literal next */
736     X p++;
737     X /* fall through */
738     X default: /* normal character */
739     X if (*p != *s)
740     X return(0);
741     X s++;
742     X break;
743     X }
744     X } while (*p++);
745     X if (docopy)
746     X strcpy(pat, str);
747     X return(1);
748     X}
749     X#else
750     X#define copymatch(pat, s) (!strcmp(pat, s))
751     X#endif
752     X
753     X
754     X/*
755     X * Checkheader(fin,fmt,fout) returns a value of 1 if the input format
756     X * matches the specification in fmt, 0 if no input format was found,
757     X * and -1 if the input format does not match or there is an
758     X * error reading the header. If fmt is empty, then -1 is returned
759     X * if any input format is found (or there is an error), and 0 otherwise.
760     X * If fmt contains any '*' or '?' characters, then checkheader
761     X * does wildcard expansion and copies a matching result into fmt.
762     X * Be sure that fmt is big enough to hold the match in such cases!
763     X * The input header (minus any format lines) is copied to fout
764     X * if fout is not NULL.
765     X */
766     X
767     Xcheckheader(fin, fmt, fout)
768     XFILE *fin;
769     Xchar *fmt;
770     XFILE *fout;
771     X{
772     X struct check cdat;
773     X
774     X cdat.fp = fout;
775     X cdat.fs[0] = '\0';
776     X if (getheader(fin, mycheck, &cdat) < 0)
777     X return(-1);
778     X if (cdat.fs[0] != '\0')
779     X return(copymatch(fmt, cdat.fs) ? 1 : -1);
780     X return(0);
781     X}
782     SHAR_EOF
783     fi
784     if test -f 'color.c'
785     then
786     echo shar: "will not over-write existing file 'color.c'"
787     else
788     sed 's/^X//' << \SHAR_EOF > 'color.c'
789     X/* Copyright (c) 1991 Regents of the University of California */
790     X
791     X#ifndef lint
792     Xstatic char SCCSid[] = "@(#)color.c 2.8 3/26/94 LBL";
793     X#endif
794     X
795     X/*
796     X * color.c - routines for color calculations.
797     X *
798     X * 10/10/85
799     X */
800     X
801     X#include <stdio.h>
802     X
803     X#include <math.h>
804     X
805     X#include "color.h"
806     X
807     X#define MINELEN 8 /* minimum scanline length for encoding */
808     X#define MAXELEN 0x7fff /* maximum scanline length for encoding */
809     X#define MINRUN 4 /* minimum run length */
810     X
811     X
812     Xchar *
813     Xtempbuffer(len) /* get a temporary buffer */
814     Xunsigned len;
815     X{
816     X extern char *malloc(), *realloc();
817     X static char *tempbuf = NULL;
818     X static unsigned tempbuflen = 0;
819     X
820     X if (len > tempbuflen) {
821     X if (tempbuflen > 0)
822     X tempbuf = realloc(tempbuf, len);
823     X else
824     X tempbuf = malloc(len);
825     X tempbuflen = tempbuf==NULL ? 0 : len;
826     X }
827     X return(tempbuf);
828     X}
829     X
830     X
831     Xfwritecolrs(scanline, len, fp) /* write out a colr scanline */
832     Xregister COLR *scanline;
833     Xunsigned len;
834     Xregister FILE *fp;
835     X{
836     X register int i, j, beg, cnt;
837     X int c2;
838     X
839     X if (len < MINELEN | len > MAXELEN) /* OOBs, write out flat */
840     X return(fwrite((char *)scanline,sizeof(COLR),len,fp) - len);
841     X /* put magic header */
842     X putc(2, fp);
843     X putc(2, fp);
844     X putc(len>>8, fp);
845     X putc(len&255, fp);
846     X /* put components seperately */
847     X for (i = 0; i < 4; i++) {
848     X for (j = 0; j < len; j += cnt) { /* find next run */
849     X for (beg = j; beg < len; beg += cnt) {
850     X for (cnt = 1; cnt < 127 && beg+cnt < len &&
851     X scanline[beg+cnt][i] == scanline[beg][i]; cnt++)
852     X ;
853     X if (cnt >= MINRUN)
854     X break; /* long enough */
855     X }
856     X if (beg-j > 1 && beg-j < MINRUN) {
857     X c2 = j+1;
858     X while (scanline[c2++][i] == scanline[j][i])
859     X if (c2 == beg) { /* short run */
860     X putc(128+beg-j, fp);
861     X putc(scanline[j][i], fp);
862     X j = beg;
863     X break;
864     X }
865     X }
866     X while (j < beg) { /* write out non-run */
867     X if ((c2 = beg-j) > 128) c2 = 128;
868     X putc(c2, fp);
869     X while (c2--)
870     X putc(scanline[j++][i], fp);
871     X }
872     X if (cnt >= MINRUN) { /* write out run */
873     X putc(128+cnt, fp);
874     X putc(scanline[beg][i], fp);
875     X } else
876     X cnt = 0;
877     X }
878     X }
879     X return(ferror(fp) ? -1 : 0);
880     X}
881     X
882     X
883     Xfreadcolrs(scanline, len, fp) /* read in an encoded colr scanline */
884     Xregister COLR *scanline;
885     Xint len;
886     Xregister FILE *fp;
887     X{
888     X register int i, j;
889     X int code, val;
890     X /* determine scanline type */
891     X if (len < MINELEN | len > MAXELEN)
892     X return(oldreadcolrs(scanline, len, fp));
893     X if ((i = getc(fp)) == EOF)
894     X return(-1);
895     X if (i != 2) {
896     X ungetc(i, fp);
897     X return(oldreadcolrs(scanline, len, fp));
898     X }
899     X scanline[0][GRN] = getc(fp);
900     X scanline[0][BLU] = getc(fp);
901     X if ((i = getc(fp)) == EOF)
902     X return(-1);
903     X if (scanline[0][GRN] != 2 || scanline[0][BLU] & 128) {
904     X scanline[0][RED] = 2;
905     X scanline[0][EXP] = i;
906     X return(oldreadcolrs(scanline+1, len-1, fp));
907     X }
908     X if ((scanline[0][BLU]<<8 | i) != len)
909     X return(-1); /* length mismatch! */
910     X /* read each component */
911     X for (i = 0; i < 4; i++)
912     X for (j = 0; j < len; ) {
913     X if ((code = getc(fp)) == EOF)
914     X return(-1);
915     X if (code > 128) { /* run */
916     X code &= 127;
917     X val = getc(fp);
918     X while (code--)
919     X scanline[j++][i] = val;
920     X } else /* non-run */
921     X while (code--)
922     X scanline[j++][i] = getc(fp);
923     X }
924     X return(feof(fp) ? -1 : 0);
925     X}
926     X
927     X
928     Xoldreadcolrs(scanline, len, fp) /* read in an old colr scanline */
929     Xregister COLR *scanline;
930     Xint len;
931     Xregister FILE *fp;
932     X{
933     X int rshift;
934     X register int i;
935     X
936     X rshift = 0;
937     X
938     X while (len > 0) {
939     X scanline[0][RED] = getc(fp);
940     X scanline[0][GRN] = getc(fp);
941     X scanline[0][BLU] = getc(fp);
942     X scanline[0][EXP] = getc(fp);
943     X if (feof(fp) || ferror(fp))
944     X return(-1);
945     X if (scanline[0][RED] == 1 &&
946     X scanline[0][GRN] == 1 &&
947     X scanline[0][BLU] == 1) {
948     X for (i = scanline[0][EXP] << rshift; i > 0; i--) {
949     X copycolr(scanline[0], scanline[-1]);
950     X scanline++;
951     X len--;
952     X }
953     X rshift += 8;
954     X } else {
955     X scanline++;
956     X len--;
957     X rshift = 0;
958     X }
959     X }
960     X return(0);
961     X}
962     X
963     X
964     Xfwritescan(scanline, len, fp) /* write out a scanline */
965     Xregister COLOR *scanline;
966     Xint len;
967     XFILE *fp;
968     X{
969     X COLR *clrscan;
970     X int n;
971     X register COLR *sp;
972     X /* get scanline buffer */
973     X if ((sp = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL)
974     X return(-1);
975     X clrscan = sp;
976     X /* convert scanline */
977     X n = len;
978     X while (n-- > 0) {
979     X setcolr(sp[0], scanline[0][RED],
980     X scanline[0][GRN],
981     X scanline[0][BLU]);
982     X scanline++;
983     X sp++;
984     X }
985     X return(fwritecolrs(clrscan, len, fp));
986     X}
987     X
988     X
989     Xfreadscan(scanline, len, fp) /* read in a scanline */
990     Xregister COLOR *scanline;
991     Xint len;
992     XFILE *fp;
993     X{
994     X register COLR *clrscan;
995     X
996     X if ((clrscan = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL)
997     X return(-1);
998     X if (freadcolrs(clrscan, len, fp) < 0)
999     X return(-1);
1000     X /* convert scanline */
1001     X colr_color(scanline[0], clrscan[0]);
1002     X while (--len > 0) {
1003     X scanline++; clrscan++;
1004     X if (clrscan[0][RED] == clrscan[-1][RED] &&
1005     X clrscan[0][GRN] == clrscan[-1][GRN] &&
1006     X clrscan[0][BLU] == clrscan[-1][BLU] &&
1007     X clrscan[0][EXP] == clrscan[-1][EXP])
1008     X copycolor(scanline[0], scanline[-1]);
1009     X else
1010     X colr_color(scanline[0], clrscan[0]);
1011     X }
1012     X return(0);
1013     X}
1014     X
1015     X
1016     Xsetcolr(clr, r, g, b) /* assign a short color value */
1017     Xregister COLR clr;
1018     Xdouble r, g, b;
1019     X{
1020     X double d;
1021     X int e;
1022     X
1023     X d = r > g ? r : g;
1024     X if (b > d) d = b;
1025     X
1026     X if (d <= 1e-32) {
1027     X clr[RED] = clr[GRN] = clr[BLU] = 0;
1028     X clr[EXP] = 0;
1029     X return;
1030     X }
1031     X
1032     X d = frexp(d, &e) * 255.9999 / d;
1033     X
1034     X clr[RED] = r * d;
1035     X clr[GRN] = g * d;
1036     X clr[BLU] = b * d;
1037     X clr[EXP] = e + COLXS;
1038     X}
1039     X
1040     X
1041     Xcolr_color(col, clr) /* convert short to float color */
1042     Xregister COLOR col;
1043     Xregister COLR clr;
1044     X{
1045     X double f;
1046     X
1047     X if (clr[EXP] == 0)
1048     X col[RED] = col[GRN] = col[BLU] = 0.0;
1049     X else {
1050     X f = ldexp(1.0, (int)clr[EXP]-(COLXS+8));
1051     X col[RED] = (clr[RED] + 0.5)*f;
1052     X col[GRN] = (clr[GRN] + 0.5)*f;
1053     X col[BLU] = (clr[BLU] + 0.5)*f;
1054     X }
1055     X}
1056     X
1057     X
1058     Xbigdiff(c1, c2, md) /* c1 delta c2 > md? */
1059     Xregister COLOR c1, c2;
1060     Xdouble md;
1061     X{
1062     X register int i;
1063     X
1064     X for (i = 0; i < 3; i++)
1065     X if (colval(c1,i)-colval(c2,i) > md*colval(c2,i) ||
1066     X colval(c2,i)-colval(c1,i) > md*colval(c1,i))
1067     X return(1);
1068     X return(0);
1069     X}
1070     SHAR_EOF
1071     fi
1072     if test -f 'colrops.c'
1073     then
1074     echo shar: "will not over-write existing file 'colrops.c'"
1075     else
1076     sed 's/^X//' << \SHAR_EOF > 'colrops.c'
1077     X/* Copyright (c) 1992 Regents of the University of California */
1078     X
1079     X#ifndef lint
1080     Xstatic char SCCSid[] = "@(#)colrops.c 2.4 10/2/92 LBL";
1081     X#endif
1082     X
1083     X/*
1084     X * Integer operations on COLR scanlines
1085     X */
1086     X
1087     X#include "color.h"
1088     X
1089     X#define NULL 0
1090     X
1091     Xextern char *bmalloc();
1092     X
1093     X#define MAXGSHIFT 31 /* maximum shift for gamma table */
1094     X
1095     Xstatic BYTE *g_mant = NULL, *g_nexp = NULL;
1096     X
1097     Xstatic BYTE (*g_bval)[256] = NULL;
1098     X
1099     X#ifndef pow
1100     Xextern double pow();
1101     X#endif
1102     X
1103     X
1104     Xsetcolrcor(f, a2) /* set brightness correction */
1105     Xdouble (*f)();
1106     Xdouble a2;
1107     X{
1108     X double mult;
1109     X register int i, j;
1110     X /* allocate tables */
1111     X if (g_bval == NULL && (g_bval =
1112     X (BYTE (*)[256])bmalloc((MAXGSHIFT+1)*256)) == NULL)
1113     X return(-1);
1114     X /* compute colr -> gamb mapping */
1115     X mult = 1.0/256.0;
1116     X for (i = 0; i <= MAXGSHIFT; i++) {
1117     X for (j = 0; j < 256; j++)
1118     X g_bval[i][j] = 256.0 * (*f)((j+.5)*mult, a2);
1119     X mult *= 0.5;
1120     X }
1121     X return(0);
1122     X}
1123     X
1124     X
1125     Xsetcolrinv(f, a2) /* set inverse brightness correction */
1126     Xdouble (*f)();
1127     Xdouble a2;
1128     X{
1129     X double mult;
1130     X register int i, j;
1131     X /* allocate tables */
1132     X if (g_mant == NULL && (g_mant = (BYTE *)bmalloc(256)) == NULL)
1133     X return(-1);
1134     X if (g_nexp == NULL && (g_nexp = (BYTE *)bmalloc(256)) == NULL)
1135     X return(-1);
1136     X /* compute gamb -> colr mapping */
1137     X i = 0;
1138     X mult = 256.0;
1139     X for (j = 255; j > 0; j--) {
1140     X while ((g_mant[j] = mult * (*f)(j/256.0, a2)) < 128) {
1141     X i++;
1142     X mult *= 2.0;
1143     X }
1144     X g_nexp[j] = i;
1145     X }
1146     X g_mant[0] = 0;
1147     X g_nexp[0] = COLXS;
1148     X return(0);
1149     X}
1150     X
1151     X
1152     Xsetcolrgam(g) /* set gamma conversion */
1153     Xdouble g;
1154     X{
1155     X if (setcolrcor(pow, 1.0/g) < 0)
1156     X return(-1);
1157     X return(setcolrinv(pow, g));
1158     X}
1159     X
1160     X
1161     Xcolrs_gambs(scan, len) /* convert scanline of colrs to gamma bytes */
1162     Xregister COLR *scan;
1163     Xint len;
1164     X{
1165     X register int i, expo;
1166     X
1167     X if (g_bval == NULL)
1168     X return(-1);
1169     X while (len-- > 0) {
1170     X expo = scan[0][EXP] - COLXS;
1171     X if (expo < -MAXGSHIFT) {
1172     X if (expo < -MAXGSHIFT-8) {
1173     X scan[0][RED] =
1174     X scan[0][GRN] =
1175     X scan[0][BLU] = 0;
1176     X } else {
1177     X i = (-MAXGSHIFT-1) - expo;
1178     X scan[0][RED] =
1179     X g_bval[MAXGSHIFT][((scan[0][RED]>>i)+1)>>1];
1180     X scan[0][GRN] =
1181     X g_bval[MAXGSHIFT][((scan[0][GRN]>>i)+1)>>1];
1182     X scan[0][BLU] =
1183     X g_bval[MAXGSHIFT][((scan[0][BLU]>>i)+1)>>1];
1184     X }
1185     X } else if (expo > 0) {
1186     X if (expo > 8) {
1187     X scan[0][RED] =
1188     X scan[0][GRN] =
1189     X scan[0][BLU] = 255;
1190     X } else {
1191     X i = (scan[0][RED]<<1 | 1) << (expo-1);
1192     X scan[0][RED] = i > 255 ? 255 : g_bval[0][i];
1193     X i = (scan[0][GRN]<<1 | 1) << (expo-1);
1194     X scan[0][GRN] = i > 255 ? 255 : g_bval[0][i];
1195     X i = (scan[0][BLU]<<1 | 1) << (expo-1);
1196     X scan[0][BLU] = i > 255 ? 255 : g_bval[0][i];
1197     X }
1198     X } else {
1199     X scan[0][RED] = g_bval[-expo][scan[0][RED]];
1200     X scan[0][GRN] = g_bval[-expo][scan[0][GRN]];
1201     X scan[0][BLU] = g_bval[-expo][scan[0][BLU]];
1202     X }
1203     X scan[0][EXP] = COLXS;
1204     X scan++;
1205     X }
1206     X return(0);
1207     X}
1208     X
1209     X
1210     Xgambs_colrs(scan, len) /* convert gamma bytes to colr scanline */
1211     Xregister COLR *scan;
1212     Xint len;
1213     X{
1214     X register int nexpo;
1215     X
1216     X if (g_mant == NULL | g_nexp == NULL)
1217     X return(-1);
1218     X while (len-- > 0) {
1219     X nexpo = g_nexp[scan[0][RED]];
1220     X if (g_nexp[scan[0][GRN]] < nexpo)
1221     X nexpo = g_nexp[scan[0][GRN]];
1222     X if (g_nexp[scan[0][BLU]] < nexpo)
1223     X nexpo = g_nexp[scan[0][BLU]];
1224     X if (nexpo < g_nexp[scan[0][RED]])
1225     X scan[0][RED] = g_mant[scan[0][RED]]
1226     X >> (g_nexp[scan[0][RED]]-nexpo);
1227     X else
1228     X scan[0][RED] = g_mant[scan[0][RED]];
1229     X if (nexpo < g_nexp[scan[0][GRN]])
1230     X scan[0][GRN] = g_mant[scan[0][GRN]]
1231     X >> (g_nexp[scan[0][GRN]]-nexpo);
1232     X else
1233     X scan[0][GRN] = g_mant[scan[0][GRN]];
1234     X if (nexpo < g_nexp[scan[0][BLU]])
1235     X scan[0][BLU] = g_mant[scan[0][BLU]]
1236     X >> (g_nexp[scan[0][BLU]]-nexpo);
1237     X else
1238     X scan[0][BLU] = g_mant[scan[0][BLU]];
1239     X scan[0][EXP] = COLXS - nexpo;
1240     X scan++;
1241     X }
1242     X return(0);
1243     X}
1244     X
1245     X
1246     Xshiftcolrs(scan, len, adjust) /* shift a scanline of colors by 2^adjust */
1247     Xregister COLR *scan;
1248     Xregister int len;
1249     Xregister int adjust;
1250     X{
1251     X int minexp;
1252     X
1253     X if (adjust == 0)
1254     X return;
1255     X minexp = adjust < 0 ? -adjust : 0;
1256     X while (len-- > 0) {
1257     X if (scan[0][EXP] <= minexp)
1258     X scan[0][RED] = scan[0][GRN] = scan[0][BLU] =
1259     X scan[0][EXP] = 0;
1260     X else
1261     X scan[0][EXP] += adjust;
1262     X scan++;
1263     X }
1264     X}
1265     X
1266     X
1267     Xnormcolrs(scan, len, adjust) /* normalize a scanline of colrs */
1268     Xregister COLR *scan;
1269     Xint len;
1270     Xint adjust;
1271     X{
1272     X register int c;
1273     X register int shift;
1274     X
1275     X while (len-- > 0) {
1276     X shift = scan[0][EXP] + adjust - COLXS;
1277     X if (shift > 0) {
1278     X if (shift > 8) {
1279     X scan[0][RED] =
1280     X scan[0][GRN] =
1281     X scan[0][BLU] = 255;
1282     X } else {
1283     X shift--;
1284     X c = (scan[0][RED]<<1 | 1) << shift;
1285     X scan[0][RED] = c > 255 ? 255 : c;
1286     X c = (scan[0][GRN]<<1 | 1) << shift;
1287     X scan[0][GRN] = c > 255 ? 255 : c;
1288     X c = (scan[0][BLU]<<1 | 1) << shift;
1289     X scan[0][BLU] = c > 255 ? 255 : c;
1290     X }
1291     X } else if (shift < 0) {
1292     X if (shift < -8) {
1293     X scan[0][RED] =
1294     X scan[0][GRN] =
1295     X scan[0][BLU] = 0;
1296     X } else {
1297     X shift = -1-shift;
1298     X scan[0][RED] = ((scan[0][RED]>>shift)+1)>>1;
1299     X scan[0][GRN] = ((scan[0][GRN]>>shift)+1)>>1;
1300     X scan[0][BLU] = ((scan[0][BLU]>>shift)+1)>>1;
1301     X }
1302     X }
1303     X scan[0][EXP] = COLXS - adjust;
1304     X scan++;
1305     X }
1306     X}
1307     SHAR_EOF
1308     fi
1309     exit 0
1310     # End of shell archive