ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/x11image.c
Revision: 2.29
Committed: Wed Oct 27 13:03:18 1993 UTC (30 years, 6 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.28: +36 -9 lines
Log Message:
added forking for multiple pictures

File Contents

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