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

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