ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/ximage.c
Revision: 1.27
Committed: Wed Nov 7 13:10:39 1990 UTC (33 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.26: +1 -1 lines
Log Message:
minor improvement in gamma correction

File Contents

# User Rev Content
1 greg 1.1 /* Copyright (c) 1987 Regents of the University of California */
2    
3     #ifndef lint
4     static char SCCSid[] = "$SunId$ LBL";
5     #endif
6    
7     /*
8     * ximage.c - driver for X-windows
9     *
10     * 4/30/87
11     * 3/3/88 Added calls to xraster & Paul Heckbert's ciq routines
12     */
13    
14     #include "standard.h"
15    
16     #include <X/Xlib.h>
17     #include <X/cursors/bcross.cursor>
18     #include <X/cursors/bcross_mask.cursor>
19    
20     #include <sys/types.h>
21    
22     #include <ctype.h>
23    
24     #include "color.h"
25    
26     #include "xraster.h"
27    
28     #include "view.h"
29    
30     #include "pic.h"
31    
32 greg 1.15 #include "random.h"
33    
34 greg 1.1 #define controlshift(e) (((XButtonEvent *)(e))->detail & (ShiftMask|ControlMask))
35    
36     #define FONTNAME "9x15" /* text font we'll use */
37    
38     #define CTRL(c) ('c'-'@')
39    
40     #define BORWIDTH 5 /* border width */
41     #define BARHEIGHT 25 /* menu bar size */
42    
43 greg 1.11 double gamcor = 2.2; /* gamma correction */
44 greg 1.1
45 greg 1.2 XRASTER *ourras = NULL; /* our stored raster image */
46 greg 1.1
47     int dither = 1; /* dither colors? */
48     int fast = 0; /* keep picture in Pixmap? */
49    
50     Window wind = 0; /* our output window */
51     Font fontid; /* our font */
52    
53     int maxcolors = 0; /* maximum colors */
54     int greyscale = 0; /* in grey */
55    
56 greg 1.2 int scale = 0; /* scalefactor; power of two */
57    
58 greg 1.1 int xoff = 0; /* x image offset */
59     int yoff = 0; /* y image offset */
60    
61 greg 1.21 VIEW ourview = STDVIEW; /* image view parameters */
62 greg 1.1 int gotview = 0; /* got parameters from file */
63    
64     COLR *scanline; /* scan line buffer */
65    
66     int xmax, ymax; /* picture resolution */
67     int width, height; /* window size */
68     char *fname = NULL; /* input file name */
69     FILE *fin = stdin; /* input file */
70     long *scanpos = NULL; /* scan line positions in file */
71     int cury = 0; /* current scan location */
72    
73     double exposure = 1.0; /* exposure compensation used */
74    
75     struct {
76     int xmin, ymin, xsiz, ysiz;
77     } box = {0, 0, 0, 0}; /* current box */
78    
79     char *geometry = NULL; /* geometry specification */
80    
81     char *progname;
82    
83     char errmsg[128];
84    
85     extern long ftell();
86    
87     extern char *malloc(), *calloc();
88    
89 greg 1.2 extern double atof(), pow(), log();
90 greg 1.1
91    
92     main(argc, argv)
93     int argc;
94     char *argv[];
95     {
96     int headline();
97     int i;
98    
99     progname = argv[0];
100    
101     for (i = 1; i < argc; i++)
102     if (argv[i][0] == '-')
103     switch (argv[i][1]) {
104     case 'c':
105     maxcolors = atoi(argv[++i]);
106     break;
107     case 'b':
108     greyscale = !greyscale;
109     break;
110     case 'm':
111     maxcolors = 2;
112     break;
113     case 'd':
114     dither = !dither;
115     break;
116     case 'f':
117     fast = !fast;
118     break;
119 greg 1.2 case 'e':
120     if (argv[i+1][0] != '+' && argv[i+1][0] != '-')
121     goto userr;
122     scale = atoi(argv[++i]);
123     break;
124 greg 1.1 case 'g':
125     gamcor = atof(argv[++i]);
126     break;
127     default:
128     goto userr;
129     }
130     else if (argv[i][0] == '=')
131     geometry = argv[i];
132     else
133     break;
134    
135     if (argc-i == 1) {
136     fname = argv[i];
137     fin = fopen(fname, "r");
138     if (fin == NULL) {
139     sprintf(errmsg, "can't open file \"%s\"", fname);
140     quiterr(errmsg);
141     }
142 greg 1.6 }
143 greg 1.1 /* get header */
144     getheader(fin, headline);
145     /* get picture dimensions */
146 greg 1.9 if (fgetresolu(&xmax, &ymax, fin) != (YMAJOR|YDECR))
147 greg 1.1 quiterr("bad picture size");
148     /* set view parameters */
149 greg 1.21 if (gotview && setview(&ourview) != NULL)
150     gotview = 0;
151 greg 1.1 if ((scanline = (COLR *)malloc(xmax*sizeof(COLR))) == NULL)
152     quiterr("out of memory");
153    
154     init(); /* get file and open window */
155    
156     for ( ; ; )
157     getevent(); /* main loop */
158     userr:
159     fprintf(stderr,
160 greg 1.2 "Usage: %s [=geometry][-b][-m][-d][-f][-c ncolors][-e +/-stops] file\n",
161 greg 1.1 progname);
162     quit(1);
163     }
164    
165    
166     headline(s) /* get relevant info from header */
167     char *s;
168     {
169 greg 1.4 static char *altname[] = {"rview","rpict",VIEWSTR,NULL};
170 greg 1.1 register char **an;
171    
172 greg 1.20 if (isexpos(s))
173     exposure *= exposval(s);
174 greg 1.1 else
175     for (an = altname; *an != NULL; an++)
176     if (!strncmp(*an, s, strlen(*an))) {
177 greg 1.21 if (sscanview(&ourview, s+strlen(*an)) > 0)
178 greg 1.1 gotview++;
179     return;
180     }
181     }
182    
183    
184     init() /* get data and open window */
185     {
186     register int i;
187     OpaqueFrame mainframe;
188     char defgeom[32];
189    
190     if (fname != NULL) {
191     scanpos = (long *)malloc(ymax*sizeof(long));
192     if (scanpos == NULL)
193     goto memerr;
194     for (i = 0; i < ymax; i++)
195     scanpos[i] = -1;
196     }
197     if (XOpenDisplay(NULL) == NULL)
198     quiterr("can't open display; DISPLAY variable set?");
199     #ifdef notdef
200     if (DisplayWidth() - 2*BORWIDTH < xmax ||
201     DisplayHeight() - 2*BORWIDTH - BARHEIGHT < ymax)
202     quiterr("resolution mismatch");
203     #endif
204     if (maxcolors == 0) { /* get number of available colors */
205     maxcolors = 1<<DisplayPlanes();
206     if (maxcolors > 4) maxcolors -= 2;
207     }
208     /* store image */
209 greg 1.2 getras();
210    
211 greg 1.1 mainframe.bdrwidth = BORWIDTH;
212     mainframe.border = WhitePixmap;
213     mainframe.background = BlackPixmap;
214     sprintf(defgeom, "=%dx%d+0+22", xmax, ymax);
215     wind = XCreate("Radiance Image", progname, geometry, defgeom,
216     &mainframe, 16, 16);
217     if (wind == 0)
218     quiterr("can't create window");
219     width = mainframe.width;
220     height = mainframe.height;
221     fontid = XGetFont(FONTNAME);
222     if (fontid == 0)
223     quiterr("can't get font");
224     XStoreName(wind, fname == NULL ? progname : fname);
225     XDefineCursor(wind, XCreateCursor(bcross_width, bcross_height,
226     bcross_bits, bcross_mask_bits,
227     bcross_x_hot, bcross_y_hot,
228     BlackPixel, WhitePixel, GXcopy));
229     XSelectInput(wind, ButtonPressed|ButtonReleased|UnmapWindow
230     |RightDownMotion|MiddleDownMotion|LeftDownMotion
231     |KeyPressed|ExposeWindow|ExposeRegion);
232     XMapWindow(wind);
233     return;
234     memerr:
235     quiterr("out of memory");
236     }
237    
238    
239     quiterr(err) /* print message and exit */
240     char *err;
241     {
242     if (err != NULL)
243     fprintf(stderr, "%s: %s\n", progname, err);
244    
245     exit(err == NULL ? 0 : 1);
246     }
247    
248    
249     eputs(s)
250     char *s;
251     {
252     fputs(s, stderr);
253     }
254    
255    
256     quit(code)
257     int code;
258     {
259     exit(code);
260     }
261    
262    
263 greg 1.2 getras() /* get raster file */
264     {
265     colormap ourmap;
266    
267     ourras = (XRASTER *)calloc(1, sizeof(XRASTER));
268     if (ourras == NULL)
269     goto memerr;
270     ourras->width = xmax;
271     ourras->height = ymax;
272     if (maxcolors <= 2) { /* monochrome */
273     ourras->data.m = (unsigned short *)malloc(BitmapSize(xmax,ymax));
274     if (ourras->data.m == NULL)
275     goto memerr;
276     getmono();
277     } else {
278     ourras->data.bz = (unsigned char *)malloc(BZPixmapSize(xmax,ymax));
279     if (ourras->data.bz == NULL)
280     goto memerr;
281     if (greyscale)
282     biq(dither,maxcolors,1,ourmap);
283     else
284     ciq(dither,maxcolors,1,ourmap);
285     if (init_rcolors(ourras, ourmap) == 0)
286     goto memerr;
287     }
288     return;
289     memerr:
290 greg 1.26 quiterr("out of memory");
291 greg 1.2 }
292    
293    
294 greg 1.1 getevent() /* process the next event */
295     {
296     WindowInfo info;
297     XEvent e;
298    
299     XNextEvent(&e);
300     switch (e.type) {
301     case KeyPressed:
302     docom(&e);
303     break;
304     case ExposeWindow:
305     XQueryWindow(wind, &info); /* in case resized */
306     width = info.width;
307     height = info.height;
308     /* fall through */
309     case ExposeRegion:
310     fixwindow(&e);
311     break;
312     case UnmapWindow:
313 greg 1.2 unmap_rcolors(ourras);
314 greg 1.1 break;
315     case ButtonPressed:
316     if (controlshift(&e))
317     moveimage(&e);
318     else
319     getbox(&e);
320     break;
321     }
322     }
323    
324    
325     fixwindow(eexp) /* fix new or stepped-on window */
326     XExposeEvent *eexp;
327     {
328     redraw(eexp->x, eexp->y, eexp->width, eexp->height);
329     }
330    
331    
332     redraw(x, y, w, h) /* redraw section of window */
333     int x, y;
334     int w, h;
335     {
336 greg 1.7 if (ourras->ncolors && map_rcolors(ourras) == NULL) {
337 greg 1.2 fprintf(stderr, "%s: cannot allocate colors\n", progname);
338     return(-1);
339     }
340 greg 1.1 if (fast)
341 greg 1.2 make_rpixmap(ourras);
342     return(patch_raster(wind,x-xoff,y-yoff,x,y,w,h,ourras) ? 0 : -1);
343 greg 1.1 }
344    
345    
346     docom(ekey) /* execute command */
347     XKeyEvent *ekey;
348     {
349     char buf[80];
350     COLOR cval;
351 greg 1.15 Color cvx;
352 greg 1.1 char *cp;
353     int n;
354 greg 1.2 double comp;
355 greg 1.1 FVECT rorg, rdir;
356    
357     cp = XLookupMapping(ekey, &n);
358     if (n == 0)
359     return(0);
360     switch (*cp) { /* interpret command */
361     case 'q':
362 greg 1.15 case CTRL(D): /* quit */
363 greg 1.1 quit(0);
364     case '\n':
365     case '\r':
366     case 'l':
367     case 'c': /* value */
368     if (avgbox(cval) == -1)
369     return(-1);
370     switch (*cp) {
371     case '\n':
372     case '\r': /* radiance */
373 greg 1.17 sprintf(buf, "%.3f", intens(cval)/exposure);
374 greg 1.1 break;
375     case 'l': /* luminance */
376 greg 1.17 sprintf(buf, "%.0fn", bright(cval)*683.0/exposure);
377 greg 1.1 break;
378     case 'c': /* color */
379 greg 1.2 comp = pow(2.0, (double)scale);
380 greg 1.1 sprintf(buf, "(%.2f,%.2f,%.2f)",
381 greg 1.2 colval(cval,RED)*comp,
382     colval(cval,GRN)*comp,
383     colval(cval,BLU)*comp);
384 greg 1.1 break;
385     }
386     XText(wind, box.xmin, box.ymin, buf, strlen(buf),
387     fontid, BlackPixel, WhitePixel);
388     return(0);
389 greg 1.15 case 'i': /* identify (contour) */
390 greg 1.16 if (ourras->pixels == NULL)
391 greg 1.15 return(-1);
392     n = ourras->data.bz[ekey->x-xoff+BZPixmapSize(xmax,ekey->y-yoff)];
393     n = ourras->pmap[n];
394     cvx.pixel = ourras->cdefs[n].pixel;
395     cvx.red = random() & 65535;
396     cvx.green = random() & 65535;
397     cvx.blue = random() & 65535;
398     XStoreColor(&cvx);
399     return(0);
400 greg 1.1 case 'p': /* position */
401     sprintf(buf, "(%d,%d)", ekey->x-xoff, ymax-1-ekey->y+yoff);
402     XText(wind, ekey->x, ekey->y, buf, strlen(buf),
403     fontid, BlackPixel, WhitePixel);
404     return(0);
405     case 't': /* trace */
406     if (!gotview) {
407     XFeep(0);
408     return(-1);
409     }
410 greg 1.25 if (viewray(rorg, rdir, &ourview, (ekey->x-xoff+.5)/xmax,
411     (ymax-1-ekey->y+yoff+.5)/ymax) < 0)
412     return(-1);
413 greg 1.1 printf("%e %e %e ", rorg[0], rorg[1], rorg[2]);
414     printf("%e %e %e\n", rdir[0], rdir[1], rdir[2]);
415     fflush(stdout);
416     return(0);
417 greg 1.2 case '=': /* adjust exposure */
418     if (avgbox(cval) == -1)
419     return(-1);
420     n = log(.5/bright(cval))/.69315 - scale; /* truncate */
421 greg 1.5 if (n == 0)
422 greg 1.2 return(0);
423     scale_rcolors(ourras, pow(2.0, (double)n));
424     scale += n;
425     sprintf(buf, "%+d", scale);
426     XText(wind, box.xmin, box.ymin, buf, strlen(buf),
427     fontid, BlackPixel, WhitePixel);
428     XFlush();
429     free_raster(ourras);
430     getras();
431 greg 1.3 /* fall through */
432 greg 1.1 case CTRL(R): /* redraw */
433 greg 1.6 case CTRL(L):
434 greg 1.16 unmap_rcolors(ourras);
435 greg 1.1 XClear(wind);
436     return(redraw(0, 0, width, height));
437     case ' ': /* clear */
438     return(redraw(box.xmin, box.ymin, box.xsiz, box.ysiz));
439     default:
440     XFeep(0);
441     return(-1);
442     }
443     }
444    
445    
446     moveimage(ep) /* shift the image */
447     XButtonEvent *ep;
448     {
449     XButtonEvent eb;
450    
451     XMaskEvent(ButtonReleased, &eb);
452     xoff += eb.x - ep->x;
453     yoff += eb.y - ep->y;
454     XClear(wind);
455     return(redraw(0, 0, width, height));
456     }
457    
458    
459     getbox(ebut) /* get new box */
460     XButtonEvent *ebut;
461     {
462     union {
463     XEvent e;
464     XButtonEvent b;
465     XMouseMovedEvent m;
466     } e;
467    
468     XMaskEvent(ButtonReleased|MouseMoved, &e.e);
469     while (e.e.type == MouseMoved) {
470     revbox(ebut->x, ebut->y, box.xmin = e.m.x, box.ymin = e.m.y);
471     XMaskEvent(ButtonReleased|MouseMoved, &e.e);
472     revbox(ebut->x, ebut->y, box.xmin, box.ymin);
473     }
474     box.xmin = e.b.x<0 ? 0 : (e.b.x>=width ? width-1 : e.b.x);
475     box.ymin = e.b.y<0 ? 0 : (e.b.y>=height ? height-1 : e.b.y);
476     if (box.xmin > ebut->x) {
477     box.xsiz = box.xmin - ebut->x + 1;
478     box.xmin = ebut->x;
479     } else {
480     box.xsiz = ebut->x - box.xmin + 1;
481     }
482     if (box.ymin > ebut->y) {
483     box.ysiz = box.ymin - ebut->y + 1;
484     box.ymin = ebut->y;
485     } else {
486     box.ysiz = ebut->y - box.ymin + 1;
487     }
488     }
489    
490    
491     revbox(x0, y0, x1, y1) /* draw box with reversed lines */
492     int x0, y0, x1, y1;
493     {
494     XLine(wind, x0, y0, x1, y0, 1, 1, 0, GXinvert, AllPlanes);
495     XLine(wind, x0, y1, x1, y1, 1, 1, 0, GXinvert, AllPlanes);
496     XLine(wind, x0, y0, x0, y1, 1, 1, 0, GXinvert, AllPlanes);
497     XLine(wind, x1, y0, x1, y1, 1, 1, 0, GXinvert, AllPlanes);
498     }
499    
500    
501     avgbox(clr) /* average color over current box */
502     COLOR clr;
503     {
504     int left, right, top, bottom;
505     int y;
506     double d;
507     COLOR ctmp;
508     register int x;
509    
510     setcolor(clr, 0.0, 0.0, 0.0);
511     left = box.xmin - xoff;
512     right = left + box.xsiz;
513     if (left < 0)
514     left = 0;
515     if (right > xmax)
516     right = xmax;
517     if (left >= right)
518     return(-1);
519     top = box.ymin - yoff;
520     bottom = top + box.ysiz;
521     if (top < 0)
522     top = 0;
523     if (bottom > ymax)
524     bottom = ymax;
525     if (top >= bottom)
526     return(-1);
527     for (y = top; y < bottom; y++) {
528     if (getscan(y) == -1)
529     return(-1);
530     for (x = left; x < right; x++) {
531     colr_color(ctmp, scanline[x]);
532     addcolor(clr, ctmp);
533     }
534     }
535     d = 1.0/((right-left)*(bottom-top));
536     scalecolor(clr, d);
537     return(0);
538     }
539    
540    
541     getmono() /* get monochrome data */
542     {
543     register unsigned short *dp;
544     register int x, err;
545     int y;
546 greg 1.24 rgbpixel *inl;
547 greg 1.1 short *cerr;
548    
549 greg 1.24 if ((inl = (rgbpixel *)malloc(xmax*sizeof(rgbpixel))) == NULL
550 greg 1.1 || (cerr = (short *)calloc(xmax,sizeof(short))) == NULL)
551 greg 1.26 quiterr("out of memory in getmono");
552 greg 1.2 dp = ourras->data.m - 1;
553 greg 1.1 for (y = 0; y < ymax; y++) {
554 greg 1.24 picreadline3(y, inl);
555 greg 1.1 err = 0;
556     for (x = 0; x < xmax; x++) {
557     if (!(x&0xf))
558     *++dp = 0;
559 greg 1.24 err += rgb_bright(&inl[x]) + cerr[x];
560 greg 1.1 if (err > 127)
561     err -= 255;
562     else
563     *dp |= 1<<(x&0xf);
564     cerr[x] = err >>= 1;
565     }
566     }
567 greg 1.24 free((char *)inl);
568 greg 1.1 free((char *)cerr);
569     }
570    
571    
572 greg 1.2 init_rcolors(xr, cmap) /* (re)assign color values */
573 greg 1.1 register XRASTER *xr;
574     colormap cmap;
575     {
576     register int i;
577     register unsigned char *p;
578    
579     xr->pmap = (int *)malloc(256*sizeof(int));
580     if (xr->pmap == NULL)
581     return(0);
582     xr->cdefs = (Color *)malloc(256*sizeof(Color));
583     if (xr->cdefs == NULL)
584     return(0);
585     for (i = 0; i < 256; i++)
586     xr->pmap[i] = -1;
587     xr->ncolors = 0;
588     for (p = xr->data.bz, i = BZPixmapSize(xr->width,xr->height); i--; p++)
589     if (xr->pmap[*p] == -1) {
590     xr->cdefs[xr->ncolors].red = cmap[0][*p] << 8;
591     xr->cdefs[xr->ncolors].green = cmap[1][*p] << 8;
592     xr->cdefs[xr->ncolors].blue = cmap[2][*p] << 8;
593     xr->cdefs[xr->ncolors].pixel = *p;
594     xr->pmap[*p] = xr->ncolors++;
595     }
596     xr->cdefs = (Color *)realloc((char *)xr->cdefs, xr->ncolors*sizeof(Color));
597     if (xr->cdefs == NULL)
598     return(0);
599     return(1);
600     }
601    
602    
603 greg 1.2 scale_rcolors(xr, sf) /* scale color map */
604     register XRASTER *xr;
605     double sf;
606     {
607     register int i;
608 greg 1.16 long maxv;
609 greg 1.2
610 greg 1.16 if (xr->pixels == NULL)
611     return;
612    
613 greg 1.2 sf = pow(sf, 1.0/gamcor);
614 greg 1.16 maxv = 65535/sf;
615 greg 1.2
616     for (i = xr->ncolors; i--; ) {
617 greg 1.16 xr->cdefs[i].red = xr->cdefs[i].red > maxv ?
618     65535 :
619 greg 1.2 xr->cdefs[i].red * sf;
620 greg 1.16 xr->cdefs[i].green = xr->cdefs[i].green > maxv ?
621     65535 :
622 greg 1.2 xr->cdefs[i].green * sf;
623 greg 1.16 xr->cdefs[i].blue = xr->cdefs[i].blue > maxv ?
624     65535 :
625 greg 1.2 xr->cdefs[i].blue * sf;
626     }
627 greg 1.16 XStoreColors(xr->ncolors, xr->cdefs);
628 greg 1.2 }
629    
630    
631 greg 1.1 getscan(y)
632     int y;
633     {
634     if (y != cury) {
635     if (scanpos == NULL || scanpos[y] == -1)
636     return(-1);
637     if (fseek(fin, scanpos[y], 0) == -1)
638 greg 1.26 quiterr("fseek error");
639 greg 1.1 cury = y;
640     } else if (scanpos != NULL)
641     scanpos[y] = ftell(fin);
642    
643     if (freadcolrs(scanline, xmax, fin) < 0)
644     quiterr("read error");
645    
646     cury++;
647     return(0);
648     }
649    
650    
651     picreadline3(y, l3) /* read in 3-byte scanline */
652     int y;
653     register rgbpixel *l3;
654     {
655 greg 1.12 register int i;
656     /* read scanline */
657 greg 1.1 if (getscan(y) < 0)
658     quiterr("cannot seek for picreadline");
659     /* convert scanline */
660 greg 1.23 normcolrs(scanline, xmax, scale);
661 greg 1.12 for (i = 0; i < xmax; i++) {
662     l3[i].r = scanline[i][RED];
663     l3[i].g = scanline[i][GRN];
664     l3[i].b = scanline[i][BLU];
665 greg 1.1 }
666     }
667    
668    
669     picwriteline(y, l) /* add 8-bit scanline to image */
670     int y;
671     pixel *l;
672     {
673 greg 1.22 bcopy((char *)l, (char *)ourras->data.bz+BZPixmapSize(xmax,y), BZPixmapSize(xmax,1));
674 greg 1.1 }
675    
676    
677 greg 1.8 picreadcm(map) /* do gamma correction */
678 greg 1.1 colormap map;
679     {
680     extern double pow();
681     register int i, val;
682    
683     for (i = 0; i < 256; i++) {
684 greg 1.27 val = pow((i+0.5)/256.0, 1.0/gamcor) * 256.0;
685 greg 1.1 map[0][i] = map[1][i] = map[2][i] = val;
686     }
687     }
688    
689    
690     picwritecm(map) /* handled elsewhere */
691     colormap map;
692     {
693 greg 1.2 #ifdef DEBUG
694     register int i;
695    
696     for (i = 0; i < 256; i++)
697     printf("%d %d %d\n", map[0][i],map[1][i],map[2][i]);
698     #endif
699 greg 1.1 }