ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/x11image.c
Revision: 2.43
Committed: Mon Jan 27 15:07:03 1997 UTC (27 years, 3 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.42: +36 -5 lines
Log Message:
added -t option and continuous mouse tracking with right button

File Contents

# Content
1 /* Copyright (c) 1997 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 <signal.h>
25 #include <X11/Xlib.h>
26 #include <X11/cursorfont.h>
27 #include <X11/Xutil.h>
28 #include <X11/Xatom.h>
29
30 #include "color.h"
31 #include "view.h"
32 #include "x11raster.h"
33 #include "random.h"
34 #include "resolu.h"
35
36 #ifdef __alpha
37 #define int4 int
38 #endif
39 #ifndef int4
40 #define int4 long
41 #endif
42
43 #define FONTNAME "8x13" /* text font we'll use */
44
45 #define CTRL(c) ((c)-'@')
46
47 #define BORWIDTH 5 /* border width */
48
49 #define ICONSIZ (8*10) /* maximum icon dimension (even 8) */
50
51 #define ourscreen DefaultScreen(thedisplay)
52 #define ourroot RootWindow(thedisplay,ourscreen)
53
54 #define revline(x0,y0,x1,y1) XDrawLine(thedisplay,wind,revgc,x0,y0,x1,y1)
55
56 #define redraw(x,y,w,h) patch_raster(wind,(x)-xoff,(y)-yoff,x,y,w,h,ourras)
57
58 double gamcor = 2.2; /* gamma correction */
59 char *gamstr = NULL; /* gamma value override */
60
61 int dither = 1; /* dither colors? */
62 int fast = 0; /* keep picture in Pixmap? */
63
64 char *dispname = NULL; /* our display name */
65
66 Window wind = 0; /* our output window */
67 unsigned long ourblack=0, ourwhite=1; /* black and white for this visual */
68 int maxcolors = 0; /* maximum colors */
69 int greyscale = 0; /* in grey */
70
71 int scale = 0; /* scalefactor; power of two */
72
73 int xoff = 0; /* x image offset */
74 int yoff = 0; /* y image offset */
75
76 int parent = 0; /* number of children, -1 if child */
77 int sequential = 0; /* display images in sequence */
78
79 char *tout = "od"; /* output of 't' command */
80 int tinterv = 0; /* interval between mouse reports */
81
82 VIEW ourview = STDVIEW; /* image view parameters */
83 int gotview = 0; /* got parameters from file */
84
85 COLR *scanline; /* scan line buffer */
86
87 RESOLU inpres; /* input resolution and ordering */
88 int xmax, ymax; /* picture dimensions */
89 int width, height; /* window size */
90 char *fname = NULL; /* input file name */
91 FILE *fin = stdin; /* input file */
92 long *scanpos = NULL; /* scan line positions in file */
93 int cury = 0; /* current scan location */
94
95 double exposure = 1.0; /* exposure compensation used */
96
97 int wrongformat = 0; /* input in another format? */
98
99 GC ourgc; /* standard graphics context */
100 GC revgc; /* graphics context with GXinvert */
101
102 int *ourrank; /* our visual class ranking */
103 XVisualInfo ourvis; /* our visual */
104 XRASTER *ourras; /* our stored image */
105 unsigned char *ourdata; /* our image data */
106
107 struct {
108 int xmin, ymin, xsiz, ysiz;
109 } box = {0, 0, 0, 0}; /* current box */
110
111 char *geometry = NULL; /* geometry specification */
112
113 char icondata[ICONSIZ*ICONSIZ/8]; /* icon bitmap data */
114 int iconwidth = 0, iconheight = 0;
115
116 char *progname;
117
118 char errmsg[128];
119
120 BYTE clrtab[256][3]; /* global color map */
121
122 extern long ftell();
123
124 extern char *getenv();
125
126 Display *thedisplay;
127 Atom closedownAtom, wmProtocolsAtom;
128
129 int sigrecv;
130
131 int onsig() { sigrecv++; }
132
133
134 main(argc, argv)
135 int argc;
136 char *argv[];
137 {
138 int headline();
139 int i;
140 int pid;
141
142 progname = argv[0];
143
144 for (i = 1; i < argc; i++)
145 if (argv[i][0] == '-')
146 switch (argv[i][1]) {
147 case 'c': /* number of colors */
148 maxcolors = atoi(argv[++i]);
149 break;
150 case 'b': /* greyscale only */
151 greyscale = !greyscale;
152 break;
153 case 'm': /* monochrome */
154 greyscale = 1;
155 maxcolors = 2;
156 break;
157 case 'd': /* display or dither */
158 if (argv[i][2] == 'i')
159 dispname = argv[++i];
160 else
161 dither = !dither;
162 break;
163 case 'f': /* save pixmap */
164 fast = !fast;
165 break;
166 case 's': /* one at a time */
167 sequential = !sequential;
168 break;
169 case 'o': /* 't' output */
170 tout = argv[i]+2;
171 break;
172 case 't': /* msec interval */
173 tinterv = atoi(argv[++i]);
174 break;
175 case 'e': /* exposure comp. */
176 if (argv[i+1][0] != '+' && argv[i+1][0] != '-')
177 goto userr;
178 scale = atoi(argv[++i]);
179 break;
180 case 'g': /* gamma comp. */
181 if (argv[i][2] == 'e')
182 geometry = argv[++i];
183 else
184 gamstr = argv[++i];
185 break;
186 default:
187 goto userr;
188 }
189 else if (argv[i][0] == '=')
190 geometry = argv[i];
191 else
192 break;
193
194 if (i > argc)
195 goto userr;
196 while (i < argc-1) {
197 sigrecv = 0;
198 signal(SIGCONT, onsig);
199 if ((pid=fork()) == 0) { /* a child for each picture */
200 parent = -1;
201 break;
202 }
203 if (pid < 0)
204 quiterr("fork failed");
205 parent++;
206 while (!sigrecv)
207 pause(); /* wait for wake-up call */
208 i++;
209 }
210 if (i < argc) { /* open picture file */
211 fname = argv[i];
212 fin = fopen(fname, "r");
213 if (fin == NULL)
214 quiterr("cannot open picture file");
215 }
216 /* get header */
217 getheader(fin, headline, NULL);
218 /* get picture dimensions */
219 if (wrongformat || !fgetsresolu(&inpres, fin))
220 quiterr("bad picture format");
221 xmax = scanlen(&inpres);
222 ymax = numscans(&inpres);
223 /* set view parameters */
224 if (gotview && setview(&ourview) != NULL)
225 gotview = 0;
226 if ((scanline = (COLR *)malloc(xmax*sizeof(COLR))) == NULL)
227 quiterr("out of memory");
228
229 init(argc, argv); /* get file and open window */
230
231 for ( ; ; )
232 getevent(); /* main loop */
233 userr:
234 fprintf(stderr,
235 "Usage: %s [-di disp][[-ge] spec][-b][-m][-d][-f][-c nclrs][-e +/-stops][-g gamcor][-s][-ospec][-t intvl] pic ..\n",
236 progname);
237 exit(1);
238 }
239
240
241 headline(s) /* get relevant info from header */
242 char *s;
243 {
244 char fmt[32];
245
246 if (isexpos(s))
247 exposure *= exposval(s);
248 else if (isformat(s)) {
249 formatval(fmt, s);
250 wrongformat = strcmp(fmt, COLRFMT);
251 } else if (isview(s) && sscanview(&ourview, s) > 0)
252 gotview++;
253 }
254
255
256 init(argc, argv) /* get data and open window */
257 int argc;
258 char **argv;
259 {
260 XSetWindowAttributes ourwinattr;
261 XClassHint xclshints;
262 XWMHints xwmhints;
263 XSizeHints xszhints;
264 XTextProperty windowName, iconName;
265 XGCValues xgcv;
266 char *name;
267 register int i;
268
269 if (fname != NULL) {
270 scanpos = (long *)malloc(ymax*sizeof(long));
271 if (scanpos == NULL)
272 quiterr("out of memory");
273 for (i = 0; i < ymax; i++)
274 scanpos[i] = -1;
275 name = fname;
276 } else
277 name = progname;
278 /* remove directory prefix from name */
279 for (i = strlen(name); i-- > 0; )
280 if (name[i] == '/')
281 break;
282 name += i+1;
283 if ((thedisplay = XOpenDisplay(dispname)) == NULL)
284 quiterr("cannot open display");
285 /* set gamma value */
286 if (gamstr == NULL) /* get it from the X server */
287 gamstr = XGetDefault(thedisplay, "radiance", "gamma");
288 if (gamstr == NULL) /* get it from the environment */
289 gamstr = getenv("DISPLAY_GAMMA");
290 if (gamstr != NULL)
291 gamcor = atof(gamstr);
292 /* get best visual for default screen */
293 getbestvis();
294 /* store image */
295 getras();
296 /* get size and position */
297 xszhints.flags = 0;
298 xszhints.width = xmax; xszhints.height = ymax;
299 if (geometry != NULL) {
300 i = XParseGeometry(geometry, &xszhints.x, &xszhints.y,
301 (unsigned *)&xszhints.width,
302 (unsigned *)&xszhints.height);
303 if ((i&(WidthValue|HeightValue)) == (WidthValue|HeightValue))
304 xszhints.flags |= USSize;
305 else
306 xszhints.flags |= PSize;
307 if ((i&(XValue|YValue)) == (XValue|YValue)) {
308 xszhints.flags |= USPosition;
309 if (i & XNegative)
310 xszhints.x += DisplayWidth(thedisplay,
311 ourscreen)-1-xszhints.width-2*BORWIDTH;
312 if (i & YNegative)
313 xszhints.y += DisplayHeight(thedisplay,
314 ourscreen)-1-xszhints.height-2*BORWIDTH;
315 }
316 }
317 /* open window */
318 i = CWEventMask|CWCursor|CWBackPixel|CWBorderPixel;
319 ourwinattr.border_pixel = ourwhite;
320 ourwinattr.background_pixel = ourblack;
321 if (ourvis.visual != DefaultVisual(thedisplay,ourscreen)) {
322 ourwinattr.colormap = newcmap(thedisplay, ourscreen, ourvis.visual);
323 i |= CWColormap;
324 }
325 ourwinattr.event_mask = ExposureMask|KeyPressMask|ButtonPressMask|
326 ButtonReleaseMask|ButtonMotionMask|StructureNotifyMask;
327 ourwinattr.cursor = XCreateFontCursor(thedisplay, XC_diamond_cross);
328 wind = XCreateWindow(thedisplay, ourroot, xszhints.x, xszhints.y,
329 xszhints.width, xszhints.height, BORWIDTH,
330 ourvis.depth, InputOutput, ourvis.visual,
331 i, &ourwinattr);
332 if (wind == 0)
333 quiterr("cannot create window");
334 width = xmax;
335 height = ymax;
336 /* prepare graphics drawing context */
337 if ((xgcv.font = XLoadFont(thedisplay, FONTNAME)) == 0)
338 quiterr("cannot get font");
339 xgcv.foreground = ourblack;
340 xgcv.background = ourwhite;
341 ourgc = XCreateGC(thedisplay, wind, GCForeground|GCBackground|
342 GCFont, &xgcv);
343 xgcv.function = GXinvert;
344 revgc = XCreateGC(thedisplay, wind, GCForeground|GCBackground|
345 GCFunction, &xgcv);
346
347 /* set up the window manager */
348 xwmhints.flags = InputHint|IconPixmapHint;
349 xwmhints.input = True;
350 xwmhints.icon_pixmap = XCreateBitmapFromData(thedisplay,
351 wind, icondata, iconwidth, iconheight);
352
353 windowName.encoding = iconName.encoding = XA_STRING;
354 windowName.format = iconName.format = 8;
355 windowName.value = (u_char *)name;
356 windowName.nitems = strlen(windowName.value);
357 iconName.value = (u_char *)name;
358 iconName.nitems = strlen(windowName.value);
359
360 xclshints.res_name = NULL;
361 xclshints.res_class = "Ximage";
362 XSetWMProperties(thedisplay, wind, &windowName, &iconName,
363 argv, argc, &xszhints, &xwmhints, &xclshints);
364 closedownAtom = XInternAtom(thedisplay, "WM_DELETE_WINDOW", False);
365 wmProtocolsAtom = XInternAtom(thedisplay, "WM_PROTOCOLS", False);
366 XSetWMProtocols(thedisplay, wind, &closedownAtom, 1);
367
368 XMapWindow(thedisplay, wind);
369 } /* end of init */
370
371
372 quiterr(err) /* print message and exit */
373 char *err;
374 {
375 register int es;
376 int cs;
377
378 if (es = err != NULL)
379 fprintf(stderr, "%s: %s: %s\n", progname,
380 fname==NULL?"<stdin>":fname, err);
381 if (thedisplay != NULL)
382 XCloseDisplay(thedisplay);
383 if (parent < 0 & sigrecv == 0)
384 kill(getppid(), SIGCONT);
385 while (parent > 0 && wait(&cs) != -1) { /* wait for any children */
386 if (es == 0)
387 es = cs>>8 & 0xff;
388 parent--;
389 }
390 exit(es);
391 }
392
393
394 static int
395 viscmp(v1,v2) /* compare visual to see which is better, descending */
396 register XVisualInfo *v1, *v2;
397 {
398 int bad1 = 0, bad2 = 0;
399 register int *rp;
400
401 if (v1->class == v2->class) {
402 if (v1->class == TrueColor || v1->class == DirectColor) {
403 /* prefer 24-bit to 32-bit */
404 if (v1->depth == 24 && v2->depth == 32)
405 return(-1);
406 if (v1->depth == 32 && v2->depth == 24)
407 return(1);
408 return(0);
409 }
410 /* don't be too greedy */
411 if (maxcolors <= 1<<v1->depth && maxcolors <= 1<<v2->depth)
412 return(v1->depth - v2->depth);
413 return(v2->depth - v1->depth);
414 }
415 /* prefer Pseudo when < 24-bit */
416 if ((v1->class == TrueColor || v1->class == DirectColor) &&
417 v1->depth < 24)
418 bad1 = 1;
419 if ((v2->class == TrueColor || v2->class == DirectColor) &&
420 v2->depth < 24)
421 bad2 = -1;
422 if (bad1 | bad2)
423 return(bad1+bad2);
424 /* otherwise, use class ranking */
425 for (rp = ourrank; *rp != -1; rp++) {
426 if (v1->class == *rp)
427 return(-1);
428 if (v2->class == *rp)
429 return(1);
430 }
431 return(0);
432 }
433
434
435 getbestvis() /* get the best visual for this screen */
436 {
437 #ifdef DEBUG
438 static char vistype[][12] = {
439 "StaticGray",
440 "GrayScale",
441 "StaticColor",
442 "PseudoColor",
443 "TrueColor",
444 "DirectColor"
445 };
446 #endif
447 static int rankings[3][6] = {
448 {TrueColor,DirectColor,PseudoColor,GrayScale,StaticGray,-1},
449 {PseudoColor,GrayScale,StaticGray,-1},
450 {PseudoColor,GrayScale,StaticGray,-1}
451 };
452 XVisualInfo *xvi;
453 int vismatched;
454 register int i, j;
455
456 if (greyscale) {
457 ourrank = rankings[2];
458 if (maxcolors < 2) maxcolors = 256;
459 } else if (maxcolors >= 2 && maxcolors <= 256)
460 ourrank = rankings[1];
461 else {
462 ourrank = rankings[0];
463 maxcolors = 256;
464 }
465 /* find best visual */
466 ourvis.screen = ourscreen;
467 xvi = XGetVisualInfo(thedisplay,VisualScreenMask,&ourvis,&vismatched);
468 if (xvi == NULL)
469 quiterr("no visuals for this screen!");
470 #ifdef DEBUG
471 fprintf(stderr, "Supported visuals:\n");
472 for (i = 0; i < vismatched; i++)
473 fprintf(stderr, "\ttype %s, depth %d\n",
474 vistype[xvi[i].class], xvi[i].depth);
475 #endif
476 for (i = 0, j = 1; j < vismatched; j++)
477 if (viscmp(&xvi[i],&xvi[j]) > 0)
478 i = j;
479 /* compare to least acceptable */
480 for (j = 0; ourrank[j++] != -1; )
481 ;
482 ourvis.class = ourrank[--j];
483 ourvis.depth = 1;
484 if (viscmp(&xvi[i],&ourvis) > 0)
485 quiterr("inadequate visuals on this screen");
486 /* OK, we'll use it */
487 copystruct(&ourvis, &xvi[i]);
488 #ifdef DEBUG
489 fprintf(stderr, "Selected visual type %s, depth %d\n",
490 vistype[ourvis.class], ourvis.depth);
491 #endif
492 /* make appropriate adjustments */
493 if (ourvis.class == GrayScale || ourvis.class == StaticGray)
494 greyscale = 1;
495 if (ourvis.depth <= 8 && ourvis.colormap_size < maxcolors)
496 maxcolors = ourvis.colormap_size;
497 if (ourvis.class == StaticGray) {
498 ourblack = 0;
499 ourwhite = 255;
500 } else if (ourvis.class == PseudoColor) {
501 ourblack = BlackPixel(thedisplay,ourscreen);
502 ourwhite = WhitePixel(thedisplay,ourscreen);
503 if ((ourblack|ourwhite) & ~255L) {
504 ourblack = 0;
505 ourwhite = 1;
506 }
507 if (maxcolors > 4)
508 maxcolors -= 2;
509 } else {
510 ourblack = 0;
511 ourwhite = ourvis.red_mask|ourvis.green_mask|ourvis.blue_mask;
512 }
513 XFree((char *)xvi);
514 }
515
516
517 getras() /* get raster file */
518 {
519 XVisualInfo vinfo;
520
521 if (maxcolors <= 2) { /* monochrome */
522 ourdata = (unsigned char *)malloc(ymax*((xmax+7)/8));
523 if (ourdata == NULL)
524 goto fail;
525 ourras = make_raster(thedisplay, &ourvis, 1, ourdata,
526 xmax, ymax, 8);
527 if (ourras == NULL)
528 goto fail;
529 getmono();
530 } else if (ourvis.class == TrueColor | ourvis.class == DirectColor) {
531 ourdata = (unsigned char *)malloc(sizeof(int4)*xmax*ymax);
532 if (ourdata == NULL)
533 goto fail;
534 ourras = make_raster(thedisplay, &ourvis, sizeof(int4)*8,
535 ourdata, xmax, ymax, 32);
536 if (ourras == NULL)
537 goto fail;
538 getfull();
539 } else {
540 ourdata = (unsigned char *)malloc(xmax*ymax);
541 if (ourdata == NULL)
542 goto fail;
543 ourras = make_raster(thedisplay, &ourvis, 8, ourdata,
544 xmax, ymax, 8);
545 if (ourras == NULL)
546 goto fail;
547 if (greyscale | ourvis.class == StaticGray)
548 getgrey();
549 else
550 getmapped();
551 if (ourvis.class != StaticGray && !init_rcolors(ourras,clrtab))
552 goto fail;
553 }
554 return;
555 fail:
556 quiterr("could not create raster image");
557 }
558
559
560 getevent() /* process the next event */
561 {
562 XEvent xev;
563
564 XNextEvent(thedisplay, &xev);
565 switch ((int)xev.type) {
566 case KeyPress:
567 docom(&xev.xkey);
568 break;
569 case ConfigureNotify:
570 width = xev.xconfigure.width;
571 height = xev.xconfigure.height;
572 break;
573 case MapNotify:
574 map_rcolors(ourras, wind);
575 if (fast)
576 make_rpixmap(ourras, wind);
577 if (!sequential & parent < 0 & sigrecv == 0) {
578 kill(getppid(), SIGCONT);
579 sigrecv--;
580 }
581 break;
582 case UnmapNotify:
583 if (!fast)
584 unmap_rcolors(ourras);
585 break;
586 case Expose:
587 redraw(xev.xexpose.x, xev.xexpose.y,
588 xev.xexpose.width, xev.xexpose.height);
589 break;
590 case ButtonPress:
591 if (xev.xbutton.state & (ShiftMask|ControlMask))
592 moveimage(&xev.xbutton);
593 else
594 switch (xev.xbutton.button) {
595 case Button1:
596 getbox(&xev.xbutton);
597 break;
598 case Button2:
599 traceray(xev.xbutton.x, xev.xbutton.y);
600 break;
601 case Button3:
602 trackrays(&xev.xbutton);
603 break;
604 }
605 break;
606 case ClientMessage:
607 if ((xev.xclient.message_type == wmProtocolsAtom) &&
608 (xev.xclient.data.l[0] == closedownAtom))
609 quiterr(NULL);
610 break;
611 }
612 }
613
614
615 traceray(xpos, ypos) /* print requested pixel data */
616 int xpos, ypos;
617 {
618 extern char *index();
619 FLOAT hv[2];
620 FVECT rorg, rdir;
621 COLOR cval;
622 register char *cp;
623
624 box.xmin = xpos; box.xsiz = 1;
625 box.ymin = ypos; box.ysiz = 1;
626 avgbox(cval);
627 scalecolor(cval, 1./exposure);
628 pix2loc(hv, &inpres, xpos-xoff, ypos-yoff);
629 if (!gotview || viewray(rorg, rdir, &ourview, hv[0], hv[1]) < 0)
630 rorg[0] = rorg[1] = rorg[2] =
631 rdir[0] = rdir[1] = rdir[2] = 0.;
632
633 for (cp = tout; *cp; cp++) /* print what they asked for */
634 switch (*cp) {
635 case 'o': /* origin */
636 printf("%e %e %e ", rorg[0], rorg[1], rorg[2]);
637 break;
638 case 'd': /* direction */
639 printf("%e %e %e ", rdir[0], rdir[1], rdir[2]);
640 break;
641 case 'v': /* radiance value */
642 printf("%e %e %e ", colval(cval,RED),
643 colval(cval,GRN), colval(cval,BLU));
644 break;
645 case 'l': /* luminance */
646 printf("%e ", luminance(cval));
647 break;
648 case 'p': /* pixel position */
649 printf("%d %d ", (int)(hv[0]*inpres.xr),
650 (int)(hv[1]*inpres.yr));
651 break;
652 }
653 putchar('\n');
654 fflush(stdout);
655 return(0);
656 }
657
658
659 docom(ekey) /* execute command */
660 XKeyPressedEvent *ekey;
661 {
662 char buf[80];
663 COLOR cval;
664 XColor cvx;
665 int com, n;
666 double comp;
667 FLOAT hv[2];
668
669 n = XLookupString(ekey, buf, sizeof(buf), NULL, NULL);
670 if (n == 0)
671 return(0);
672 com = buf[0];
673 switch (com) { /* interpret command */
674 case 'q':
675 case 'Q':
676 case CTRL('D'): /* quit */
677 quiterr(NULL);
678 case '\n':
679 case '\r':
680 case 'l':
681 case 'c': /* value */
682 if (avgbox(cval) == -1)
683 return(-1);
684 switch (com) {
685 case '\n':
686 case '\r': /* radiance */
687 sprintf(buf, "%.3f", intens(cval)/exposure);
688 break;
689 case 'l': /* luminance */
690 sprintf(buf, "%.0fL", luminance(cval)/exposure);
691 break;
692 case 'c': /* color */
693 comp = pow(2.0, (double)scale);
694 sprintf(buf, "(%.2f,%.2f,%.2f)",
695 colval(cval,RED)*comp,
696 colval(cval,GRN)*comp,
697 colval(cval,BLU)*comp);
698 break;
699 }
700 XDrawImageString(thedisplay, wind, ourgc,
701 box.xmin, box.ymin+box.ysiz, buf, strlen(buf));
702 return(0);
703 case 'i': /* identify (contour) */
704 if (ourras->pixels == NULL)
705 return(-1);
706 n = ourdata[ekey->x-xoff+xmax*(ekey->y-yoff)];
707 n = ourras->pmap[n];
708 cvx.pixel = ourras->cdefs[n].pixel;
709 cvx.red = random() & 65535;
710 cvx.green = random() & 65535;
711 cvx.blue = random() & 65535;
712 cvx.flags = DoRed|DoGreen|DoBlue;
713 XStoreColor(thedisplay, ourras->cmap, &cvx);
714 return(0);
715 case 'p': /* position */
716 pix2loc(hv, &inpres, ekey->x-xoff, ekey->y-yoff);
717 sprintf(buf, "(%d,%d)", (int)(hv[0]*inpres.xr),
718 (int)(hv[1]*inpres.yr));
719 XDrawImageString(thedisplay, wind, ourgc, ekey->x, ekey->y,
720 buf, strlen(buf));
721 return(0);
722 case 't': /* trace */
723 return(traceray(ekey->x, ekey->y));
724 case '=': /* adjust exposure */
725 case '@': /* adaptation level */
726 if (avgbox(cval) == -1)
727 return(-1);
728 comp = bright(cval);
729 if (comp < 1e-20) {
730 XBell(thedisplay, 0);
731 return(-1);
732 }
733 if (com == '@')
734 comp = 106./exposure/
735 pow(1.219+pow(comp*WHTEFFICACY/exposure,.4),2.5);
736 else
737 comp = .5/comp;
738 comp = log(comp)/.69315 - scale;
739 n = comp < 0 ? comp-.5 : comp+.5 ; /* round */
740 if (n == 0)
741 return(0);
742 scale_rcolors(ourras, pow(2.0, (double)n));
743 scale += n;
744 sprintf(buf, "%+d", scale);
745 XDrawImageString(thedisplay, wind, ourgc,
746 box.xmin, box.ymin+box.ysiz, buf, strlen(buf));
747 XFlush(thedisplay);
748 free(ourdata);
749 free_raster(ourras);
750 getras();
751 /* fall through */
752 case CTRL('R'): /* redraw */
753 case CTRL('L'):
754 unmap_rcolors(ourras);
755 XClearWindow(thedisplay, wind);
756 map_rcolors(ourras, wind);
757 if (fast)
758 make_rpixmap(ourras, wind);
759 redraw(0, 0, width, height);
760 return(0);
761 case 'f': /* turn on fast redraw */
762 fast = 1;
763 make_rpixmap(ourras, wind);
764 return(0);
765 case 'F': /* turn off fast redraw */
766 fast = 0;
767 free_rpixmap(ourras);
768 return(0);
769 case '0': /* recenter origin */
770 if (xoff == 0 & yoff == 0)
771 return(0);
772 xoff = yoff = 0;
773 XClearWindow(thedisplay, wind);
774 redraw(0, 0, width, height);
775 return(0);
776 case ' ': /* clear */
777 redraw(box.xmin, box.ymin, box.xsiz, box.ysiz);
778 return(0);
779 default:
780 XBell(thedisplay, 0);
781 return(-1);
782 }
783 }
784
785
786 moveimage(ebut) /* shift the image */
787 XButtonPressedEvent *ebut;
788 {
789 XEvent e;
790 int mxo, myo;
791
792 XMaskEvent(thedisplay, ButtonReleaseMask|ButtonMotionMask, &e);
793 while (e.type == MotionNotify) {
794 mxo = e.xmotion.x;
795 myo = e.xmotion.y;
796 revline(ebut->x, ebut->y, mxo, myo);
797 revbox(xoff+mxo-ebut->x, yoff+myo-ebut->y,
798 xoff+mxo-ebut->x+xmax, yoff+myo-ebut->y+ymax);
799 XMaskEvent(thedisplay,ButtonReleaseMask|ButtonMotionMask,&e);
800 revline(ebut->x, ebut->y, mxo, myo);
801 revbox(xoff+mxo-ebut->x, yoff+myo-ebut->y,
802 xoff+mxo-ebut->x+xmax, yoff+myo-ebut->y+ymax);
803 }
804 xoff += e.xbutton.x - ebut->x;
805 yoff += e.xbutton.y - ebut->y;
806 XClearWindow(thedisplay, wind);
807 redraw(0, 0, width, height);
808 }
809
810
811 getbox(ebut) /* get new box */
812 XButtonPressedEvent *ebut;
813 {
814 XEvent e;
815
816 XMaskEvent(thedisplay, ButtonReleaseMask|ButtonMotionMask, &e);
817 while (e.type == MotionNotify) {
818 revbox(ebut->x, ebut->y, box.xmin = e.xmotion.x, box.ymin = e.xmotion.y);
819 XMaskEvent(thedisplay,ButtonReleaseMask|ButtonMotionMask,&e);
820 revbox(ebut->x, ebut->y, box.xmin, box.ymin);
821 }
822 box.xmin = e.xbutton.x<0 ? 0 : (e.xbutton.x>=width ? width-1 : e.xbutton.x);
823 box.ymin = e.xbutton.y<0 ? 0 : (e.xbutton.y>=height ? height-1 : e.xbutton.y);
824 if (box.xmin > ebut->x) {
825 box.xsiz = box.xmin - ebut->x + 1;
826 box.xmin = ebut->x;
827 } else {
828 box.xsiz = ebut->x - box.xmin + 1;
829 }
830 if (box.ymin > ebut->y) {
831 box.ysiz = box.ymin - ebut->y + 1;
832 box.ymin = ebut->y;
833 } else {
834 box.ysiz = ebut->y - box.ymin + 1;
835 }
836 }
837
838
839 trackrays(ebut) /* trace rays as mouse moves */
840 XButtonPressedEvent *ebut;
841 {
842 XEvent e;
843 unsigned long lastrept;
844
845 traceray(ebut->x, ebut->y);
846 lastrept = ebut->time;
847 XMaskEvent(thedisplay, ButtonReleaseMask|ButtonMotionMask, &e);
848 while (e.type == MotionNotify) {
849 if (e.xmotion.time >= lastrept + tinterv) {
850 traceray(e.xmotion.x, e.xmotion.y);
851 lastrept = e.xmotion.time;
852 }
853 XMaskEvent(thedisplay,ButtonReleaseMask|ButtonMotionMask,&e);
854 }
855 }
856
857
858 revbox(x0, y0, x1, y1) /* draw box with reversed lines */
859 int x0, y0, x1, y1;
860 {
861 revline(x0, y0, x1, y0);
862 revline(x0, y1, x1, y1);
863 revline(x0, y0, x0, y1);
864 revline(x1, y0, x1, y1);
865 }
866
867
868 avgbox(clr) /* average color over current box */
869 COLOR clr;
870 {
871 static COLOR lc;
872 static int ll, lr, lt, lb;
873 int left, right, top, bottom;
874 int y;
875 double d;
876 COLOR ctmp;
877 register int x;
878
879 setcolor(clr, 0.0, 0.0, 0.0);
880 left = box.xmin - xoff;
881 right = left + box.xsiz;
882 if (left < 0)
883 left = 0;
884 if (right > xmax)
885 right = xmax;
886 if (left >= right)
887 return(-1);
888 top = box.ymin - yoff;
889 bottom = top + box.ysiz;
890 if (top < 0)
891 top = 0;
892 if (bottom > ymax)
893 bottom = ymax;
894 if (top >= bottom)
895 return(-1);
896 if (left == ll && right == lr && top == lt && bottom == lb) {
897 copycolor(clr, lc);
898 return(0);
899 }
900 for (y = top; y < bottom; y++) {
901 if (getscan(y) == -1)
902 return(-1);
903 for (x = left; x < right; x++) {
904 colr_color(ctmp, scanline[x]);
905 addcolor(clr, ctmp);
906 }
907 }
908 d = 1.0/((right-left)*(bottom-top));
909 scalecolor(clr, d);
910 ll = left; lr = right; lt = top; lb = bottom;
911 copycolor(lc, clr);
912 return(0);
913 }
914
915
916 getmono() /* get monochrome data */
917 {
918 register unsigned char *dp;
919 register int x, err;
920 int y, errp;
921 short *cerr;
922
923 if ((cerr = (short *)calloc(xmax,sizeof(short))) == NULL)
924 quiterr("out of memory in getmono");
925 dp = ourdata - 1;
926 for (y = 0; y < ymax; y++) {
927 getscan(y);
928 add2icon(y, scanline);
929 normcolrs(scanline, xmax, scale);
930 err = 0;
931 for (x = 0; x < xmax; x++) {
932 if (!(x&7))
933 *++dp = 0;
934 errp = err;
935 err += normbright(scanline[x]) + cerr[x];
936 if (err > 127)
937 err -= 255;
938 else
939 *dp |= 1<<(7-(x&07));
940 err /= 3;
941 cerr[x] = err + errp;
942 }
943 }
944 free((char *)cerr);
945 }
946
947
948 add2icon(y, scan) /* add a scanline to our icon data */
949 int y;
950 COLR *scan;
951 {
952 static short cerr[ICONSIZ];
953 static int ynext;
954 static char *dp;
955 COLR clr;
956 register int err;
957 register int x, ti;
958 int errp;
959
960 if (iconheight == 0) { /* initialize */
961 if (xmax <= ICONSIZ && ymax <= ICONSIZ) {
962 iconwidth = xmax;
963 iconheight = ymax;
964 } else if (xmax > ymax) {
965 iconwidth = ICONSIZ;
966 iconheight = ICONSIZ*ymax/xmax;
967 if (iconheight < 1)
968 iconheight = 1;
969 } else {
970 iconwidth = ICONSIZ*xmax/ymax;
971 if (iconwidth < 1)
972 iconwidth = 1;
973 iconheight = ICONSIZ;
974 }
975 ynext = 0;
976 dp = icondata - 1;
977 }
978 if (y < ynext*ymax/iconheight) /* skip this one */
979 return;
980 err = 0;
981 for (x = 0; x < iconwidth; x++) {
982 if (!(x&7))
983 *++dp = 0;
984 errp = err;
985 ti = x*xmax/iconwidth;
986 copycolr(clr, scan[ti]);
987 normcolrs(clr, 1, scale);
988 err += normbright(clr) + cerr[x];
989 if (err > 127)
990 err -= 255;
991 else
992 *dp |= 1<<(x&07);
993 err /= 3;
994 cerr[x] = err + errp;
995 }
996 ynext++;
997 }
998
999
1000 getfull() /* get full (24-bit) data */
1001 {
1002 int y;
1003 register unsigned int4 *dp;
1004 register int x;
1005 /* set gamma correction */
1006 setcolrgam(gamcor);
1007 /* read and convert file */
1008 dp = (unsigned int4 *)ourdata;
1009 for (y = 0; y < ymax; y++) {
1010 getscan(y);
1011 add2icon(y, scanline);
1012 if (scale)
1013 shiftcolrs(scanline, xmax, scale);
1014 colrs_gambs(scanline, xmax);
1015 if (ourras->image->blue_mask & 1)
1016 for (x = 0; x < xmax; x++)
1017 *dp++ = (unsigned int4)scanline[x][RED] << 16 |
1018 (unsigned int4)scanline[x][GRN] << 8 |
1019 (unsigned int4)scanline[x][BLU] ;
1020 else
1021 for (x = 0; x < xmax; x++)
1022 *dp++ = (unsigned int4)scanline[x][RED] |
1023 (unsigned int4)scanline[x][GRN] << 8 |
1024 (unsigned int4)scanline[x][BLU] << 16 ;
1025 }
1026 }
1027
1028
1029 getgrey() /* get greyscale data */
1030 {
1031 int y;
1032 register unsigned char *dp;
1033 register int x;
1034 /* set gamma correction */
1035 setcolrgam(gamcor);
1036 /* read and convert file */
1037 dp = ourdata;
1038 for (y = 0; y < ymax; y++) {
1039 getscan(y);
1040 add2icon(y, scanline);
1041 if (scale)
1042 shiftcolrs(scanline, xmax, scale);
1043 for (x = 0; x < xmax; x++)
1044 scanline[x][GRN] = normbright(scanline[x]);
1045 colrs_gambs(scanline, xmax);
1046 if (maxcolors < 256)
1047 for (x = 0; x < xmax; x++)
1048 *dp++ = ((long)scanline[x][GRN] *
1049 maxcolors + maxcolors/2) >> 8;
1050 else
1051 for (x = 0; x < xmax; x++)
1052 *dp++ = scanline[x][GRN];
1053 }
1054 for (x = 0; x < maxcolors; x++)
1055 clrtab[x][RED] = clrtab[x][GRN] =
1056 clrtab[x][BLU] = ((long)x*256 + 128)/maxcolors;
1057 }
1058
1059
1060 getmapped() /* get color-mapped data */
1061 {
1062 int y;
1063 /* make sure we can do it first */
1064 if (fname == NULL)
1065 quiterr("cannot map colors from standard input");
1066 /* set gamma correction */
1067 setcolrgam(gamcor);
1068 /* make histogram */
1069 if (new_histo((long)xmax*ymax) == -1)
1070 quiterr("cannot initialize histogram");
1071 for (y = 0; y < ymax; y++) {
1072 if (getscan(y) < 0)
1073 break;
1074 add2icon(y, scanline);
1075 if (scale)
1076 shiftcolrs(scanline, xmax, scale);
1077 colrs_gambs(scanline, xmax);
1078 cnt_colrs(scanline, xmax);
1079 }
1080 /* map pixels */
1081 if (!new_clrtab(maxcolors))
1082 quiterr("cannot create color map");
1083 for (y = 0; y < ymax; y++) {
1084 getscan(y);
1085 if (scale)
1086 shiftcolrs(scanline, xmax, scale);
1087 colrs_gambs(scanline, xmax);
1088 if (dither)
1089 dith_colrs(ourdata+y*xmax, scanline, xmax);
1090 else
1091 map_colrs(ourdata+y*xmax, scanline, xmax);
1092 }
1093 }
1094
1095
1096 scale_rcolors(xr, sf) /* scale color map */
1097 register XRASTER *xr;
1098 double sf;
1099 {
1100 register int i;
1101 long maxv;
1102
1103 if (xr->pixels == NULL)
1104 return;
1105
1106 sf = pow(sf, 1.0/gamcor);
1107 maxv = 65535/sf;
1108
1109 for (i = xr->ncolors; i--; ) {
1110 xr->cdefs[i].red = xr->cdefs[i].red > maxv ?
1111 65535 :
1112 xr->cdefs[i].red * sf;
1113 xr->cdefs[i].green = xr->cdefs[i].green > maxv ?
1114 65535 :
1115 xr->cdefs[i].green * sf;
1116 xr->cdefs[i].blue = xr->cdefs[i].blue > maxv ?
1117 65535 :
1118 xr->cdefs[i].blue * sf;
1119 }
1120 XStoreColors(thedisplay, xr->cmap, xr->cdefs, xr->ncolors);
1121 }
1122
1123
1124 getscan(y)
1125 int y;
1126 {
1127 static int trunced = -1; /* truncated file? */
1128 skipit:
1129 if (trunced >= 0 && y >= trunced) {
1130 bzero(scanline, xmax*sizeof(COLR));
1131 return(-1);
1132 }
1133 if (y != cury) {
1134 if (scanpos == NULL || scanpos[y] == -1)
1135 return(-1);
1136 if (fseek(fin, scanpos[y], 0) == -1)
1137 quiterr("fseek error");
1138 cury = y;
1139 } else if (scanpos != NULL && scanpos[y] == -1)
1140 scanpos[y] = ftell(fin);
1141
1142 if (freadcolrs(scanline, xmax, fin) < 0) {
1143 fprintf(stderr, "%s: %s: unfinished picture\n",
1144 progname, fname==NULL?"<stdin>":fname);
1145 trunced = y;
1146 goto skipit;
1147 }
1148 cury++;
1149 return(0);
1150 }