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

File Contents

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