Back to index

radiance  4R0+20100331
x11image.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char RCSid[] = "$Id: x11image.c,v 2.73 2008/11/10 19:08:19 greg Exp $";
00003 #endif
00004 /*
00005  *  x11image.c - driver for X-windows
00006  *
00007  *     3/1/90
00008  */
00009 
00010 /*
00011  *  Modified for X11
00012  *
00013  *  January 1990
00014  *
00015  *  Anat Grynberg  and Greg Ward
00016  */
00017 
00018 
00019 #include  "standard.h"
00020 
00021 #include  <string.h>
00022 #include  <signal.h>
00023 #include  <unistd.h>
00024 #include  <sys/types.h>
00025 #include  <sys/wait.h>
00026 #include  <X11/Xlib.h>
00027 #include  <X11/cursorfont.h>
00028 #include  <X11/Xutil.h>
00029 #include  <X11/Xatom.h>
00030 
00031 #include  "color.h"
00032 #include  "tonemap.h"
00033 #include  "clrtab.h"
00034 #include  "view.h"
00035 #include  "x11raster.h"
00036 #include  "random.h"
00037 
00038 #define  FONTNAME    "8x13"        /* text font we'll use */
00039 
00040 #define  CTRL(c)     ((c)-'@')
00041 
00042 #define  BORWIDTH    5             /* border width */
00043 
00044 #define  ICONSIZ     (8*10)        /* maximum icon dimension (even 8) */
00045 
00046 #define  FIXWEIGHT   20            /* weight to add for fixation points */
00047 
00048 #define  ourscreen   DefaultScreen(thedisplay)
00049 #define  ourroot     RootWindow(thedisplay,ourscreen)
00050 
00051 #define  revline(x0,y0,x1,y1)      XDrawLine(thedisplay,wind,revgc,x0,y0,x1,y1)
00052 
00053 #define  redraw(x,y,w,h) patch_raster(wind,(x)-xoff,(y)-yoff,x,y,w,h,ourras)
00054 
00055 double  gamcor = 2.2;                     /* gamma correction */
00056 char  *gamstr = NULL;                     /* gamma value override */
00057 
00058 int  dither = 1;                   /* dither colors? */
00059 int  fast = 0;                            /* keep picture in Pixmap? */
00060 
00061 char   *dispname = NULL;           /* our display name */
00062 
00063 Window  wind = 0;                  /* our output window */
00064 unsigned long  ourblack=0, ourwhite=1;    /* black and white for this visual */
00065 int  maxcolors = 0;                /* maximum colors */
00066 int  greyscale = 0;                /* in grey */
00067 
00068 int  scale = 0;                           /* scalefactor; power of two */
00069 
00070 int  xoff = 0;                            /* x image offset */
00071 int  yoff = 0;                            /* y image offset */
00072 
00073 int  parent = 0;                   /* number of children, -1 if child */
00074 int  sequential = 0;               /* display images in sequence */
00075 
00076 char  *tout = "od";                /* output of 't' command */
00077 int  tinterv = 0;                  /* interval between mouse reports */
00078 
00079 int  tmflags = TM_F_LINEAR;        /* tone mapping flags */
00080 
00081 VIEW  ourview = STDVIEW;           /* image view parameters */
00082 int  gotview = 0;                  /* got parameters from file */
00083 
00084 COLR  *scanline;                   /* scan line buffer */
00085 TMbright  *lscan;                  /* encoded luminance scanline */
00086 BYTE  *cscan;                      /* encoded chroma scanline */
00087 BYTE  *pscan;                      /* compute pixel scanline */
00088 
00089 RESOLU  inpres;                           /* input resolution and ordering */
00090 int  xmax, ymax;                   /* picture dimensions */
00091 int  width, height;                /* window size */
00092 char  *fname = NULL;               /* input file name */
00093 FILE  *fin = NULL;                 /* input file */
00094 long  *scanpos = NULL;                    /* scan line positions in file */
00095 int  cury = 0;                            /* current scan location */
00096 
00097 double  exposure = 1.0;                   /* exposure compensation used */
00098 
00099 int  wrongformat = 0;                     /* input in another format? */
00100 
00101 TMstruct      *tmGlobal;           /* base tone-mapping */
00102 TMstruct      *tmCurrent;          /* curren tone-mapping */
00103 
00104 GC     ourgc;                      /* standard graphics context */
00105 GC     revgc;                      /* graphics context with GXinvert */
00106 
00107 int           *ourrank;            /* our visual class ranking */
00108 XVisualInfo   ourvis;                     /* our visual */
00109 XRASTER              *ourras;             /* our stored image */
00110 unsigned char *ourdata;            /* our image data */
00111 
00112 struct {
00113        int  xmin, ymin, xsiz, ysiz;
00114 }  bbox = {0, 0, 0, 0};                   /* current bbox */
00115 
00116 char  *geometry = NULL;                   /* geometry specification */
00117 
00118 char  icondata[ICONSIZ*ICONSIZ/8]; /* icon bitmap data */
00119 int  iconwidth = 0, iconheight = 0;
00120 
00121 char  *progname;
00122 
00123 char  errmsg[128];
00124 
00125 BYTE  clrtab[256][3];                     /* global color map */
00126 
00127 
00128 Display  *thedisplay;
00129 Atom  closedownAtom, wmProtocolsAtom;
00130 
00131 int  sigrecv;
00132 
00133 void  onsig(int i) { sigrecv++; }
00134 
00135 typedef void doboxf_t(COLR *scn, int n, void *);
00136 
00137 static gethfunc headline;
00138 static void init(int argc, char **argv);
00139 static void quiterr(char *err);
00140 static int viscmp(XVisualInfo *v1, XVisualInfo *v2);
00141 static void getbestvis(void);
00142 static void getras(void);
00143 static void getevent(void);
00144 static int traceray(int xpos, int ypos);
00145 static int docom(XKeyPressedEvent *ekey);
00146 static void moveimage(XButtonPressedEvent *ebut);
00147 static void getbox(XButtonPressedEvent *ebut);
00148 static void trackrays(XButtonPressedEvent *ebut);
00149 static void revbox(int x0, int y0, int x1, int y1);
00150 static doboxf_t colavg;
00151 static doboxf_t addfix;
00152 static int avgbox(COLOR cavg);
00153 static int dobox(doboxf_t *f, void *p);
00154 static void make_tonemap(void);
00155 static void tmap_colrs(COLR *scn, int len);
00156 static void getmono(void);
00157 static void add2icon(int y, COLR *scan);
00158 static void getfull(void);
00159 static void getgrey(void);
00160 static void getmapped(void);
00161 static void scale_rcolors(XRASTER *xr, double sf);
00162 static int getscan(int y);
00163 
00164 
00165 int
00166 main(int  argc, char  *argv[])
00167 {
00168        int  i;
00169        int  pid;
00170        
00171        progname = argv[0];
00172        fin = stdin;
00173 
00174        for (i = 1; i < argc; i++)
00175               if (argv[i][0] == '-')
00176                      switch (argv[i][1]) {
00177                      case 'c':                   /* number of colors */
00178                             maxcolors = atoi(argv[++i]);
00179                             break;
00180                      case 'b':                   /* greyscale only */
00181                             greyscale = !greyscale;
00182                             break;
00183                      case 'm':                   /* monochrome */
00184                             greyscale = 1;
00185                             maxcolors = 2;
00186                             break;
00187                      case 'd':                   /* display or dither */
00188                             if (argv[i][2] == 'i')
00189                                    dispname = argv[++i];
00190                             else
00191                                    dither = !dither;
00192                             break;
00193                      case 'f':                   /* save pixmap */
00194                             fast = !fast;
00195                             break;
00196                      case 's':                   /* one at a time */
00197                             sequential = !sequential;
00198                             break;
00199                      case 'o':                   /* 't' output */
00200                             tout = argv[i]+2;
00201                             break;
00202                      case 't':                   /* msec interval */
00203                             tinterv = atoi(argv[++i]);
00204                             break;
00205                      case 'e':                   /* exposure comp. */
00206                             i++;
00207                             if (argv[i][0] == 'a') {
00208                                    tmflags = TM_F_CAMERA;
00209                                    break;
00210                             }
00211                             if (argv[i][0] == 'h') {
00212                                    tmflags = TM_F_HUMAN;
00213                                    break;
00214                             }
00215                             if (argv[i][0] != '+' && argv[i][0] != '-')
00216                                    goto userr;
00217                             scale = atoi(argv[i]);
00218                             break;
00219                      case 'g':                   /* gamma comp. */
00220                             if (argv[i][2] == 'e')
00221                                    geometry = argv[++i];
00222                             else
00223                                    gamstr = argv[++i];
00224                             break;
00225                      default:
00226                             goto userr;
00227                      }
00228               else if (argv[i][0] == '=')
00229                      geometry = argv[i];
00230               else
00231                      break;
00232 
00233        if (i > argc)
00234               goto userr;
00235        while (i < argc-1) {
00236               sigrecv = 0;
00237               signal(SIGCONT, onsig);
00238               if ((pid=fork()) == 0) {    /* a child for each picture */
00239                      parent = -1;
00240                      break;
00241               }
00242               if (pid < 0)
00243                      quiterr("fork failed");
00244               parent++;
00245               while (!sigrecv)
00246                      pause();      /* wait for wake-up call */
00247               i++;
00248        }
00249        if (i < argc) {                    /* open picture file */
00250               fname = argv[i];
00251               fin = fopen(fname, "r");
00252               if (fin == NULL)
00253                      quiterr("cannot open picture file");
00254        }
00255                             /* get header */
00256        getheader(fin, headline, NULL);
00257                             /* get picture dimensions */
00258        if (wrongformat || !fgetsresolu(&inpres, fin))
00259               quiterr("bad picture format");
00260        xmax = scanlen(&inpres);
00261        ymax = numscans(&inpres);
00262                             /* set view parameters */
00263        if (gotview && setview(&ourview) != NULL)
00264               gotview = 0;
00265        if ((scanline = (COLR *)malloc(xmax*sizeof(COLR))) == NULL)
00266               quiterr("out of memory");
00267 
00268        init(argc, argv);                  /* get file and open window */
00269 
00270        for ( ; ; )
00271               getevent();          /* main loop */
00272 userr:
00273        fprintf(stderr,
00274 "Usage: %s [-di disp][[-ge] spec][-b][-m][-d][-f][-c nclrs][-e spec][-g gamcor][-s][-ospec][-t intvl] hdr ..\n",
00275                      progname);
00276        exit(1);
00277 }
00278 
00279 
00280 static int
00281 headline(            /* get relevant info from header */
00282        char   *s,
00283        void   *p
00284 )
00285 {
00286        char  fmt[32];
00287 
00288        if (isexpos(s))
00289               exposure *= exposval(s);
00290        else if (formatval(fmt, s))
00291               wrongformat = strcmp(fmt, COLRFMT);
00292        else if (isview(s) && sscanview(&ourview, s) > 0)
00293               gotview++;
00294        return(0);
00295 }
00296 
00297 
00298 static void
00299 init(                /* get data and open window */
00300        int argc,
00301        char **argv
00302 )
00303 {
00304        XSetWindowAttributes ourwinattr;
00305        XClassHint    xclshints;
00306        XWMHints      xwmhints;
00307        XSizeHints    xszhints;
00308        XTextProperty windowName, iconName;
00309        XGCValues     xgcv;
00310        char   *name;
00311        register int  i;
00312        
00313        if (fname != NULL) {
00314               scanpos = (long *)malloc(ymax*sizeof(long));
00315               if (scanpos == NULL)
00316                      quiterr("out of memory");
00317               for (i = 0; i < ymax; i++)
00318                      scanpos[i] = -1;
00319               name = fname;
00320        } else
00321               name = progname;
00322                             /* remove directory prefix from name */
00323        for (i = strlen(name); i-- > 0; )
00324               if (name[i] == '/')
00325                      break;
00326        name += i+1;
00327        if ((thedisplay = XOpenDisplay(dispname)) == NULL)
00328               quiterr("cannot open display");
00329                             /* set gamma value */
00330        if (gamstr == NULL)         /* get it from the X server */
00331               gamstr = XGetDefault(thedisplay, "radiance", "gamma");
00332        if (gamstr == NULL)         /* get it from the environment */
00333               gamstr = getenv("DISPLAY_GAMMA");
00334        if (gamstr != NULL)
00335               gamcor = atof(gamstr);
00336                             /* get best visual for default screen */
00337        getbestvis();
00338                             /* store image */
00339        getras();
00340                             /* get size and position */
00341        xszhints.flags = 0;
00342        xszhints.width = xmax; xszhints.height = ymax;
00343        if (geometry != NULL) {
00344               i = XParseGeometry(geometry, &xszhints.x, &xszhints.y,
00345                             (unsigned *)&xszhints.width,
00346                             (unsigned *)&xszhints.height);
00347               if ((i&(WidthValue|HeightValue)) == (WidthValue|HeightValue))
00348                      xszhints.flags |= USSize;
00349               else
00350                      xszhints.flags |= PSize;
00351               if ((i&(XValue|YValue)) == (XValue|YValue)) {
00352                      xszhints.flags |= USPosition;
00353                      if (i & XNegative)
00354                             xszhints.x += DisplayWidth(thedisplay,
00355                             ourscreen)-1-xszhints.width-2*BORWIDTH;
00356                      if (i & YNegative)
00357                             xszhints.y += DisplayHeight(thedisplay,
00358                             ourscreen)-1-xszhints.height-2*BORWIDTH;
00359               }
00360        }
00361        /* open window */
00362        i = CWEventMask|CWCursor|CWBackPixel|CWBorderPixel;
00363        ourwinattr.border_pixel = ourwhite;
00364        ourwinattr.background_pixel = ourblack;
00365        if (ourvis.visual != DefaultVisual(thedisplay,ourscreen)) {
00366               ourwinattr.colormap = newcmap(thedisplay, ourscreen, ourvis.visual);
00367               i |= CWColormap;
00368        }
00369        ourwinattr.event_mask = ExposureMask|KeyPressMask|ButtonPressMask|
00370                      ButtonReleaseMask|ButtonMotionMask|StructureNotifyMask;
00371        ourwinattr.cursor = XCreateFontCursor(thedisplay, XC_diamond_cross);
00372        wind = XCreateWindow(thedisplay, ourroot, xszhints.x, xszhints.y,
00373                      xszhints.width, xszhints.height, BORWIDTH,
00374                      ourvis.depth, InputOutput, ourvis.visual,
00375                      i, &ourwinattr);
00376        if (wind == 0)
00377               quiterr("cannot create window");
00378        width = xmax;
00379        height = ymax;
00380        /* prepare graphics drawing context */
00381        if ((xgcv.font = XLoadFont(thedisplay, FONTNAME)) == 0)
00382               quiterr("cannot get font");
00383        xgcv.foreground = ourblack;
00384        xgcv.background = ourwhite;
00385        ourgc = XCreateGC(thedisplay, wind, GCForeground|GCBackground|
00386                      GCFont, &xgcv);
00387        xgcv.function = GXinvert;
00388        revgc = XCreateGC(thedisplay, wind, GCForeground|GCBackground|
00389                      GCFunction, &xgcv);
00390 
00391        /* set up the window manager */
00392        xwmhints.flags = InputHint|IconPixmapHint;
00393        xwmhints.input = True;
00394        xwmhints.icon_pixmap = XCreateBitmapFromData(thedisplay,
00395                      wind, icondata, iconwidth, iconheight);
00396 
00397        windowName.encoding = iconName.encoding = XA_STRING;
00398        windowName.format = iconName.format = 8;
00399        windowName.value = (u_char *)name;
00400        windowName.nitems = strlen((char *)windowName.value);
00401        iconName.value = (u_char *)name;
00402        iconName.nitems = strlen((char *)windowName.value);
00403 
00404        xclshints.res_name = NULL;
00405        xclshints.res_class = "Ximage";
00406        XSetWMProperties(thedisplay, wind, &windowName, &iconName,
00407                      argv, argc, &xszhints, &xwmhints, &xclshints);
00408        closedownAtom = XInternAtom(thedisplay, "WM_DELETE_WINDOW", False);
00409        wmProtocolsAtom = XInternAtom(thedisplay, "WM_PROTOCOLS", False);
00410        XSetWMProtocols(thedisplay, wind, &closedownAtom, 1);
00411 
00412        XMapWindow(thedisplay, wind);
00413 } /* end of init */
00414 
00415 
00416 static void
00417 quiterr(             /* print message and exit */
00418        char  *err
00419 )
00420 {
00421        register int  es;
00422        int  cs;
00423 
00424        if ( (es = err != NULL) )
00425               fprintf(stderr, "%s: %s: %s\n", progname, 
00426                             fname==NULL?"<stdin>":fname, err);
00427        if (thedisplay != NULL)
00428               XCloseDisplay(thedisplay);
00429        if ((parent < 0) & (sigrecv == 0))
00430               kill(getppid(), SIGCONT);
00431        while (parent > 0 && wait(&cs) != -1) {   /* wait for any children */
00432               if (es == 0)
00433                      es = cs>>8 & 0xff;
00434               parent--;
00435        }
00436        exit(es);
00437 }
00438 
00439 
00440 static int
00441 viscmp(              /* compare visual to see which is better, descending */
00442        register XVisualInfo *v1,
00443        register XVisualInfo *v2
00444 )
00445 {
00446        int    bad1 = 0, bad2 = 0;
00447        register int  *rp;
00448 
00449        if (v1->class == v2->class) {
00450               if ((v1->class == TrueColor) | (v1->class == DirectColor)) {
00451                                    /* prefer 24-bit */
00452                      if ((v1->depth == 24) & (v2->depth > 24))
00453                             return(-1);
00454                      if ((v1->depth > 24) & (v2->depth == 24))
00455                             return(1);
00456                                    /* go for maximum depth otherwise */
00457                      return(v2->depth - v1->depth);
00458               }
00459                                    /* don't be too greedy */
00460               if ((maxcolors <= 1<<v1->depth) & (maxcolors <= 1<<v2->depth))
00461                      return(v1->depth - v2->depth);
00462               return(v2->depth - v1->depth);
00463        }
00464                                    /* prefer Pseudo when < 15-bit */
00465        if ((v1->class == TrueColor) | (v1->class == DirectColor) &&
00466                      v1->depth < 15)
00467               bad1 = 1;
00468        if ((v2->class == TrueColor) | (v2->class == DirectColor) &&
00469                      v2->depth < 15)
00470               bad2 = -1;
00471        if (bad1 | bad2)
00472               return(bad1+bad2);
00473                                    /* otherwise, use class ranking */
00474        for (rp = ourrank; *rp != -1; rp++) {
00475               if (v1->class == *rp)
00476                      return(-1);
00477               if (v2->class == *rp)
00478                      return(1);
00479        }
00480        return(0);
00481 }
00482 
00483 
00484 static void
00485 getbestvis(void)                   /* get the best visual for this screen */
00486 {
00487 #ifdef DEBUG
00488 static char  vistype[][12] = {
00489               "StaticGray",
00490               "GrayScale",
00491               "StaticColor",
00492               "PseudoColor",
00493               "TrueColor",
00494               "DirectColor"
00495 };
00496 #endif
00497        static int    rankings[3][6] = {
00498               {TrueColor,DirectColor,PseudoColor,GrayScale,StaticGray,-1},
00499               {PseudoColor,GrayScale,StaticGray,-1},
00500               {PseudoColor,GrayScale,StaticGray,-1}
00501        };
00502        XVisualInfo   *xvi;
00503        int    vismatched;
00504        register int  i, j;
00505 
00506        if (greyscale) {
00507               ourrank = rankings[2];
00508               if (maxcolors < 2) maxcolors = 256;
00509        } else if (maxcolors >= 2 && maxcolors <= 256)
00510               ourrank = rankings[1];
00511        else {
00512               ourrank = rankings[0];
00513               maxcolors = 256;
00514        }
00515                                    /* find best visual */
00516        ourvis.screen = ourscreen;
00517        xvi = XGetVisualInfo(thedisplay,VisualScreenMask,&ourvis,&vismatched);
00518        if (xvi == NULL)
00519               quiterr("no visuals for this screen!");
00520 #ifdef DEBUG
00521        fprintf(stderr, "Supported visuals:\n");
00522        for (i = 0; i < vismatched; i++)
00523               fprintf(stderr, "\ttype %s, depth %d\n",
00524                             vistype[xvi[i].class], xvi[i].depth);
00525 #endif
00526        for (i = 0, j = 1; j < vismatched; j++)
00527               if (viscmp(&xvi[i],&xvi[j]) > 0)
00528                      i = j;
00529                                    /* compare to least acceptable */
00530        for (j = 0; ourrank[j++] != -1; )
00531               ;
00532        ourvis.class = ourrank[--j];
00533        ourvis.depth = 1;
00534        if (viscmp(&xvi[i],&ourvis) > 0)
00535               quiterr("inadequate visuals on this screen");
00536                                    /* OK, we'll use it */
00537        ourvis = xvi[i];
00538 #ifdef DEBUG
00539        fprintf(stderr, "Selected visual type %s, depth %d\n",
00540                      vistype[ourvis.class], ourvis.depth);
00541 #endif
00542                                    /* make appropriate adjustments */
00543        if (ourvis.class == GrayScale || ourvis.class == StaticGray)
00544               greyscale = 1;
00545        if (ourvis.depth <= 8 && ourvis.colormap_size < maxcolors)
00546               maxcolors = ourvis.colormap_size;
00547        if (ourvis.class == StaticGray) {
00548               ourblack = 0;
00549               ourwhite = 255;
00550        } else if (ourvis.class == PseudoColor) {
00551               ourblack = BlackPixel(thedisplay,ourscreen);
00552               ourwhite = WhitePixel(thedisplay,ourscreen);
00553               if ((ourblack|ourwhite) & ~255L) {
00554                      ourblack = 0;
00555                      ourwhite = 1;
00556               }
00557               if (maxcolors > 4)
00558                      maxcolors -= 2;
00559        } else {
00560               ourblack = 0;
00561               ourwhite = ourvis.red_mask|ourvis.green_mask|ourvis.blue_mask;
00562        }
00563        XFree((char *)xvi);
00564 }
00565 
00566 
00567 static void
00568 getras(void)                       /* get raster file */
00569 {
00570        if (maxcolors <= 2) {              /* monochrome */
00571               ourdata = (unsigned char *)malloc(ymax*((xmax+7)/8));
00572               if (ourdata == NULL)
00573                      goto fail;
00574               ourras = make_raster(thedisplay, &ourvis, 1, (char *)ourdata,
00575                             xmax, ymax, 8);
00576               if (ourras == NULL)
00577                      goto fail;
00578               getmono();
00579        } else if ((ourvis.class == TrueColor) | (ourvis.class == DirectColor)) {
00580               int  datsiz = ourvis.depth>16 ? sizeof(int32) : sizeof(int16);
00581               ourdata = (unsigned char *)malloc(datsiz*xmax*ymax);
00582               if (ourdata == NULL)
00583                      goto fail;
00584               ourras = make_raster(thedisplay, &ourvis, datsiz*8,
00585                             (char *)ourdata, xmax, ymax, datsiz*8);
00586               if (ourras == NULL)
00587                      goto fail;
00588               getfull();
00589        } else {
00590               ourdata = (unsigned char *)malloc(xmax*ymax);
00591               if (ourdata == NULL)
00592                      goto fail;
00593               ourras = make_raster(thedisplay, &ourvis, 8, (char *)ourdata,
00594                             xmax, ymax, 8);
00595               if (ourras == NULL)
00596                      goto fail;
00597               if (greyscale)
00598                      getgrey();
00599               else
00600                      getmapped();
00601               if (ourvis.class != StaticGray && !init_rcolors(ourras,clrtab))
00602                      goto fail;
00603        }
00604        return;
00605 fail:
00606        quiterr("could not create raster image");
00607 }
00608 
00609 
00610 static void
00611 getevent(void)                            /* process the next event */
00612 {
00613        XEvent xev;
00614 
00615        XNextEvent(thedisplay, &xev);
00616        switch ((int)xev.type) {
00617        case KeyPress:
00618               docom(&xev.xkey);
00619               break;
00620        case ConfigureNotify:
00621               width = xev.xconfigure.width;
00622               height = xev.xconfigure.height;
00623               break;
00624        case MapNotify:
00625               map_rcolors(ourras, wind);
00626               if (fast)
00627                      make_rpixmap(ourras, wind);
00628               if ((!sequential) & (parent < 0) & (sigrecv == 0)) {
00629                      kill(getppid(), SIGCONT);
00630                      sigrecv--;
00631               }
00632               break;
00633        case UnmapNotify:
00634               if (!fast)
00635                      unmap_rcolors(ourras);
00636               break;
00637        case Expose:
00638               redraw(xev.xexpose.x, xev.xexpose.y,
00639                             xev.xexpose.width, xev.xexpose.height);
00640               break;
00641        case ButtonPress:
00642               if (xev.xbutton.state & (ShiftMask|ControlMask))
00643                      moveimage(&xev.xbutton);
00644               else
00645                      switch (xev.xbutton.button) {
00646                      case Button1:
00647                             getbox(&xev.xbutton);
00648                             break;
00649                      case Button2:
00650                             traceray(xev.xbutton.x, xev.xbutton.y);
00651                             break;
00652                      case Button3:
00653                             trackrays(&xev.xbutton);
00654                             break;
00655                      }
00656               break;
00657        case ClientMessage:
00658               if ((xev.xclient.message_type == wmProtocolsAtom) &&
00659                             (xev.xclient.data.l[0] == closedownAtom))
00660                      quiterr(NULL);
00661               break;
00662        }
00663 }
00664 
00665 
00666 static int
00667 traceray(                   /* print requested pixel data */
00668        int  xpos,
00669        int  ypos
00670 )
00671 {
00672        RREAL  hv[2];
00673        FVECT  rorg, rdir;
00674        COLOR  cval;
00675        register char  *cp;
00676 
00677        bbox.xmin = xpos; bbox.xsiz = 1;
00678        bbox.ymin = ypos; bbox.ysiz = 1;
00679        avgbox(cval);
00680        scalecolor(cval, 1./exposure);
00681        pix2loc(hv, &inpres, xpos-xoff, ypos-yoff);
00682        if (!gotview || viewray(rorg, rdir, &ourview, hv[0], hv[1]) < 0)
00683               rorg[0] = rorg[1] = rorg[2] =
00684               rdir[0] = rdir[1] = rdir[2] = 0.;
00685 
00686        for (cp = tout; *cp; cp++)  /* print what they asked for */
00687               switch (*cp) {
00688               case 'o':                   /* origin */
00689                      printf("%e %e %e ", rorg[0], rorg[1], rorg[2]);
00690                      break;
00691               case 'd':                   /* direction */
00692                      printf("%e %e %e ", rdir[0], rdir[1], rdir[2]);
00693                      break;
00694               case 'v':                   /* radiance value */
00695                      printf("%e %e %e ", colval(cval,RED),
00696                                    colval(cval,GRN), colval(cval,BLU));
00697                      break;
00698               case 'l':                   /* luminance */
00699                      printf("%e ", luminance(cval));
00700                      break;
00701               case 'p':                   /* pixel position */
00702                      printf("%d %d ", (int)(hv[0]*inpres.xr),
00703                                    (int)(hv[1]*inpres.yr));
00704                      break;
00705               }
00706        putchar('\n');
00707        fflush(stdout);
00708        return(0);
00709 }
00710 
00711 
00712 static int
00713 docom(                      /* execute command */
00714        XKeyPressedEvent  *ekey
00715 )
00716 {
00717        char  buf[80];
00718        COLOR  cval;
00719        XColor  cvx;
00720        int  com, n;
00721        double  comp;
00722        RREAL  hv[2];
00723 
00724        n = XLookupString(ekey, buf, sizeof(buf), NULL, NULL); 
00725        if (n == 0)
00726               return(0);
00727        com = buf[0];
00728        switch (com) {                     /* interpret command */
00729        case 'q':
00730        case 'Q':
00731        case CTRL('D'):                           /* quit */
00732               quiterr(NULL);
00733        case '\n':
00734        case '\r':
00735        case 'l':
00736        case 'c':                          /* value */
00737               if (!avgbox(cval))
00738                      return(-1);
00739               switch (com) {
00740               case '\n':
00741               case '\r':                         /* radiance */
00742                      sprintf(buf, "%.3f", intens(cval)/exposure);
00743                      break;
00744               case 'l':                          /* luminance */
00745                      sprintf(buf, "%.1fL", luminance(cval)/exposure);
00746                      break;
00747               case 'c':                          /* color */
00748                      comp = pow(2.0, (double)scale);
00749                      sprintf(buf, "(%.2f,%.2f,%.2f)",
00750                                    colval(cval,RED)*comp,
00751                                    colval(cval,GRN)*comp,
00752                                    colval(cval,BLU)*comp);
00753                      break;
00754               }
00755               XDrawImageString(thedisplay, wind, ourgc,
00756                             bbox.xmin, bbox.ymin+bbox.ysiz, buf, strlen(buf)); 
00757               return(0);
00758        case 'i':                          /* identify (contour) */
00759               if (ourras->pixels == NULL)
00760                      return(-1);
00761               n = ourdata[ekey->x-xoff+xmax*(ekey->y-yoff)];
00762               n = ourras->pmap[n];
00763               cvx.pixel = ourras->cdefs[n].pixel;
00764               cvx.red = random() & 65535;
00765               cvx.green = random() & 65535;
00766               cvx.blue = random() & 65535;
00767               cvx.flags = DoRed|DoGreen|DoBlue;
00768               XStoreColor(thedisplay, ourras->cmap, &cvx);
00769               return(0);
00770        case 'p':                          /* position */
00771               pix2loc(hv, &inpres, ekey->x-xoff, ekey->y-yoff);
00772               sprintf(buf, "(%d,%d)", (int)(hv[0]*inpres.xr),
00773                             (int)(hv[1]*inpres.yr));
00774               XDrawImageString(thedisplay, wind, ourgc, ekey->x, ekey->y,
00775                                    buf, strlen(buf));
00776               return(0);
00777        case 't':                          /* trace */
00778               return(traceray(ekey->x, ekey->y));
00779        case 'a':                          /* auto exposure */
00780               if (fname == NULL)
00781                      return(-1);
00782               tmflags = TM_F_CAMERA;
00783               strcpy(buf, "auto exposure...");
00784               goto remap;
00785        case 'h':                          /* human response */
00786               if (fname == NULL)
00787                      return(-1);
00788               tmflags = TM_F_HUMAN;
00789               strcpy(buf, "human exposure...");
00790               goto remap;
00791        case '=':                          /* adjust exposure */
00792        case '@':                          /* adaptation level */
00793               if (!avgbox(cval))
00794                      return(-1);
00795               comp = bright(cval);
00796               if (comp < 1e-20) {
00797                      XBell(thedisplay, 0);
00798                      return(-1);
00799               }
00800               if (com == '@')
00801                      comp = 106./exposure/
00802                      pow(1.219+pow(comp*WHTEFFICACY/exposure,.4),2.5);
00803               else
00804                      comp = .5/comp;
00805               comp = log(comp)/.69315 - scale;
00806               n = comp < 0 ? comp-.5 : comp+.5 ; /* round */
00807               if (tmflags != TM_F_LINEAR)
00808                      tmflags = TM_F_LINEAR;      /* turn off tone mapping */
00809               else {
00810                      if (n == 0)          /* else check if any change */
00811                             return(0);
00812                      scale_rcolors(ourras, pow(2.0, (double)n));
00813               }
00814               scale += n;
00815               sprintf(buf, "%+d", scale);
00816        remap:
00817               XDrawImageString(thedisplay, wind, ourgc,
00818                             bbox.xmin, bbox.ymin+bbox.ysiz, buf, strlen(buf));
00819               XFlush(thedisplay);
00820               /* free(ourdata);    This is done in XDestroyImage()! */
00821               free_raster(ourras);
00822               getras();
00823        /* fall through */
00824        case CTRL('R'):                           /* redraw */
00825        case CTRL('L'):
00826               unmap_rcolors(ourras);
00827               XClearWindow(thedisplay, wind);
00828               map_rcolors(ourras, wind);
00829               if (fast)
00830                      make_rpixmap(ourras, wind);
00831               redraw(0, 0, width, height);
00832               return(0);
00833        case 'f':                          /* turn on fast redraw */
00834               fast = 1;
00835               make_rpixmap(ourras, wind);
00836               return(0);
00837        case 'F':                          /* turn off fast redraw */
00838               fast = 0;
00839               free_rpixmap(ourras);
00840               return(0);
00841        case '0':                          /* recenter origin */
00842               if ((xoff == 0) & (yoff == 0))
00843                      return(0);
00844               xoff = yoff = 0;
00845               XClearWindow(thedisplay, wind);
00846               redraw(0, 0, width, height);
00847               return(0);
00848        case ' ':                          /* clear */
00849               redraw(bbox.xmin, bbox.ymin, bbox.xsiz, bbox.ysiz);
00850               return(0);
00851        default:
00852               XBell(thedisplay, 0);
00853               return(-1);
00854        }
00855 }
00856 
00857 
00858 static void
00859 moveimage(                         /* shift the image */
00860        XButtonPressedEvent  *ebut
00861 )
00862 {
00863        XEvent e;
00864        int    mxo, myo;
00865 
00866        XMaskEvent(thedisplay, ButtonReleaseMask|ButtonMotionMask, &e);
00867        while (e.type == MotionNotify) {
00868               mxo = e.xmotion.x;
00869               myo = e.xmotion.y;
00870               revline(ebut->x, ebut->y, mxo, myo);
00871               revbox(xoff+mxo-ebut->x, yoff+myo-ebut->y,
00872                             xoff+mxo-ebut->x+xmax, yoff+myo-ebut->y+ymax);
00873               XMaskEvent(thedisplay,ButtonReleaseMask|ButtonMotionMask,&e);
00874               revline(ebut->x, ebut->y, mxo, myo);
00875               revbox(xoff+mxo-ebut->x, yoff+myo-ebut->y,
00876                             xoff+mxo-ebut->x+xmax, yoff+myo-ebut->y+ymax);
00877        }
00878        xoff += e.xbutton.x - ebut->x;
00879        yoff += e.xbutton.y - ebut->y;
00880        XClearWindow(thedisplay, wind);
00881        redraw(0, 0, width, height);
00882 }
00883 
00884 
00885 static void
00886 getbox(                            /* get new bbox */
00887        XButtonPressedEvent  *ebut
00888 )
00889 {
00890        XEvent e;
00891 
00892        XMaskEvent(thedisplay, ButtonReleaseMask|ButtonMotionMask, &e);
00893        while (e.type == MotionNotify) {
00894               revbox(ebut->x, ebut->y, bbox.xmin = e.xmotion.x, bbox.ymin = e.xmotion.y);
00895               XMaskEvent(thedisplay,ButtonReleaseMask|ButtonMotionMask,&e);
00896               revbox(ebut->x, ebut->y, bbox.xmin, bbox.ymin);
00897        }
00898        bbox.xmin = e.xbutton.x<0 ? 0 : (e.xbutton.x>=width ? width-1 : e.xbutton.x);
00899        bbox.ymin = e.xbutton.y<0 ? 0 : (e.xbutton.y>=height ? height-1 : e.xbutton.y);
00900        if (bbox.xmin > ebut->x) {
00901               bbox.xsiz = bbox.xmin - ebut->x + 1;
00902               bbox.xmin = ebut->x;
00903        } else {
00904               bbox.xsiz = ebut->x - bbox.xmin + 1;
00905        }
00906        if (bbox.ymin > ebut->y) {
00907               bbox.ysiz = bbox.ymin - ebut->y + 1;
00908               bbox.ymin = ebut->y;
00909        } else {
00910               bbox.ysiz = ebut->y - bbox.ymin + 1;
00911        }
00912 }
00913 
00914 
00915 static void
00916 trackrays(                         /* trace rays as mouse moves */
00917        XButtonPressedEvent  *ebut
00918 )
00919 {
00920        XEvent e;
00921        unsigned long lastrept;
00922 
00923        traceray(ebut->x, ebut->y);
00924        lastrept = ebut->time;
00925        XMaskEvent(thedisplay, ButtonReleaseMask|ButtonMotionMask, &e);
00926        while (e.type == MotionNotify) {
00927               if (e.xmotion.time >= lastrept + tinterv) {
00928                      traceray(e.xmotion.x, e.xmotion.y);
00929                      lastrept = e.xmotion.time;
00930               }
00931               XMaskEvent(thedisplay,ButtonReleaseMask|ButtonMotionMask,&e);
00932        }
00933 }
00934 
00935 
00936 static void
00937 revbox(                     /* draw bbox with reversed lines */
00938        int  x0,
00939        int  y0,
00940        int  x1,
00941        int  y1
00942 )
00943 {
00944        revline(x0, y0, x1, y0);
00945        revline(x0, y1, x1, y1);
00946        revline(x0, y0, x0, y1);
00947        revline(x1, y0, x1, y1);
00948 }
00949 
00950 
00951 static void
00952 colavg(
00953        register COLR *scn,
00954        register int  n,
00955        void *cavg
00956 )
00957 {
00958        COLOR  col;
00959 
00960        while (n--) {
00961               colr_color(col, *scn++);
00962               addcolor((COLORV*)cavg, col);
00963        }
00964 }
00965 
00966 
00967 static int
00968 avgbox(                            /* average color over current bbox */
00969        COLOR  cavg
00970 )
00971 {
00972        double d;
00973        register int  rval;
00974 
00975        setcolor(cavg, 0., 0., 0.);
00976        rval = dobox(colavg, (void *)cavg);
00977        if (rval > 0) {
00978               d = 1./rval;
00979               scalecolor(cavg, d);
00980        }
00981        return(rval);
00982 }
00983 
00984 
00985 static int
00986 dobox(                      /* run function over bbox */
00987        //void (*f)(),                     /* function to call for each subscan */
00988        doboxf_t *f,                /* function to call for each subscan */
00989        void   *p                   /* pointer to private data */
00990 )
00991 {
00992        int  left, right, top, bottom;
00993        int  y;
00994 
00995        left = bbox.xmin - xoff;
00996        right = left + bbox.xsiz;
00997        if (left < 0)
00998               left = 0;
00999        if (right > xmax)
01000               right = xmax;
01001        if (left >= right)
01002               return(0);
01003        top = bbox.ymin - yoff;
01004        bottom = top + bbox.ysiz;
01005        if (top < 0)
01006               top = 0;
01007        if (bottom > ymax)
01008               bottom = ymax;
01009        if (top >= bottom)
01010               return(0);
01011        for (y = top; y < bottom; y++) {
01012               if (getscan(y) == -1)
01013                      return(-1);
01014               (*f)(scanline+left, right-left, p);
01015        }
01016        return((right-left)*(bottom-top));
01017 }
01018 
01019 
01020 static void
01021 addfix(                     /* add fixation points to histogram */
01022        COLR   *scn,
01023        int    n,
01024        void   *p
01025 )
01026 {
01027        TMstruct *    tms = (TMstruct *)p;
01028        
01029        if (tmCvColrs(tms, lscan, TM_NOCHROM, scn, n))
01030               goto tmerr;
01031        if (tmAddHisto(tms, lscan, n, FIXWEIGHT))
01032               goto tmerr;
01033        return;
01034 tmerr:
01035        quiterr("tone mapping error");
01036 }
01037 
01038 
01039 static void
01040 make_tonemap(void)                 /* initialize tone mapping */
01041 {
01042        int  flags, y;
01043 
01044        if (tmflags != TM_F_LINEAR && fname == NULL) {
01045               fprintf(stderr, "%s: cannot adjust tone of standard input\n",
01046                             progname);
01047               tmflags = TM_F_LINEAR;
01048        }
01049        if (tmflags == TM_F_LINEAR) {      /* linear with clamping */
01050               setcolrcor(pow, 1.0/gamcor);
01051               return;
01052        }
01053        flags = tmflags;            /* histogram adjustment */
01054        if (greyscale) flags |= TM_F_BW;
01055        if (tmGlobal != NULL) {            /* reuse old histogram if one */
01056               tmDone(tmCurrent); tmCurrent = NULL;
01057               tmGlobal->flags = flags;
01058        } else {                    /* else initialize */
01059               if ((lscan = (TMbright *)malloc(xmax*sizeof(TMbright))) == NULL)
01060                      goto memerr;
01061               if (greyscale) {
01062                      cscan = TM_NOCHROM;
01063                      if ((pscan = (BYTE *)malloc(sizeof(BYTE)*xmax)) == NULL)
01064                             goto memerr;
01065               } else if ((pscan=cscan = (BYTE *)malloc(3*sizeof(BYTE)*xmax))
01066                             == NULL)
01067                      goto memerr;
01068                                           /* initialize tm library */
01069               tmGlobal = tmInit(flags, stdprims, gamcor);
01070               if (tmGlobal == NULL)
01071                      goto memerr;
01072               if (tmSetSpace(tmGlobal, stdprims, WHTEFFICACY/exposure, NULL))
01073                      goto tmerr;
01074                                           /* compute picture histogram */
01075               for (y = 0; y < ymax; y++) {
01076                      getscan(y);
01077                      if (tmCvColrs(tmGlobal, lscan, TM_NOCHROM,
01078                                    scanline, xmax))
01079                             goto tmerr;
01080                      if (tmAddHisto(tmGlobal, lscan, xmax, 1))
01081                             goto tmerr;
01082               }
01083        }
01084        tmCurrent = tmDup(tmGlobal);       /* add fixations to duplicate map */
01085        dobox(addfix, (void *)tmCurrent);
01086                                    /* (re)compute tone mapping */
01087        if (tmComputeMapping(tmCurrent, gamcor, 0., 0.))
01088               goto tmerr;
01089        return;
01090 memerr:
01091        quiterr("out of memory in make_tonemap");
01092 tmerr:
01093        quiterr("tone mapping error");
01094 }
01095 
01096 
01097 static void
01098 tmap_colrs(          /* apply tone mapping to scanline */
01099        register COLR  *scn,
01100        int  len
01101 )
01102 {
01103        register BYTE  *ps;
01104 
01105        if (tmflags == TM_F_LINEAR) {
01106               if (scale)
01107                      shiftcolrs(scn, len, scale);
01108               colrs_gambs(scn, len);
01109               return;
01110        }
01111        if (len > xmax)
01112               quiterr("code error 1 in tmap_colrs");
01113        if (tmCvColrs(tmCurrent, lscan, cscan, scn, len))
01114               goto tmerr;
01115        if (tmMapPixels(tmCurrent, pscan, lscan, cscan, len))
01116               goto tmerr;
01117        ps = pscan;
01118        if (greyscale)
01119               while (len--) {
01120                      scn[0][RED] = scn[0][GRN] = scn[0][BLU] = *ps++;
01121                      scn[0][EXP] = COLXS;
01122                      scn++;
01123               }
01124        else
01125               while (len--) {
01126                      scn[0][RED] = *ps++;
01127                      scn[0][GRN] = *ps++;
01128                      scn[0][BLU] = *ps++;
01129                      scn[0][EXP] = COLXS;
01130                      scn++;
01131               }
01132        return;
01133 tmerr:
01134        quiterr("tone mapping error");
01135 }
01136 
01137 
01138 static void
01139 getmono(void)               /* get monochrome data */
01140 {
01141        register unsigned char      *dp;
01142        register int  x, err;
01143        int    y, errp;
01144        short  *cerr;
01145 
01146        if ((cerr = (short *)calloc(xmax,sizeof(short))) == NULL)
01147               quiterr("out of memory in getmono");
01148        dp = ourdata - 1;
01149        for (y = 0; y < ymax; y++) {
01150               getscan(y);
01151               add2icon(y, scanline);
01152               normcolrs(scanline, xmax, scale);
01153               err = 0;
01154               for (x = 0; x < xmax; x++) {
01155                      if (!(x&7))
01156                             *++dp = 0;
01157                      errp = err;
01158                      err += normbright(scanline[x]) + cerr[x];
01159                      if (err > 127)
01160                             err -= 255;
01161                      else
01162                             *dp |= 1<<(7-(x&07));
01163                      err /= 3;
01164                      cerr[x] = err + errp;
01165               }
01166        }
01167        free((void *)cerr);
01168 }
01169 
01170 
01171 static void
01172 add2icon(            /* add a scanline to our icon data */
01173        int  y,
01174        COLR  *scan
01175 )
01176 {
01177        static short  cerr[ICONSIZ];
01178        static int  ynext;
01179        static char  *dp;
01180        COLR  clr;
01181        register int  err;
01182        register int  x, ti;
01183        int  errp;
01184 
01185        if (iconheight == 0) {             /* initialize */
01186               if (xmax <= ICONSIZ && ymax <= ICONSIZ) {
01187                      iconwidth = xmax;
01188                      iconheight = ymax;
01189               } else if (xmax > ymax) {
01190                      iconwidth = ICONSIZ;
01191                      iconheight = ICONSIZ*ymax/xmax;
01192                      if (iconheight < 1)
01193                             iconheight = 1;
01194               } else {
01195                      iconwidth = ICONSIZ*xmax/ymax;
01196                      if (iconwidth < 1)
01197                             iconwidth = 1;
01198                      iconheight = ICONSIZ;
01199               }
01200               ynext = 0;
01201               dp = icondata - 1;
01202        }
01203        if (y < ynext*ymax/iconheight)     /* skip this one */
01204               return;
01205        err = 0;
01206        for (x = 0; x < iconwidth; x++) {
01207               if (!(x&7))
01208                      *++dp = 0;
01209               errp = err;
01210               ti = x*xmax/iconwidth;
01211               copycolr(clr, scan[ti]);
01212               normcolrs(&clr, 1, scale);
01213               err += normbright(clr) + cerr[x];
01214               if (err > 127)
01215                      err -= 255;
01216               else
01217                      *dp |= 1<<(x&07);
01218               err /= 3;
01219               cerr[x] = err + errp;
01220        }
01221        ynext++;
01222 }
01223 
01224 
01225 static void
01226 getfull(void)               /* get full (24-bit) data */
01227 {
01228        int    y;
01229        register uint32      *dp;
01230        register uint16      *dph;
01231        register int  x;
01232                                    /* initialize tone mapping */
01233        make_tonemap();
01234                                    /* read and convert file */
01235        dp = (uint32 *)ourdata;
01236        dph = (uint16 *)ourdata;
01237        for (y = 0; y < ymax; y++) {
01238               getscan(y);
01239               add2icon(y, scanline);
01240               tmap_colrs(scanline, xmax);
01241               switch (ourras->image->blue_mask) {
01242               case 0xff:           /* 24-bit RGB */
01243                      for (x = 0; x < xmax; x++)
01244                             *dp++ =       (uint32)scanline[x][RED] << 16 |
01245                                    (uint32)scanline[x][GRN] << 8 |
01246                                    (uint32)scanline[x][BLU] ;
01247                      break;
01248               case 0xff0000:              /* 24-bit BGR */
01249                      for (x = 0; x < xmax; x++)
01250                             *dp++ =       (uint32)scanline[x][RED] |
01251                                    (uint32)scanline[x][GRN] << 8 |
01252                                    (uint32)scanline[x][BLU] << 16 ;
01253                      break;
01254 #if 0
01255               case 0x1f:           /* 15-bit RGB */
01256                      for (x = 0; x < xmax; x++)
01257                             *dph++ =      (scanline[x][RED] << 7 & 0x7c00) |
01258                                    (scanline[x][GRN] << 2 & 0x3e0) |
01259                                    (unsigned)scanline[x][BLU] >> 3 ;
01260                      break;
01261               case 0x7c00:         /* 15-bit BGR */
01262                      for (x = 0; x < xmax; x++)
01263                             *dph++ =      (unsigned)scanline[x][RED] >> 3 |
01264                                    (scanline[x][GRN] << 2 & 0x3e0) |
01265                                    (scanline[x][BLU] << 7 & 0x7c00) ;
01266                      break;
01267 #endif
01268               default:             /* unknown */
01269                      if (ourvis.depth > 16)
01270                             for (x = 0; x < xmax; x++) {
01271                                    *dp = ourras->image->red_mask &
01272                                           ourras->image->red_mask*scanline[x][RED]/255;
01273                                    *dp |= ourras->image->green_mask &
01274                                           ourras->image->green_mask*scanline[x][GRN]/255;
01275                                    *dp++ |= ourras->image->blue_mask &
01276                                           ourras->image->blue_mask*scanline[x][BLU]/255;
01277                             }
01278                      else
01279                             for (x = 0; x < xmax; x++) {
01280                                    *dph = ourras->image->red_mask &
01281                                           ourras->image->red_mask*scanline[x][RED]/255;
01282                                    *dph |= ourras->image->green_mask &
01283                                           ourras->image->green_mask*scanline[x][GRN]/255;
01284                                    *dph++ |= ourras->image->blue_mask &
01285                                           ourras->image->blue_mask*scanline[x][BLU]/255;
01286                             }
01287                      break;
01288               }
01289        }
01290 }
01291 
01292 
01293 static void
01294 getgrey(void)               /* get greyscale data */
01295 {
01296        int    y;
01297        register unsigned char      *dp;
01298        register int  x;
01299                                    /* initialize tone mapping */
01300        make_tonemap();
01301                                    /* read and convert file */
01302        dp = ourdata;
01303        for (y = 0; y < ymax; y++) {
01304               getscan(y);
01305               add2icon(y, scanline);
01306               tmap_colrs(scanline, xmax);
01307               if (maxcolors < 256)
01308                      for (x = 0; x < xmax; x++)
01309                             *dp++ =       ((int32)scanline[x][GRN] *
01310                                    maxcolors + maxcolors/2) >> 8;
01311               else
01312                      for (x = 0; x < xmax; x++)
01313                             *dp++ =       scanline[x][GRN];
01314        }
01315        for (x = 0; x < maxcolors; x++)
01316               clrtab[x][RED] = clrtab[x][GRN] =
01317                      clrtab[x][BLU] = ((int32)x*256 + 128)/maxcolors;
01318 }
01319 
01320 
01321 static void
01322 getmapped(void)                    /* get color-mapped data */
01323 {
01324        int    y;
01325                                    /* make sure we can do it first */
01326        if (fname == NULL)
01327               quiterr("cannot map colors from standard input");
01328                                    /* initialize tone mapping */
01329        make_tonemap();
01330                                    /* make histogram */
01331        if (new_histo((int32)xmax*ymax) == -1)
01332               quiterr("cannot initialize histogram");
01333        for (y = 0; y < ymax; y++) {
01334               if (getscan(y) < 0)
01335                      break;
01336               add2icon(y, scanline);
01337               tmap_colrs(scanline, xmax);
01338               cnt_colrs(scanline, xmax);
01339        }
01340                                    /* map pixels */
01341        if (!new_clrtab(maxcolors))
01342               quiterr("cannot create color map");
01343        for (y = 0; y < ymax; y++) {
01344               getscan(y);
01345               tmap_colrs(scanline, xmax);
01346               if (dither)
01347                      dith_colrs(ourdata+y*xmax, scanline, xmax);
01348               else
01349                      map_colrs(ourdata+y*xmax, scanline, xmax);
01350        }
01351 }
01352 
01353 
01354 static void
01355 scale_rcolors(                     /* scale color map */
01356        register XRASTER     *xr,
01357        double sf
01358 )
01359 {
01360        register int  i;
01361        long   maxv;
01362 
01363        if (xr->pixels == NULL)
01364               return;
01365 
01366        sf = pow(sf, 1.0/gamcor);
01367        maxv = 65535/sf;
01368 
01369        for (i = xr->ncolors; i--; ) {
01370               xr->cdefs[i].red = xr->cdefs[i].red > maxv ?
01371                             65535 :
01372                             xr->cdefs[i].red * sf;
01373               xr->cdefs[i].green = xr->cdefs[i].green > maxv ?
01374                             65535 :
01375                             xr->cdefs[i].green * sf;
01376               xr->cdefs[i].blue = xr->cdefs[i].blue > maxv ?
01377                             65535 :
01378                             xr->cdefs[i].blue * sf;
01379        }
01380        XStoreColors(thedisplay, xr->cmap, xr->cdefs, xr->ncolors);
01381 }
01382 
01383 
01384 static int
01385 getscan(
01386        int  y
01387 )
01388 {
01389        static int  trunced = -1;          /* truncated file? */
01390 skipit:
01391        if (trunced >= 0 && y >= trunced) {
01392               memset(scanline, '\0', xmax*sizeof(COLR));
01393               return(-1);
01394        }
01395        if (y != cury) {
01396               if (scanpos == NULL || scanpos[y] == -1)
01397                      return(-1);
01398               if (fseek(fin, scanpos[y], 0) == -1)
01399                      quiterr("fseek error");
01400               cury = y;
01401        } else if (scanpos != NULL && scanpos[y] == -1)
01402               scanpos[y] = ftell(fin);
01403 
01404        if (freadcolrs(scanline, xmax, fin) < 0) {
01405               fprintf(stderr, "%s: %s: unfinished picture\n",
01406                             progname, fname==NULL?"<stdin>":fname);
01407               trunced = y;
01408               goto skipit;
01409        }
01410        cury++;
01411        return(0);
01412 }