ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/x11image.c
Revision: 2.42
Committed: Wed Dec 13 09:52:38 1995 UTC (28 years, 4 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.41: +46 -17 lines
Log Message:
added -o option to control output of 't' command

File Contents

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