--- ray/src/px/x11image.c 1997/04/15 16:53:58 2.44 +++ ray/src/px/x11image.c 1999/07/20 14:07:38 2.55 @@ -1,7 +1,7 @@ -/* Copyright (c) 1997 Regents of the University of California */ +/* Copyright (c) 1999 Regents of the University of California */ #ifndef lint -static char SCCSid[] = "$SunId$ LBL"; +static char SCCSid[] = "$SunId$ SGI"; #endif /* @@ -27,16 +27,15 @@ static char SCCSid[] = "$SunId$ LBL"; #include #include +#undef NOPROTO +#define NOPROTO 1 +#include "color.h" #include "tonemap.h" #include "view.h" #include "x11raster.h" #include "random.h" #include "resolu.h" -#ifndef int4 -#define int4 int /* most int's are 32-bit */ -#endif - #define FONTNAME "8x13" /* text font we'll use */ #define CTRL(c) ((c)-'@') @@ -45,6 +44,8 @@ static char SCCSid[] = "$SunId$ LBL"; #define ICONSIZ (8*10) /* maximum icon dimension (even 8) */ +#define FIXWEIGHT 20 /* weight to add for fixation points */ + #define ourscreen DefaultScreen(thedisplay) #define ourroot RootWindow(thedisplay,ourscreen) @@ -76,7 +77,7 @@ int sequential = 0; /* display images in sequence * char *tout = "od"; /* output of 't' command */ int tinterv = 0; /* interval between mouse reports */ -int tmflags = -1; /* tone mapping flags (-1 for none) */ +int tmflags = TM_F_LINEAR; /* tone mapping flags */ VIEW ourview = STDVIEW; /* image view parameters */ int gotview = 0; /* got parameters from file */ @@ -90,7 +91,7 @@ RESOLU inpres; /* input resolution and ordering */ int xmax, ymax; /* picture dimensions */ int width, height; /* window size */ char *fname = NULL; /* input file name */ -FILE *fin = stdin; /* input file */ +FILE *fin = NULL; /* input file */ long *scanpos = NULL; /* scan line positions in file */ int cury = 0; /* current scan location */ @@ -142,6 +143,7 @@ char *argv[]; int pid; progname = argv[0]; + fin = stdin; for (i = 1; i < argc; i++) if (argv[i][0] == '-') @@ -176,11 +178,11 @@ char *argv[]; break; case 'e': /* exposure comp. */ i++; - if (!strcmp(argv[i], "auto")) { + if (argv[i][0] == 'a') { tmflags = TM_F_CAMERA; break; } - if (!strcmp(argv[i], "human")) { + if (argv[i][0] == 'h') { tmflags = TM_F_HUMAN; break; } @@ -249,6 +251,7 @@ userr: } +int headline(s) /* get relevant info from header */ char *s; { @@ -260,6 +263,7 @@ char *s; wrongformat = strcmp(fmt, COLRFMT); else if (isview(s) && sscanview(&ourview, s) > 0) gotview++; + return(0); } @@ -415,19 +419,20 @@ register XVisualInfo *v1, *v2; return(-1); if (v1->depth == 32 && v2->depth == 24) return(1); - return(0); + /* go for maximum depth otherwise */ + return(v2->depth - v1->depth); } /* don't be too greedy */ if (maxcolors <= 1<depth && maxcolors <= 1<depth) return(v1->depth - v2->depth); return(v2->depth - v1->depth); } - /* prefer Pseudo when < 24-bit */ + /* prefer Pseudo when < 15-bit */ if ((v1->class == TrueColor || v1->class == DirectColor) && - v1->depth < 24) + v1->depth < 15) bad1 = 1; if ((v2->class == TrueColor || v2->class == DirectColor) && - v2->depth < 24) + v2->depth < 15) bad2 = -1; if (bad1 | bad2) return(bad1+bad2); @@ -538,11 +543,12 @@ getras() /* get raster file */ goto fail; getmono(); } else if (ourvis.class == TrueColor | ourvis.class == DirectColor) { - ourdata = (unsigned char *)malloc(sizeof(int4)*xmax*ymax); + int datsiz = ourvis.depth>16 ? sizeof(int4) : sizeof(int2); + ourdata = (unsigned char *)malloc(datsiz*xmax*ymax); if (ourdata == NULL) goto fail; - ourras = make_raster(thedisplay, &ourvis, sizeof(int4)*8, - ourdata, xmax, ymax, 32); + ourras = make_raster(thedisplay, &ourvis, datsiz*8, + ourdata, xmax, ymax, datsiz*8); if (ourras == NULL) goto fail; getfull(); @@ -689,7 +695,7 @@ XKeyPressedEvent *ekey; case '\r': case 'l': case 'c': /* value */ - if (avgbox(cval) == -1) + if (!avgbox(cval)) return(-1); switch (com) { case '\n': @@ -731,9 +737,21 @@ XKeyPressedEvent *ekey; return(0); case 't': /* trace */ return(traceray(ekey->x, ekey->y)); + case 'a': /* auto exposure */ + if (fname == NULL) + return(-1); + tmflags = TM_F_CAMERA; + strcpy(buf, "auto exposure..."); + goto remap; + case 'h': /* human response */ + if (fname == NULL) + return(-1); + tmflags = TM_F_HUMAN; + strcpy(buf, "human exposure..."); + goto remap; case '=': /* adjust exposure */ case '@': /* adaptation level */ - if (avgbox(cval) == -1) + if (!avgbox(cval)) return(-1); comp = bright(cval); if (comp < 1e-20) { @@ -747,8 +765,8 @@ XKeyPressedEvent *ekey; comp = .5/comp; comp = log(comp)/.69315 - scale; n = comp < 0 ? comp-.5 : comp+.5 ; /* round */ - if (tmflags != -1) - tmflags = -1; /* turn off tone mapping */ + if (tmflags != TM_F_LINEAR) + tmflags = TM_F_LINEAR; /* turn off tone mapping */ else { if (n == 0) /* else check if any change */ return(0); @@ -756,6 +774,7 @@ XKeyPressedEvent *ekey; } scale += n; sprintf(buf, "%+d", scale); + remap: XDrawImageString(thedisplay, wind, ourgc, box.xmin, box.ymin+box.ysiz, buf, strlen(buf)); XFlush(thedisplay); @@ -879,18 +898,46 @@ int x0, y0, x1, y1; } -avgbox(clr) /* average color over current box */ -COLOR clr; +int +colavg(scn, n, cavg) +register COLR *scn; +register int n; +COLOR cavg; { - static COLOR lc; - static int ll, lr, lt, lb; + COLOR col; + + while (n--) { + colr_color(col, scn++); + addcolor(cavg, col); + } +} + + +int +avgbox(cavg) /* average color over current box */ +COLOR cavg; +{ + double d; + register int rval; + + setcolor(cavg, 0., 0., 0.); + rval = dobox(colavg, (char *)cavg); + if (rval > 0) { + d = 1./rval; + scalecolor(cavg, d); + } + return(rval); +} + + +int +dobox(f, p) /* run function over box */ +int (*f)(); /* function to call for each subscan */ +char *p; /* pointer to private data */ +{ int left, right, top, bottom; int y; - double d; - COLOR ctmp; - register int x; - setcolor(clr, 0.0, 0.0, 0.0); left = box.xmin - xoff; right = left + box.xsiz; if (left < 0) @@ -898,7 +945,7 @@ COLOR clr; if (right > xmax) right = xmax; if (left >= right) - return(-1); + return(0); top = box.ymin - yoff; bottom = top + box.ysiz; if (top < 0) @@ -906,68 +953,78 @@ COLOR clr; if (bottom > ymax) bottom = ymax; if (top >= bottom) - return(-1); - if (left == ll && right == lr && top == lt && bottom == lb) { - copycolor(clr, lc); return(0); - } for (y = top; y < bottom; y++) { if (getscan(y) == -1) return(-1); - for (x = left; x < right; x++) { - colr_color(ctmp, scanline[x]); - addcolor(clr, ctmp); - } + (*f)(scanline+left, right-left, p); } - d = 1.0/((right-left)*(bottom-top)); - scalecolor(clr, d); - ll = left; lr = right; lt = top; lb = bottom; - copycolor(lc, clr); - return(0); + return((right-left)*(bottom-top)); } +int +addfix(scn, n) /* add fixation points to histogram */ +COLR *scn; +int n; +{ + if (tmCvColrs(lscan, TM_NOCHROM, scn, n)) + goto tmerr; + if (tmAddHisto(lscan, n, FIXWEIGHT)) + goto tmerr; + return; +tmerr: + quiterr("tone mapping error"); +} + + make_tonemap() /* initialize tone mapping */ { - int y; + int flags, y; - if (tmflags != -1 && fname == NULL) { + if (tmflags != TM_F_LINEAR && fname == NULL) { fprintf(stderr, "%s: cannot adjust tone of standard input\n", progname); - tmflags = -1; + tmflags = TM_F_LINEAR; } - if (tmflags == -1) { + if (tmflags == TM_F_LINEAR) { /* linear with clamping */ setcolrcor(pow, 1.0/gamcor); return; } - if (greyscale) - tmflags |= TM_F_BW; - /* initialize tm library */ - if (tmInit(tmflags, stdprims, gamcor) == NULL) - goto memerr; - if (tmSetSpace(stdprims, WHTEFFICACY/exposure)) - goto tmerr; - /* allocate encoding buffers */ - if ((lscan = (TMbright *)malloc(xmax*sizeof(TMbright))) == NULL) - goto memerr; - if (tmflags & TM_F_BW) { - cscan = TM_NOCHROM; - if ((pscan = (BYTE *)malloc(sizeof(BYTE)*xmax)) == NULL) + flags = tmflags; /* histogram adjustment */ + if (greyscale) flags |= TM_F_BW; + if (tmTop != NULL) { /* reuse old histogram if one */ + tmDone(tmTop); + tmTop->flags = flags; + } else { /* else initialize */ + if ((lscan = (TMbright *)malloc(xmax*sizeof(TMbright))) == NULL) goto memerr; - } else if ((pscan=cscan = (BYTE *)malloc(3*sizeof(BYTE)*xmax)) == NULL) - goto memerr; - /* compute picture histogram */ - for (y = 0; y < ymax; y++) { - getscan(y); - if (tmCvColrs(lscan, TM_NOCHROM, scanline, xmax)) + if (greyscale) { + cscan = TM_NOCHROM; + if ((pscan = (BYTE *)malloc(sizeof(BYTE)*xmax)) == NULL) + goto memerr; + } else if ((pscan=cscan = (BYTE *)malloc(3*sizeof(BYTE)*xmax)) + == NULL) + goto memerr; + /* initialize tm library */ + if (tmInit(flags, stdprims, gamcor) == NULL) + goto memerr; + if (tmSetSpace(stdprims, WHTEFFICACY/exposure)) goto tmerr; - if (tmAddHisto(lscan, xmax, 1)) - goto tmerr; + /* compute picture histogram */ + for (y = 0; y < ymax; y++) { + getscan(y); + if (tmCvColrs(lscan, TM_NOCHROM, scanline, xmax)) + goto tmerr; + if (tmAddHisto(lscan, xmax, 1)) + goto tmerr; + } } - /* compute tone mapping */ + tmDup(); /* add fixations to duplicate map */ + dobox(addfix, NULL); + /* (re)compute tone mapping */ if (tmComputeMapping(gamcor, 0., 0.)) goto tmerr; - free((char *)lscan); return; memerr: quiterr("out of memory in make_tonemap"); @@ -982,7 +1039,7 @@ int len; { register BYTE *ps; - if (tmflags == -1) { + if (tmflags == TM_F_LINEAR) { if (scale) shiftcolrs(scn, len, scale); colrs_gambs(scn, len); @@ -995,7 +1052,7 @@ int len; if (tmMapPixels(pscan, lscan, cscan, len)) goto tmerr; ps = pscan; - if (tmflags & TM_F_BW) + if (greyscale) while (len--) { scn[0][RED] = scn[0][GRN] = scn[0][BLU] = *ps++; scn[0][EXP] = COLXS; @@ -1015,16 +1072,6 @@ tmerr: } -done_tonemap() /* clean up after tone mapping is done */ -{ - if (tmflags == -1 || tmTop == NULL) - return; - tmDone(tmTop); /* clear old mapping */ - free((char *)lscan); /* free memory */ - free((char *)pscan); -} - - getmono() /* get monochrome data */ { register unsigned char *dp; @@ -1113,27 +1160,66 @@ getfull() /* get full (24-bit) data */ { int y; register unsigned int4 *dp; + register unsigned int2 *dph; register int x; /* initialize tone mapping */ make_tonemap(); /* read and convert file */ dp = (unsigned int4 *)ourdata; + dph = (unsigned int2 *)ourdata; for (y = 0; y < ymax; y++) { getscan(y); add2icon(y, scanline); tmap_colrs(scanline, xmax); - if (ourras->image->blue_mask & 1) + switch (ourras->image->blue_mask) { + case 0xff: /* 24-bit RGB */ for (x = 0; x < xmax; x++) *dp++ = (unsigned int4)scanline[x][RED] << 16 | (unsigned int4)scanline[x][GRN] << 8 | (unsigned int4)scanline[x][BLU] ; - else + break; + case 0xff0000: /* 24-bit BGR */ for (x = 0; x < xmax; x++) *dp++ = (unsigned int4)scanline[x][RED] | (unsigned int4)scanline[x][GRN] << 8 | (unsigned int4)scanline[x][BLU] << 16 ; + break; +#if 0 + case 0x1f: /* 15-bit RGB */ + for (x = 0; x < xmax; x++) + *dph++ = (scanline[x][RED] << 7 & 0x7c00) | + (scanline[x][GRN] << 2 & 0x3e0) | + (unsigned)scanline[x][BLU] >> 3 ; + break; + case 0x7c00: /* 15-bit BGR */ + for (x = 0; x < xmax; x++) + *dph++ = (unsigned)scanline[x][RED] >> 3 | + (scanline[x][GRN] << 2 & 0x3e0) | + (scanline[x][BLU] << 7 & 0x7c00) ; + break; +#endif + default: /* unknown */ + if (ourvis.depth > 16) + for (x = 0; x < xmax; x++) { + *dp = ourras->image->red_mask & + ourras->image->red_mask*scanline[x][RED]/255; + *dp |= ourras->image->green_mask & + ourras->image->green_mask*scanline[x][GRN]/255; + *dp++ |= ourras->image->blue_mask & + ourras->image->blue_mask*scanline[x][BLU]/255; + } + else + for (x = 0; x < xmax; x++) { + *dph = ourras->image->red_mask & + ourras->image->red_mask*scanline[x][RED]/255; + *dph |= ourras->image->green_mask & + ourras->image->green_mask*scanline[x][GRN]/255; + *dph++ |= ourras->image->blue_mask & + ourras->image->blue_mask*scanline[x][BLU]/255; + } + break; + } } - done_tonemap(); } @@ -1161,7 +1247,6 @@ getgrey() /* get greyscale data */ for (x = 0; x < maxcolors; x++) clrtab[x][RED] = clrtab[x][GRN] = clrtab[x][BLU] = ((int4)x*256 + 128)/maxcolors; - done_tonemap(); } @@ -1194,7 +1279,6 @@ getmapped() /* get color-mapped data */ else map_colrs(ourdata+y*xmax, scanline, xmax); } - done_tonemap(); }