ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/ra_ppm.c
Revision: 2.19
Committed: Sat Jun 7 05:09:46 2025 UTC (2 weeks, 1 day ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.18: +1 -2 lines
Log Message:
refactor: Put some declarations into "paths.h" and included in "platform.h"

File Contents

# User Rev Content
1 greg 1.1 #ifndef lint
2 greg 2.19 static const char RCSid[] = "$Id: ra_ppm.c,v 2.18 2025/06/06 19:11:21 greg Exp $";
3 greg 1.1 #endif
4     /*
5     * program to convert between RADIANCE and Poskanzer Pixmaps
6     */
7    
8 greg 2.4 #include <math.h>
9 greg 1.1 #include <ctype.h>
10 schorsch 2.10 #include "platform.h"
11 greg 2.16 #include "rtio.h"
12 greg 1.1 #include "color.h"
13 greg 1.2 #include "resolu.h"
14    
15 gwlarson 2.8 #define fltv(i) (((i)+.5)/(maxval+1.))
16 greg 1.1 int bradj = 0; /* brightness adjustment */
17 gwlarson 2.8 double gamcor = 2.2; /* gamma correction value */
18 greg 1.1 int maxval = 255; /* maximum primary value */
19 schorsch 2.12 int xmax, ymax;
20 greg 1.1
21 schorsch 2.12 typedef int colrscanf_t(COLR *scan, int len, FILE *fp);
22     typedef int colorscanf_t(COLOR *scan, int len, FILE *fp);
23 greg 1.1
24 schorsch 2.12 static colrscanf_t agryscan, bgryscan, aclrscan, bclrscan;
25     static void ppm2ra(colrscanf_t *getscan);
26     static void ra2ppm(int binary, int grey);
27    
28     static colorscanf_t agryscan2, bgryscan2, aclrscan2, bclrscan2;
29     static void ppm2ra2(colorscanf_t *getscan);
30     static void ra2ppm2(int binary, int grey);
31    
32     static int normval(unsigned int v);
33     static unsigned int scanint(FILE *fp);
34     static unsigned int intv(double v);
35     static unsigned int getby2(FILE *fp);
36     static void putby2(unsigned int w, FILE *fp);
37     static void quiterr(char *err);
38 greg 1.1
39    
40 schorsch 2.12 int
41     main(
42     int argc,
43     char *argv[]
44     )
45 greg 1.1 {
46 greg 2.3 char inpbuf[2];
47 gwlarson 2.8 int gryflag = 0;
48 greg 1.1 int binflag = 1;
49     int reverse = 0;
50     int ptype;
51     int i;
52    
53 greg 2.18 fixargv0(argv[0]);
54 greg 1.1
55     for (i = 1; i < argc; i++)
56     if (argv[i][0] == '-')
57     switch (argv[i][1]) {
58 gwlarson 2.8 case 's':
59     maxval = atoi(argv[++i]) & 0xffff;
60     break;
61     case 'b':
62     gryflag = 1;
63     break;
64 greg 1.1 case 'g':
65 greg 2.5 gamcor = atof(argv[++i]);
66 greg 1.1 break;
67     case 'e':
68     if (argv[i+1][0] != '+' && argv[i+1][0] != '-')
69     goto userr;
70     bradj = atoi(argv[++i]);
71     break;
72     case 'a':
73     binflag = 0;
74     break;
75     case 'r':
76     reverse = !reverse;
77     break;
78     default:
79     goto userr;
80     }
81     else
82     break;
83    
84     if (i < argc-2)
85     goto userr;
86     if (i <= argc-1 && freopen(argv[i], "r", stdin) == NULL) {
87     fprintf(stderr, "%s: can't open input \"%s\"\n",
88     progname, argv[i]);
89     exit(1);
90     }
91     if (i == argc-2 && freopen(argv[i+1], "w", stdout) == NULL) {
92 greg 2.6 fprintf(stderr, "%s: can't open output \"%s\"\n",
93 greg 1.1 progname, argv[i+1]);
94     exit(1);
95     }
96 gwlarson 2.8 if (maxval < 256)
97     setcolrgam(gamcor);
98 greg 1.1 if (reverse) {
99     /* get header */
100 greg 2.3 if (read(fileno(stdin), inpbuf, 2) != 2 || inpbuf[0] != 'P')
101 greg 1.1 quiterr("input not a Poskanzer Pixmap");
102 greg 2.3 ptype = inpbuf[1];
103 schorsch 2.15 #if defined(_WIN32) || defined(_WIN64)
104 greg 2.3 if (ptype > 4)
105 schorsch 2.10 SET_FILE_BINARY(stdin);
106     SET_FILE_BINARY(stdout);
107 greg 2.3 #endif
108 greg 1.1 xmax = scanint(stdin);
109     ymax = scanint(stdin);
110     maxval = scanint(stdin);
111     /* put header */
112 greg 2.7 newheader("RADIANCE", stdout);
113 greg 1.1 printargs(i, argv, stdout);
114     fputformat(COLRFMT, stdout);
115     putchar('\n');
116 greg 1.2 fprtresolu(xmax, ymax, stdout);
117 greg 1.1 /* convert file */
118 gwlarson 2.8 if (maxval >= 256)
119     switch (ptype) {
120     case '2':
121     ppm2ra2(agryscan2);
122     break;
123     case '5':
124     ppm2ra2(bgryscan2);
125     break;
126     case '3':
127     ppm2ra2(aclrscan2);
128     break;
129     case '6':
130     ppm2ra2(bclrscan2);
131     break;
132     default:
133     quiterr("unsupported Pixmap type");
134     }
135     else
136     switch (ptype) {
137     case '2':
138     ppm2ra(agryscan);
139     break;
140     case '5':
141     ppm2ra(bgryscan);
142     break;
143     case '3':
144     ppm2ra(aclrscan);
145     break;
146     case '6':
147     ppm2ra(bclrscan);
148     break;
149     default:
150     quiterr("unsupported Pixmap type");
151     }
152 greg 1.1 } else {
153 schorsch 2.15 #if defined(_WIN32) || defined(_WIN64)
154 schorsch 2.10 SET_FILE_BINARY(stdin);
155 greg 2.3 if (binflag)
156 schorsch 2.10 SET_FILE_BINARY(stdout);
157 greg 2.3 #endif
158 greg 1.1 /* get header info. */
159     if (checkheader(stdin, COLRFMT, NULL) < 0 ||
160 greg 1.2 fgetresolu(&xmax, &ymax, stdin) < 0)
161 greg 1.1 quiterr("bad picture format");
162     /* write PPM header */
163 gwlarson 2.8 printf("P%1d\n%d %d\n%u\n", (gryflag?2:3)+(binflag?3:0),
164 greg 1.1 xmax, ymax, maxval);
165     /* convert file */
166 gwlarson 2.8 if (maxval >= 256)
167     ra2ppm2(binflag, gryflag);
168     else
169     ra2ppm(binflag, gryflag);
170 greg 1.1 }
171     exit(0);
172     userr:
173     fprintf(stderr,
174 gwlarson 2.8 "Usage: %s [-r][-a][-b][-s maxv][-g gamma][-e +/-stops] [input [output]]\n",
175 greg 1.1 progname);
176     exit(1);
177     }
178    
179    
180 schorsch 2.12 static void
181     quiterr( /* print message and exit */
182     char *err
183     )
184 greg 1.1 {
185     if (err != NULL) {
186     fprintf(stderr, "%s: %s\n", progname, err);
187     exit(1);
188     }
189     exit(0);
190     }
191    
192    
193 schorsch 2.12 static void
194     ppm2ra( /* convert 1-byte Pixmap to Radiance picture */
195     colrscanf_t *getscan
196     )
197 greg 1.1 {
198     COLR *scanout;
199     int y;
200     /* allocate scanline */
201     scanout = (COLR *)malloc(xmax*sizeof(COLR));
202     if (scanout == NULL)
203     quiterr("out of memory in ppm2ra");
204     /* convert image */
205     for (y = ymax-1; y >= 0; y--) {
206     if ((*getscan)(scanout, xmax, stdin) < 0)
207     quiterr("error reading Pixmap");
208     gambs_colrs(scanout, xmax);
209     if (bradj)
210     shiftcolrs(scanout, xmax, bradj);
211     if (fwritecolrs(scanout, xmax, stdout) < 0)
212     quiterr("error writing Radiance picture");
213     }
214     /* free scanline */
215 greg 2.9 free((void *)scanout);
216 greg 1.1 }
217    
218    
219 schorsch 2.12 static void
220 greg 2.13 ra2ppm( /* convert Radiance picture to 1-byte/sample Pixmap */
221 schorsch 2.12 int binary,
222     int grey
223     )
224 greg 1.1 {
225     COLR *scanin;
226     register int x;
227     int y;
228     /* allocate scanline */
229     scanin = (COLR *)malloc(xmax*sizeof(COLR));
230     if (scanin == NULL)
231 gwlarson 2.8 quiterr("out of memory in ra2ppm");
232 greg 1.1 /* convert image */
233     for (y = ymax-1; y >= 0; y--) {
234     if (freadcolrs(scanin, xmax, stdin) < 0)
235     quiterr("error reading Radiance picture");
236     if (bradj)
237     shiftcolrs(scanin, xmax, bradj);
238 gwlarson 2.8 for (x = grey?xmax:0; x--; )
239     scanin[x][GRN] = normbright(scanin[x]);
240 greg 1.1 colrs_gambs(scanin, xmax);
241 gwlarson 2.8 if (grey)
242     if (binary)
243     for (x = 0; x < xmax; x++)
244     putc(scanin[x][GRN], stdout);
245     else
246     for (x = 0; x < xmax; x++)
247     printf("%d\n", scanin[x][GRN]);
248     else
249     if (binary)
250     for (x = 0; x < xmax; x++) {
251     putc(scanin[x][RED], stdout);
252     putc(scanin[x][GRN], stdout);
253     putc(scanin[x][BLU], stdout);
254     }
255     else
256     for (x = 0; x < xmax; x++)
257     printf("%d %d %d\n", scanin[x][RED],
258     scanin[x][GRN],
259     scanin[x][BLU]);
260     if (ferror(stdout))
261     quiterr("error writing Pixmap");
262     }
263     /* free scanline */
264 greg 2.9 free((void *)scanin);
265 gwlarson 2.8 }
266    
267    
268 schorsch 2.12 static void
269     ppm2ra2( /* convert 2-byte Pixmap to Radiance picture */
270     colorscanf_t *getscan
271     )
272 gwlarson 2.8 {
273     COLOR *scanout;
274     double mult;
275     int y;
276     register int x;
277     /* allocate scanline */
278     scanout = (COLOR *)malloc(xmax*sizeof(COLOR));
279     if (scanout == NULL)
280     quiterr("out of memory in ppm2ra2");
281     if (bradj)
282     mult = pow(2., (double)bradj);
283     /* convert image */
284     for (y = ymax-1; y >= 0; y--) {
285     if ((*getscan)(scanout, xmax, stdin) < 0)
286     quiterr("error reading Pixmap");
287 schorsch 2.11 for (x = (gamcor>1.01)|(gamcor<0.99)?xmax:0; x--; ) {
288 gwlarson 2.8 colval(scanout[x],RED) =
289     pow(colval(scanout[x],RED), gamcor);
290     colval(scanout[x],GRN) =
291     pow(colval(scanout[x],GRN), gamcor);
292     colval(scanout[x],BLU) =
293     pow(colval(scanout[x],BLU), gamcor);
294     }
295     for (x = bradj?xmax:0; x--; )
296     scalecolor(scanout[x], mult);
297     if (fwritescan(scanout, xmax, stdout) < 0)
298     quiterr("error writing Radiance picture");
299     }
300     /* free scanline */
301 greg 2.9 free((void *)scanout);
302 gwlarson 2.8 }
303    
304    
305 schorsch 2.12 static void
306     ra2ppm2( /* convert Radiance picture to Pixmap (2-byte) */
307     int binary,
308     int grey
309     )
310 gwlarson 2.8 {
311     COLOR *scanin;
312     double mult, d;
313     register int x;
314     int y;
315     /* allocate scanline */
316     scanin = (COLOR *)malloc(xmax*sizeof(COLOR));
317     if (scanin == NULL)
318     quiterr("out of memory in ra2ppm2");
319     if (bradj)
320     mult = pow(2., (double)bradj);
321     /* convert image */
322     for (y = ymax-1; y >= 0; y--) {
323     if (freadscan(scanin, xmax, stdin) < 0)
324     quiterr("error reading Radiance picture");
325     for (x = bradj?xmax:0; x--; )
326     scalecolor(scanin[x], mult);
327     for (x = grey?xmax:0; x--; )
328     colval(scanin[x],GRN) = bright(scanin[x]);
329     d = 1./gamcor;
330 schorsch 2.11 for (x = (d>1.01)|(d<0.99)?xmax:0; x--; ) {
331 gwlarson 2.8 colval(scanin[x],GRN) = pow(colval(scanin[x],GRN), d);
332     if (!grey) {
333     colval(scanin[x],RED) =
334     pow(colval(scanin[x],RED), d);
335     colval(scanin[x],BLU) =
336     pow(colval(scanin[x],BLU), d);
337 greg 1.1 }
338 gwlarson 2.8 }
339     if (grey)
340     if (binary)
341     for (x = 0; x < xmax; x++)
342     putby2(intv(colval(scanin[x],GRN)),
343     stdout);
344     else
345     for (x = 0; x < xmax; x++)
346     printf("%u\n",
347     intv(colval(scanin[x],GRN)));
348 greg 1.1 else
349 gwlarson 2.8 if (binary)
350     for (x = 0; x < xmax; x++) {
351     putby2(intv(colval(scanin[x],RED)),
352     stdout);
353     putby2(intv(colval(scanin[x],GRN)),
354     stdout);
355     putby2(intv(colval(scanin[x],BLU)),
356     stdout);
357     }
358     else
359     for (x = 0; x < xmax; x++)
360     printf("%u %u %u\n",
361     intv(colval(scanin[x],RED)),
362     intv(colval(scanin[x],GRN)),
363     intv(colval(scanin[x],BLU)));
364 greg 1.1 if (ferror(stdout))
365     quiterr("error writing Pixmap");
366     }
367     /* free scanline */
368 greg 2.9 free((void *)scanin);
369 greg 1.1 }
370    
371    
372 schorsch 2.12 static int
373     agryscan( /* get an ASCII greyscale scanline */
374     register COLR *scan,
375     register int len,
376     FILE *fp
377     )
378 greg 1.1 {
379     while (len-- > 0) {
380     scan[0][RED] =
381     scan[0][GRN] =
382     scan[0][BLU] = normval(scanint(fp));
383     scan++;
384     }
385     return(0);
386     }
387    
388    
389 schorsch 2.12 static int
390     bgryscan( /* get a binary greyscale scanline */
391     register COLR *scan,
392     int len,
393     register FILE *fp
394     )
395 greg 1.1 {
396     register int c;
397    
398     while (len-- > 0) {
399     if ((c = getc(fp)) == EOF)
400     return(-1);
401     if (maxval != 255)
402     c = normval(c);
403     scan[0][RED] =
404     scan[0][GRN] =
405     scan[0][BLU] = c;
406     scan++;
407     }
408     return(0);
409     }
410    
411    
412 schorsch 2.12 static int
413     aclrscan( /* get an ASCII color scanline */
414     register COLR *scan,
415     register int len,
416     FILE *fp
417     )
418 greg 1.1 {
419     while (len-- > 0) {
420     scan[0][RED] = normval(scanint(fp));
421     scan[0][GRN] = normval(scanint(fp));
422     scan[0][BLU] = normval(scanint(fp));
423     scan++;
424     }
425     return(0);
426     }
427    
428    
429 schorsch 2.12 static int
430     bclrscan( /* get a binary color scanline */
431     register COLR *scan,
432     int len,
433     register FILE *fp
434     )
435 greg 1.1 {
436     int r, g, b;
437    
438     while (len-- > 0) {
439     r = getc(fp);
440     g = getc(fp);
441     if ((b = getc(fp)) == EOF)
442     return(-1);
443     if (maxval == 255) {
444     scan[0][RED] = r;
445     scan[0][GRN] = g;
446     scan[0][BLU] = b;
447     } else {
448     scan[0][RED] = normval(r);
449     scan[0][GRN] = normval(g);
450     scan[0][BLU] = normval(b);
451     }
452     scan++;
453     }
454     return(0);
455     }
456    
457    
458 schorsch 2.12 static int
459     agryscan2( /* get an ASCII greyscale scanline */
460     register COLOR *scan,
461     register int len,
462     FILE *fp
463     )
464 gwlarson 2.8 {
465     while (len-- > 0) {
466     colval(scan[0],RED) =
467     colval(scan[0],GRN) =
468     colval(scan[0],BLU) = fltv(scanint(fp));
469     scan++;
470     }
471     return(0);
472     }
473    
474    
475 schorsch 2.12 static int
476     bgryscan2( /* get a binary greyscale scanline */
477     register COLOR *scan,
478     int len,
479     register FILE *fp
480     )
481 gwlarson 2.8 {
482     register int c;
483    
484     while (len-- > 0) {
485     if ((c = getby2(fp)) == EOF)
486     return(-1);
487     colval(scan[0],RED) =
488     colval(scan[0],GRN) =
489     colval(scan[0],BLU) = fltv(c);
490     scan++;
491     }
492     return(0);
493     }
494    
495    
496 schorsch 2.12 static int
497     aclrscan2( /* get an ASCII color scanline */
498     register COLOR *scan,
499     register int len,
500     FILE *fp
501     )
502 gwlarson 2.8 {
503     while (len-- > 0) {
504     colval(scan[0],RED) = fltv(scanint(fp));
505     colval(scan[0],GRN) = fltv(scanint(fp));
506     colval(scan[0],BLU) = fltv(scanint(fp));
507     scan++;
508     }
509     return(0);
510     }
511    
512    
513 schorsch 2.12 static int
514     bclrscan2( /* get a binary color scanline */
515     register COLOR *scan,
516     int len,
517     register FILE *fp
518     )
519 gwlarson 2.8 {
520     int r, g, b;
521    
522     while (len-- > 0) {
523     r = getby2(fp);
524     g = getby2(fp);
525     if ((b = getby2(fp)) == EOF)
526     return(-1);
527     scan[0][RED] = fltv(r);
528     scan[0][GRN] = fltv(g);
529     scan[0][BLU] = fltv(b);
530     scan++;
531     }
532     return(0);
533     }
534    
535    
536 schorsch 2.12 static unsigned int
537     scanint( /* scan the next positive integer value */
538     register FILE *fp
539     )
540 greg 1.1 {
541 gwlarson 2.8 register int c;
542     register unsigned int i;
543 greg 1.1 tryagain:
544     while (isspace(c = getc(fp)))
545     ;
546     if (c == EOF)
547     quiterr("unexpected end of file");
548     if (c == '#') { /* comment */
549     while ((c = getc(fp)) != EOF && c != '\n')
550     ;
551     goto tryagain;
552     }
553     /* should be integer */
554     i = 0;
555     do {
556     if (!isdigit(c))
557     quiterr("error reading integer");
558     i = 10*i + c - '0';
559     c = getc(fp);
560     } while (c != EOF && !isspace(c));
561     return(i);
562     }
563    
564    
565 schorsch 2.12 static int
566     normval( /* normalize a value to [0,255] */
567     register unsigned int v
568     )
569 greg 1.1 {
570     if (v >= maxval)
571     return(255);
572     if (maxval == 255)
573     return(v);
574     return(v*255L/maxval);
575 gwlarson 2.8 }
576    
577    
578 schorsch 2.12 static unsigned int
579     getby2( /* return 2-byte quantity from fp */
580     register FILE *fp
581     )
582 gwlarson 2.8 {
583     register int lowerb, upperb;
584    
585 greg 2.13 upperb = getc(fp);
586 gwlarson 2.8 lowerb = getc(fp);
587 greg 2.14 if (lowerb == EOF)
588 gwlarson 2.8 return(EOF);
589     return(upperb<<8 | lowerb);
590     }
591    
592    
593 schorsch 2.12 static void
594     putby2( /* put 2-byte quantity to fp */
595     register unsigned int w,
596     register FILE *fp
597     )
598 gwlarson 2.8 {
599 greg 2.13 putc(w>>8 & 0xff, fp);
600 gwlarson 2.8 putc(w & 0xff, fp);
601     if (ferror(fp)) {
602     fprintf(stderr, "%s: write error on PPM output\n", progname);
603     exit(1);
604     }
605     }
606    
607    
608 schorsch 2.12 static unsigned int
609     intv( /* return integer quantity for v */
610     register double v
611     )
612 gwlarson 2.8 {
613     if (v >= 0.99999)
614     return(maxval);
615     if (v <= 0.)
616     return(0);
617     return((int)(v*(maxval+1)));
618 greg 1.1 }