home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Raytrace & Morphing / SOS-RAYTRACE.ISO / programm / source / radsrc22 / src / px / x11image.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-23  |  23.1 KB  |  967 lines

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