ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/color.c
Revision: 2.23
Committed: Sat Dec 3 21:37:26 2022 UTC (17 months, 2 weeks ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.22: +31 -3 lines
Log Message:
docs: Randolph Fritz added some useful comments describing encoding

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: color.c,v 2.22 2022/03/05 17:18:02 greg Exp $";
3 #endif
4 /*
5 * color.c - routines for color calculations.
6 *
7 * Externals declared in color.h
8 */
9
10 #include "copyright.h"
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <math.h>
15 #include "color.h"
16
17 #ifdef getc_unlocked /* avoid horrendous overhead of flockfile */
18 #undef getc
19 #undef putc
20 #undef ferror
21 #define getc getc_unlocked
22 #define putc putc_unlocked
23 #define ferror ferror_unlocked
24 #endif
25
26 #define MINELEN 8 /* minimum scanline length for encoding */
27 #define MAXELEN 0x7fff /* maximum scanline length for encoding */
28 #define MINRUN 4 /* minimum run length */
29
30
31 void *
32 tempbuffer( /* get a temporary buffer */
33 unsigned int len
34 )
35 {
36 static void *tempbuf = NULL;
37 static unsigned int tempbuflen = 0;
38
39 if (!len) { /* call to free */
40 if (tempbuflen) {
41 free(tempbuf);
42 tempbuf = NULL;
43 tempbuflen = 0;
44 }
45 return(NULL);
46 }
47 if (len <= tempbuflen) /* big enough already? */
48 return(tempbuf);
49 /* else free & reallocate */
50 if (tempbuflen)
51 free(tempbuf);
52 tempbuf = malloc(len);
53 tempbuflen = len*(tempbuf != NULL);
54 return(tempbuf);
55 }
56
57
58 int
59 fwritecolrs( /* write out a colr scanline */
60 COLR *scanline,
61 int len,
62 FILE *fp
63 )
64 {
65 int i, j, beg, cnt = 1;
66 int c2;
67
68 if ((len < MINELEN) | (len > MAXELEN)) /* OOBs, write out flat */
69 return(fwrite((char *)scanline,sizeof(COLR),len,fp) - len);
70 /* put magic header */
71 putc(2, fp);
72 putc(2, fp);
73 putc(len>>8, fp);
74 putc(len&0xff, fp);
75 /* put components seperately */
76 for (i = 0; i < 4; i++) {
77 for (j = 0; j < len; j += cnt) { /* find next run */
78 for (beg = j; beg < len; beg += cnt) {
79 for (cnt = 1; (cnt < 127) & (beg+cnt < len) &&
80 scanline[beg+cnt][i] == scanline[beg][i]; cnt++)
81 ;
82 if (cnt >= MINRUN)
83 break; /* long enough */
84 }
85 if ((beg-j > 1) & (beg-j < MINRUN)) {
86 c2 = j+1;
87 while (scanline[c2++][i] == scanline[j][i])
88 if (c2 == beg) { /* short run */
89 putc(128+beg-j, fp);
90 putc(scanline[j][i], fp);
91 j = beg;
92 break;
93 }
94 }
95 while (j < beg) { /* write out non-run */
96 if ((c2 = beg-j) > 128) c2 = 128;
97 putc(c2, fp);
98 while (c2--)
99 putc(scanline[j++][i], fp);
100 }
101 if (cnt >= MINRUN) { /* write out run */
102 putc(128+cnt, fp);
103 putc(scanline[beg][i], fp);
104 } else
105 cnt = 0;
106 }
107 }
108 return(ferror(fp) ? -1 : 0);
109 }
110
111 /*
112 * An old-format scanline is either a stream of valid RGBE or XYZE real
113 * pixels or at least one real pixel followed by some number of
114 * invalid real pixels of the form (1,1,1,n), where n is a count.
115 * These can themselves be repeated to create a multibyte repeat
116 * count, with the least significant byte first (little-endian order.)
117 * Repeat counts are limited by the size of an int; if a repetition
118 * leads to an overrun, the rest of the the repetition will be
119 * silently ignored.
120 */
121 static int
122 oldreadcolrs( /* read in an old-style colr scanline */
123 COLR *scanline,
124 int len,
125 FILE *fp
126 )
127 {
128 int rshift = 0;
129 int i;
130
131 while (len > 0) {
132 scanline[0][RED] = getc(fp);
133 scanline[0][GRN] = getc(fp);
134 scanline[0][BLU] = getc(fp);
135 scanline[0][EXP] = i = getc(fp);
136 if (i == EOF)
137 return(-1);
138 if (scanline[0][GRN] == 1 &&
139 (scanline[0][RED] == 1) &
140 (scanline[0][BLU] == 1)) {
141 i = scanline[0][EXP] << rshift;
142 while (i--) {
143 copycolr(scanline[0], scanline[-1]);
144 if (--len <= 0)
145 return(0);
146 scanline++;
147 }
148 rshift += 8;
149 } else {
150 scanline++;
151 len--;
152 rshift = 0;
153 }
154 }
155 return(0);
156 }
157
158 /*
159 * There are two scanline formats: old and new. The old format
160 * compresses runs of RGBE or XYZE four-byte real pixels; the new
161 * format breaks the pixels into R, G, B, and E lines (or XYZE lines)
162 * which are individually run-length encoded.
163 *
164 * An old-format scanline always begins with a valid real pixel; at
165 * least one of the RGB (or XYZ) values will have its high-order bit
166 * set. A new-format scanline begins with four bytes which are not a
167 * valid real pixel: (2, 2, lenhigh, lenlow) where lenhigh is always
168 * less than 128 and hence never has a high-order bit set.
169 *
170 * A new-format scanline is broken into its RGBE or XYZE components.
171 * Each is output and run-length encoded separately so that a scanline
172 * is broken into four records. In turn, each record is organized
173 * into chunks of up to 128 characters, which begin with a count byte.
174 * If the count byte is greater than 128, the following data byte is
175 * repeated (count-128) times. If not, the count byte is followed by
176 * that many data bytes.
177 */
178 int
179 freadcolrs( /* read in an encoded colr scanline */
180 COLR *scanline,
181 int len,
182 FILE *fp
183 )
184 {
185 int i, j;
186 int code, val;
187 /* determine scanline type */
188 if ((len < MINELEN) | (len > MAXELEN))
189 return(oldreadcolrs(scanline, len, fp));
190 if ((i = getc(fp)) == EOF)
191 return(-1);
192 if (i != 2) {
193 ungetc(i, fp);
194 return(oldreadcolrs(scanline, len, fp));
195 }
196 scanline[0][GRN] = getc(fp);
197 scanline[0][BLU] = getc(fp);
198 if ((i = getc(fp)) == EOF)
199 return(-1);
200 if ((scanline[0][GRN] != 2) | ((scanline[0][BLU] & 0x80) != 0)) {
201 scanline[0][RED] = 2;
202 scanline[0][EXP] = i;
203 return(oldreadcolrs(scanline+1, len-1, fp));
204 }
205 if ((scanline[0][BLU]<<8 | i) != len)
206 return(-1); /* length mismatch! */
207 /* read each component */
208 for (i = 0; i < 4; i++)
209 for (j = 0; j < len; ) {
210 if ((code = getc(fp)) == EOF)
211 return(-1);
212 if (code > 128) { /* run */
213 code &= 127;
214 if ((val = getc(fp)) == EOF)
215 return -1;
216 if (j + code > len)
217 return -1; /* overrun */
218 while (code--)
219 scanline[j++][i] = val;
220 } else { /* non-run */
221 if (j + code > len)
222 return -1; /* overrun */
223 while (code--) {
224 if ((val = getc(fp)) == EOF)
225 return -1;
226 scanline[j++][i] = val;
227 }
228 }
229 }
230 return(0);
231 }
232
233
234 int
235 fwritescan( /* write out a scanline */
236 COLOR *scanline,
237 int len,
238 FILE *fp
239 )
240 {
241 COLR *clrscan;
242 int n;
243 COLR *sp;
244 /* get scanline buffer */
245 if ((sp = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL)
246 return(-1);
247 clrscan = sp;
248 /* convert scanline */
249 n = len;
250 while (n-- > 0) {
251 setcolr(sp[0], scanline[0][RED],
252 scanline[0][GRN],
253 scanline[0][BLU]);
254 scanline++;
255 sp++;
256 }
257 return(fwritecolrs(clrscan, len, fp));
258 }
259
260
261 int
262 freadscan( /* read in a scanline */
263 COLOR *scanline,
264 int len,
265 FILE *fp
266 )
267 {
268 COLR *clrscan;
269
270 if ((clrscan = (COLR *)tempbuffer(len*sizeof(COLR))) == NULL)
271 return(-1);
272 if (freadcolrs(clrscan, len, fp) < 0)
273 return(-1);
274 /* convert scanline */
275 colr_color(scanline[0], clrscan[0]);
276 while (--len > 0) {
277 scanline++; clrscan++;
278 if (clrscan[0][GRN] == clrscan[-1][GRN] &&
279 (clrscan[0][RED] == clrscan[-1][RED]) &
280 (clrscan[0][BLU] == clrscan[-1][BLU]) &
281 (clrscan[0][EXP] == clrscan[-1][EXP]))
282 copycolor(scanline[0], scanline[-1]);
283 else
284 colr_color(scanline[0], clrscan[0]);
285 }
286 return(0);
287 }
288
289
290 void
291 setcolr( /* assign a short color value */
292 COLR clr,
293 double r,
294 double g,
295 double b
296 )
297 {
298 double d;
299 int e;
300
301 d = r > g ? r : g;
302 if (b > d) d = b;
303
304 if (d <= 1e-32) {
305 clr[RED] = clr[GRN] = clr[BLU] = 0;
306 clr[EXP] = 0;
307 return;
308 }
309
310 d = frexp(d, &e) * 256.0 / d;
311
312 if (r > 0.0)
313 clr[RED] = r * d;
314 else
315 clr[RED] = 0;
316 if (g > 0.0)
317 clr[GRN] = g * d;
318 else
319 clr[GRN] = 0;
320 if (b > 0.0)
321 clr[BLU] = b * d;
322 else
323 clr[BLU] = 0;
324
325 clr[EXP] = e + COLXS;
326 }
327
328
329 void
330 colr_color( /* convert short to float color */
331 COLOR col,
332 COLR clr
333 )
334 {
335 double f;
336
337 if (clr[EXP] == 0)
338 col[RED] = col[GRN] = col[BLU] = 0.0;
339 else {
340 f = ldexp(1.0, (int)clr[EXP]-(COLXS+8));
341 col[RED] = (clr[RED] + 0.5)*f;
342 col[GRN] = (clr[GRN] + 0.5)*f;
343 col[BLU] = (clr[BLU] + 0.5)*f;
344 }
345 }
346
347
348 int
349 bigdiff( /* c1 delta c2 > md? */
350 COLOR c1,
351 COLOR c2,
352 double md
353 )
354 {
355 int i;
356
357 for (i = 0; i < 3; i++)
358 if (colval(c1,i)-colval(c2,i) > md*colval(c2,i) ||
359 colval(c2,i)-colval(c1,i) > md*colval(c1,i))
360 return(1);
361 return(0);
362 }