ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/x11image.c
Revision: 1.14
Committed: Thu Apr 18 14:35:49 1991 UTC (33 years ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.13: +10 -4 lines
Log Message:
added format information to headers

File Contents

# Content
1 /* Copyright (c) 1990 Regents of the University of California */
2
3 #ifndef lint
4 static char SCCSid[] = "$SunId$ LBL";
5 #endif
6
7 /*
8 * x11image.c - driver for X-windows
9 *
10 * 3/1/90
11 */
12
13 /*
14 * Modified for X11
15 *
16 * January 1990
17 *
18 * Anat Grynberg and Greg Ward
19 */
20
21
22 #include "standard.h"
23
24 #include <X11/Xlib.h>
25 #include <X11/cursorfont.h>
26 #include <X11/Xutil.h>
27
28 #include "color.h"
29 #include "view.h"
30 #include "pic.h"
31 #include "x11raster.h"
32 #include "random.h"
33
34 #define FONTNAME "8x13" /* text font we'll use */
35
36 #define CTRL(c) ('c'-'@')
37
38 #define BORWIDTH 5 /* border width */
39
40 #define ourscreen DefaultScreen(thedisplay)
41 #define ourblack BlackPixel(thedisplay,ourscreen)
42 #define ourwhite WhitePixel(thedisplay,ourscreen)
43 #define ourroot RootWindow(thedisplay,ourscreen)
44 #define ourgc DefaultGC(thedisplay,ourscreen)
45
46 #define revline(x0,y0,x1,y1) XDrawLine(thedisplay,wind,revgc,x0,y0,x1,y1)
47
48 #define redraw(x,y,w,h) patch_raster(wind,(x)-xoff,(y)-yoff,x,y,w,h,ourras)
49
50 double gamcor = 2.2; /* gamma correction */
51
52 int dither = 1; /* dither colors? */
53 int fast = 0; /* keep picture in Pixmap? */
54
55 Window wind = 0; /* our output window */
56 Font fontid; /* our font */
57
58 int maxcolors = 0; /* maximum colors */
59 int greyscale = 0; /* in grey */
60
61 int scale = 0; /* scalefactor; power of two */
62
63 int xoff = 0; /* x image offset */
64 int yoff = 0; /* y image offset */
65
66 VIEW ourview = STDVIEW; /* image view parameters */
67 int gotview = 0; /* got parameters from file */
68
69 COLR *scanline; /* scan line buffer */
70
71 int xmax, ymax; /* picture resolution */
72 int width, height; /* window size */
73 char *fname = NULL; /* input file name */
74 FILE *fin = stdin; /* input file */
75 long *scanpos = NULL; /* scan line positions in file */
76 int cury = 0; /* current scan location */
77
78 double exposure = 1.0; /* exposure compensation used */
79
80 int wrongformat = 0; /* input in another format? */
81
82 GC revgc; /* graphics context with GXinvert */
83
84 XRASTER *ourras; /* our stored image */
85 unsigned char *ourdata; /* our image data */
86
87 struct {
88 int xmin, ymin, xsiz, ysiz;
89 } box = {0, 0, 0, 0}; /* current box */
90
91 char *geometry = NULL; /* geometry specification */
92
93 char *progname;
94
95 char errmsg[128];
96
97 extern long ftell();
98
99 extern char *malloc(), *calloc();
100
101 extern double atof(), pow(), log();
102
103 Display *thedisplay;
104
105 main(argc, argv)
106 int argc;
107 char *argv[];
108 {
109 int headline();
110 int i;
111
112 progname = argv[0];
113
114 for (i = 1; i < argc; i++)
115 if (argv[i][0] == '-')
116 switch (argv[i][1]) {
117 case 'c':
118 maxcolors = atoi(argv[++i]);
119 break;
120 case 'b':
121 greyscale = !greyscale;
122 break;
123 case 'm':
124 maxcolors = 2;
125 break;
126 case 'd':
127 dither = !dither;
128 break;
129 case 'f':
130 fast = !fast;
131 break;
132 case 'e':
133 if (argv[i+1][0] != '+' && argv[i+1][0] != '-')
134 goto userr;
135 scale = atoi(argv[++i]);
136 break;
137 case 'g':
138 if (!strcmp(argv[i], "-geometry"))
139 geometry = argv[++i];
140 else
141 gamcor = atof(argv[++i]);
142 break;
143 default:
144 goto userr;
145 }
146 else if (argv[i][0] == '=')
147 geometry = argv[i];
148 else
149 break;
150
151 if (i == argc-1) {
152 fname = argv[i];
153 fin = fopen(fname, "r");
154 if (fin == NULL) {
155 sprintf(errmsg, "can't open file \"%s\"", fname);
156 quiterr(errmsg);
157 }
158 } else if (i != argc)
159 goto userr;
160 /* get header */
161 getheader(fin, headline, NULL);
162 /* get picture dimensions */
163 if (wrongformat || fgetresolu(&xmax, &ymax, fin) != (YMAJOR|YDECR))
164 quiterr("bad picture format");
165 /* set view parameters */
166 if (gotview && setview(&ourview) != NULL)
167 gotview = 0;
168 if ((scanline = (COLR *)malloc(xmax*sizeof(COLR))) == NULL)
169 quiterr("out of memory");
170
171 init(); /* get file and open window */
172
173 for ( ; ; )
174 getevent(); /* main loop */
175 userr:
176 fprintf(stderr,
177 "Usage: %s [-geometry spec][-b][-m][-d][-f][-c ncolors][-e +/-stops] file\n",
178 progname);
179 quit(1);
180 }
181
182
183 headline(s) /* get relevant info from header */
184 char *s;
185 {
186 static char *altname[] = {"rview","rpict","pinterp",VIEWSTR,NULL};
187 register char **an;
188 char fmt[32];
189
190 if (isexpos(s))
191 exposure *= exposval(s);
192 else if (isformat(s)) {
193 formatval(fmt, s);
194 wrongformat = strcmp(fmt, COLRFMT);
195 } else
196 for (an = altname; *an != NULL; an++)
197 if (!strncmp(*an, s, strlen(*an))) {
198 if (sscanview(&ourview, s+strlen(*an)) > 0)
199 gotview++;
200 return;
201 }
202 }
203
204
205 init() /* get data and open window */
206 {
207 XSetWindowAttributes ourwinattr;
208 XSizeHints oursizhints;
209 register int i;
210
211 if (fname != NULL) {
212 scanpos = (long *)malloc(ymax*sizeof(long));
213 if (scanpos == NULL)
214 goto memerr;
215 for (i = 0; i < ymax; i++)
216 scanpos[i] = -1;
217 }
218 if ((thedisplay = XOpenDisplay(NULL)) == NULL)
219 quiterr("can't open display; DISPLAY variable set?");
220 if (maxcolors == 0) { /* get number of available colors */
221 i = DisplayPlanes(thedisplay,ourscreen);
222 maxcolors = i > 8 ? 256 : 1<<i;
223 if (maxcolors > 4) maxcolors -= 2;
224 }
225 /* store image */
226 getras();
227 /* open window */
228 ourwinattr.border_pixel = ourblack;
229 ourwinattr.background_pixel = ourwhite;
230 wind = XCreateWindow(thedisplay, ourroot, 0, 0, xmax, ymax, BORWIDTH,
231 0, InputOutput, ourras->visual,
232 CWBackPixel|CWBorderPixel, &ourwinattr);
233 if (wind == 0)
234 quiterr("can't create window");
235 width = xmax;
236 height = ymax;
237 fontid = XLoadFont(thedisplay, FONTNAME);
238 if (fontid == 0)
239 quiterr("can't get font");
240 XSetFont(thedisplay, ourgc, fontid);
241 revgc = XCreateGC(thedisplay, wind, 0, 0);
242 XSetFunction(thedisplay, revgc, GXinvert);
243 XStoreName(thedisplay, wind, fname == NULL ? progname : fname);
244 XDefineCursor(thedisplay, wind, XCreateFontCursor(thedisplay,
245 XC_diamond_cross));
246 if (geometry != NULL) {
247 bzero((char *)&oursizhints, sizeof(oursizhints));
248 i = XParseGeometry(geometry, &oursizhints.x, &oursizhints.y,
249 (unsigned *)&oursizhints.width,
250 (unsigned *)&oursizhints.height);
251 if ((i&(WidthValue|HeightValue)) == (WidthValue|HeightValue))
252 oursizhints.flags |= USSize;
253 else {
254 oursizhints.width = xmax;
255 oursizhints.height = ymax;
256 oursizhints.flags |= PSize;
257 }
258 if ((i&(XValue|YValue)) == (XValue|YValue)) {
259 oursizhints.flags |= USPosition;
260 if (i & XNegative)
261 oursizhints.x += DisplayWidth(thedisplay,
262 ourscreen)-1-oursizhints.width-2*BORWIDTH;
263 if (i & YNegative)
264 oursizhints.y += DisplayHeight(thedisplay,
265 ourscreen)-1-oursizhints.height-2*BORWIDTH;
266 }
267 XSetNormalHints(thedisplay, wind, &oursizhints);
268 }
269 XSelectInput(thedisplay, wind, ButtonPressMask|ButtonReleaseMask
270 |ButtonMotionMask|StructureNotifyMask
271 |KeyPressMask|ExposureMask);
272 XMapWindow(thedisplay, wind);
273 return;
274 memerr:
275 quiterr("out of memory");
276 } /* end of init */
277
278
279 quiterr(err) /* print message and exit */
280 char *err;
281 {
282 if (err != NULL) {
283 fprintf(stderr, "%s: %s\n", progname, err);
284 exit(1);
285 }
286 exit(0);
287 }
288
289
290 eputs(s)
291 char *s;
292 {
293 fputs(s, stderr);
294 }
295
296
297 quit(code)
298 int code;
299 {
300 exit(code);
301 }
302
303
304 getras() /* get raster file */
305 {
306 colormap ourmap;
307 XVisualInfo vinfo;
308
309 if (maxcolors <= 2) { /* monochrome */
310 ourdata = (unsigned char *)malloc(ymax*((xmax+7)/8));
311 if (ourdata == NULL)
312 goto fail;
313 ourras = make_raster(thedisplay, ourscreen, 1, ourdata,
314 xmax, ymax, 8);
315 if (ourras == NULL)
316 goto fail;
317 getmono();
318 } else if (XMatchVisualInfo(thedisplay,ourscreen,24,TrueColor,&vinfo)
319 /* kludge for DirectColor */
320 || XMatchVisualInfo(thedisplay,ourscreen,24,DirectColor,&vinfo)) {
321 ourdata = (unsigned char *)malloc(xmax*ymax*3);
322 if (ourdata == NULL)
323 goto fail;
324 ourras = make_raster(thedisplay, ourscreen, 24, ourdata,
325 xmax, ymax, 8);
326 if (ourras == NULL)
327 goto fail;
328 getfull();
329 } else {
330 ourdata = (unsigned char *)malloc(xmax*ymax);
331 if (ourdata == NULL)
332 goto fail;
333 ourras = make_raster(thedisplay, ourscreen, 8, ourdata,
334 xmax, ymax, 8);
335 if (ourras == NULL)
336 goto fail;
337 if (greyscale)
338 biq(dither,maxcolors,1,ourmap);
339 else
340 ciq(dither,maxcolors,1,ourmap);
341 if (init_rcolors(ourras, ourmap[0], ourmap[1], ourmap[2]) == 0)
342 goto fail;
343 }
344 return;
345 fail:
346 quiterr("could not create raster image");
347 }
348
349
350 getevent() /* process the next event */
351 {
352 union {
353 XEvent u;
354 XConfigureEvent c;
355 XExposeEvent e;
356 XButtonPressedEvent b;
357 XKeyPressedEvent k;
358 } e;
359
360 XNextEvent(thedisplay, &e.u);
361 switch (e.u.type) {
362 case KeyPress:
363 docom(&e.k);
364 break;
365 case ConfigureNotify:
366 width = e.c.width;
367 height = e.c.height;
368 break;
369 case MapNotify:
370 map_rcolors(ourras, wind);
371 if (fast)
372 make_rpixmap(ourras);
373 break;
374 case UnmapNotify:
375 unmap_rcolors(ourras);
376 break;
377 case Expose:
378 redraw(e.e.x, e.e.y, e.e.width, e.e.height);
379 break;
380 case ButtonPress:
381 if (e.b.state & (ShiftMask|ControlMask))
382 moveimage(&e.b);
383 else
384 getbox(&e.b);
385 break;
386 }
387 }
388
389
390 docom(ekey) /* execute command */
391 XKeyPressedEvent *ekey;
392 {
393 char buf[80];
394 COLOR cval;
395 XColor cvx;
396 int com, n;
397 double comp;
398 FVECT rorg, rdir;
399
400 n = XLookupString(ekey, buf, sizeof(buf), NULL, NULL);
401 if (n == 0)
402 return(0);
403 com = buf[0];
404 switch (com) { /* interpret command */
405 case 'q':
406 case CTRL(D): /* quit */
407 quit(0);
408 case '\n':
409 case '\r':
410 case 'l':
411 case 'c': /* value */
412 if (avgbox(cval) == -1)
413 return(-1);
414 switch (com) {
415 case '\n':
416 case '\r': /* radiance */
417 sprintf(buf, "%.3f", intens(cval)/exposure);
418 break;
419 case 'l': /* luminance */
420 sprintf(buf, "%.0fn", luminance(cval)/exposure);
421 break;
422 case 'c': /* color */
423 comp = pow(2.0, (double)scale);
424 sprintf(buf, "(%.2f,%.2f,%.2f)",
425 colval(cval,RED)*comp,
426 colval(cval,GRN)*comp,
427 colval(cval,BLU)*comp);
428 break;
429 }
430 XDrawImageString(thedisplay, wind, ourgc,
431 box.xmin, box.ymin+box.ysiz, buf, strlen(buf));
432 return(0);
433 case 'i': /* identify (contour) */
434 if (ourras->pixels == NULL)
435 return(-1);
436 n = ourdata[ekey->x-xoff+xmax*(ekey->y-yoff)];
437 n = ourras->pmap[n];
438 cvx.pixel = ourras->cdefs[n].pixel;
439 cvx.red = random() & 65535;
440 cvx.green = random() & 65535;
441 cvx.blue = random() & 65535;
442 cvx.flags = DoRed|DoGreen|DoBlue;
443 XStoreColor(thedisplay, ourras->cmap, &cvx);
444 return(0);
445 case 'p': /* position */
446 sprintf(buf, "(%d,%d)", ekey->x-xoff, ymax-1-ekey->y+yoff);
447 XDrawImageString(thedisplay, wind, ourgc, ekey->x, ekey->y,
448 buf, strlen(buf));
449 return(0);
450 case 't': /* trace */
451 if (!gotview) {
452 XBell(thedisplay, 0);
453 return(-1);
454 }
455 if (viewray(rorg, rdir, &ourview,
456 (ekey->x-xoff+.5)/xmax,
457 (ymax-1-ekey->y+yoff+.5)/ymax) < 0)
458 return(-1);
459 printf("%e %e %e ", rorg[0], rorg[1], rorg[2]);
460 printf("%e %e %e\n", rdir[0], rdir[1], rdir[2]);
461 fflush(stdout);
462 return(0);
463 case '=': /* adjust exposure */
464 if (avgbox(cval) == -1)
465 return(-1);
466 n = log(.5/bright(cval))/.69315 - scale; /* truncate */
467 if (n == 0)
468 return(0);
469 scale_rcolors(ourras, pow(2.0, (double)n));
470 scale += n;
471 sprintf(buf, "%+d", scale);
472 XDrawImageString(thedisplay, wind, ourgc,
473 box.xmin, box.ymin+box.ysiz, buf, strlen(buf));
474 XFlush(thedisplay);
475 free(ourdata);
476 free_raster(ourras);
477 getras();
478 /* fall through */
479 case CTRL(R): /* redraw */
480 case CTRL(L):
481 unmap_rcolors(ourras);
482 XClearWindow(thedisplay, wind);
483 map_rcolors(ourras, wind);
484 if (fast)
485 make_rpixmap(ourras);
486 redraw(0, 0, width, height);
487 return(0);
488 case ' ': /* clear */
489 redraw(box.xmin, box.ymin, box.xsiz, box.ysiz);
490 return(0);
491 default:
492 XBell(thedisplay, 0);
493 return(-1);
494 }
495 }
496
497
498 moveimage(ebut) /* shift the image */
499 XButtonPressedEvent *ebut;
500 {
501 union {
502 XEvent u;
503 XButtonReleasedEvent b;
504 XPointerMovedEvent m;
505 } e;
506 int mxo, myo;
507
508 XMaskEvent(thedisplay, ButtonReleaseMask|ButtonMotionMask, &e.u);
509 while (e.u.type == MotionNotify) {
510 mxo = e.m.x;
511 myo = e.m.y;
512 revline(ebut->x, ebut->y, mxo, myo);
513 revbox(xoff+mxo-ebut->x, yoff+myo-ebut->y,
514 xoff+mxo-ebut->x+xmax, yoff+myo-ebut->y+ymax);
515 XMaskEvent(thedisplay,ButtonReleaseMask|ButtonMotionMask,&e.u);
516 revline(ebut->x, ebut->y, mxo, myo);
517 revbox(xoff+mxo-ebut->x, yoff+myo-ebut->y,
518 xoff+mxo-ebut->x+xmax, yoff+myo-ebut->y+ymax);
519 }
520 xoff += e.b.x - ebut->x;
521 yoff += e.b.y - ebut->y;
522 XClearWindow(thedisplay, wind);
523 redraw(0, 0, width, height);
524 }
525
526
527 getbox(ebut) /* get new box */
528 XButtonPressedEvent *ebut;
529 {
530 union {
531 XEvent u;
532 XButtonReleasedEvent b;
533 XPointerMovedEvent m;
534 } e;
535
536 XMaskEvent(thedisplay, ButtonReleaseMask|ButtonMotionMask, &e.u);
537 while (e.u.type == MotionNotify) {
538 revbox(ebut->x, ebut->y, box.xmin = e.m.x, box.ymin = e.m.y);
539 XMaskEvent(thedisplay,ButtonReleaseMask|ButtonMotionMask,&e.u);
540 revbox(ebut->x, ebut->y, box.xmin, box.ymin);
541 }
542 box.xmin = e.b.x<0 ? 0 : (e.b.x>=width ? width-1 : e.b.x);
543 box.ymin = e.b.y<0 ? 0 : (e.b.y>=height ? height-1 : e.b.y);
544 if (box.xmin > ebut->x) {
545 box.xsiz = box.xmin - ebut->x + 1;
546 box.xmin = ebut->x;
547 } else {
548 box.xsiz = ebut->x - box.xmin + 1;
549 }
550 if (box.ymin > ebut->y) {
551 box.ysiz = box.ymin - ebut->y + 1;
552 box.ymin = ebut->y;
553 } else {
554 box.ysiz = ebut->y - box.ymin + 1;
555 }
556 }
557
558
559 revbox(x0, y0, x1, y1) /* draw box with reversed lines */
560 int x0, y0, x1, y1;
561 {
562 revline(x0, y0, x1, y0);
563 revline(x0, y1, x1, y1);
564 revline(x0, y0, x0, y1);
565 revline(x1, y0, x1, y1);
566 }
567
568
569 avgbox(clr) /* average color over current box */
570 COLOR clr;
571 {
572 int left, right, top, bottom;
573 int y;
574 double d;
575 COLOR ctmp;
576 register int x;
577
578 setcolor(clr, 0.0, 0.0, 0.0);
579 left = box.xmin - xoff;
580 right = left + box.xsiz;
581 if (left < 0)
582 left = 0;
583 if (right > xmax)
584 right = xmax;
585 if (left >= right)
586 return(-1);
587 top = box.ymin - yoff;
588 bottom = top + box.ysiz;
589 if (top < 0)
590 top = 0;
591 if (bottom > ymax)
592 bottom = ymax;
593 if (top >= bottom)
594 return(-1);
595 for (y = top; y < bottom; y++) {
596 if (getscan(y) == -1)
597 return(-1);
598 for (x = left; x < right; x++) {
599 colr_color(ctmp, scanline[x]);
600 addcolor(clr, ctmp);
601 }
602 }
603 d = 1.0/((right-left)*(bottom-top));
604 scalecolor(clr, d);
605 return(0);
606 }
607
608
609 getmono() /* get monochrome data */
610 {
611 register unsigned char *dp;
612 register int x, err;
613 int y;
614 short *cerr;
615
616 if ((cerr = (short *)calloc(xmax,sizeof(short))) == NULL)
617 quiterr("out of memory in getmono");
618 dp = ourdata - 1;
619 for (y = 0; y < ymax; y++) {
620 if (getscan(y) < 0)
621 quiterr("seek error in getmono");
622 normcolrs(scanline, xmax, scale);
623 err = 0;
624 for (x = 0; x < xmax; x++) {
625 if (!(x&7))
626 *++dp = 0;
627 err += normbright(scanline[x]) + cerr[x];
628 if (err > 127)
629 err -= 255;
630 else
631 *dp |= 1<<(7-(x&07));
632 cerr[x] = err >>= 1;
633 }
634 }
635 free((char *)cerr);
636 }
637
638
639 getfull() /* get full (24-bit) data */
640 {
641 int y;
642 register unsigned char *dp;
643 register int x;
644 /* set gamma correction */
645 setcolrgam(gamcor);
646 /* read and convert file */
647 dp = ourdata;
648 for (y = 0; y < ymax; y++) {
649 if (getscan(y) < 0)
650 quiterr("seek error in getfull");
651 if (scale)
652 shiftcolrs(scanline, xmax, scale);
653 colrs_gambs(scanline, xmax);
654 for (x = 0; x < xmax; x++) {
655 *dp++ = scanline[x][RED];
656 *dp++ = scanline[x][GRN];
657 *dp++ = scanline[x][BLU];
658 }
659 }
660 }
661
662
663 scale_rcolors(xr, sf) /* scale color map */
664 register XRASTER *xr;
665 double sf;
666 {
667 register int i;
668 long maxv;
669
670 if (xr->pixels == NULL)
671 return;
672
673 sf = pow(sf, 1.0/gamcor);
674 maxv = 65535/sf;
675
676 for (i = xr->ncolors; i--; ) {
677 xr->cdefs[i].red = xr->cdefs[i].red > maxv ?
678 65535 :
679 xr->cdefs[i].red * sf;
680 xr->cdefs[i].green = xr->cdefs[i].green > maxv ?
681 65535 :
682 xr->cdefs[i].green * sf;
683 xr->cdefs[i].blue = xr->cdefs[i].blue > maxv ?
684 65535 :
685 xr->cdefs[i].blue * sf;
686 }
687 XStoreColors(thedisplay, xr->cmap, xr->cdefs, xr->ncolors);
688 }
689
690
691 getscan(y)
692 int y;
693 {
694 if (y != cury) {
695 if (scanpos == NULL || scanpos[y] == -1)
696 return(-1);
697 if (fseek(fin, scanpos[y], 0) == -1)
698 quiterr("fseek error");
699 cury = y;
700 } else if (scanpos != NULL)
701 scanpos[y] = ftell(fin);
702
703 if (freadcolrs(scanline, xmax, fin) < 0)
704 quiterr("read error");
705
706 cury++;
707 return(0);
708 }
709
710
711 picreadline3(y, l3) /* read in 3-byte scanline */
712 int y;
713 register rgbpixel *l3;
714 {
715 register int i;
716 /* read scanline */
717 if (getscan(y) < 0)
718 quiterr("cannot seek for picreadline");
719 /* convert scanline */
720 normcolrs(scanline, xmax, scale);
721 for (i = 0; i < xmax; i++) {
722 l3[i].r = scanline[i][RED];
723 l3[i].g = scanline[i][GRN];
724 l3[i].b = scanline[i][BLU];
725 }
726 }
727
728
729 picwriteline(y, l) /* add 8-bit scanline to image */
730 int y;
731 pixel *l;
732 {
733 bcopy((char *)l, (char *)ourdata+y*xmax, xmax);
734 }
735
736
737 picreadcm(map) /* do gamma correction */
738 colormap map;
739 {
740 extern double pow();
741 register int i, val;
742
743 for (i = 0; i < 256; i++) {
744 val = pow((i+0.5)/256.0, 1.0/gamcor) * 256.0;
745 map[0][i] = map[1][i] = map[2][i] = val;
746 }
747 }
748
749
750 picwritecm(map) /* handled elsewhere */
751 colormap map;
752 {
753 #ifdef DEBUG
754 register int i;
755
756 for (i = 0; i < 256; i++)
757 printf("%d %d %d\n", map[0][i],map[1][i],map[2][i]);
758 #endif
759 }