home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / xloadimg.zip / xloadimage.4.1 / send.c < prev    next >
C/C++ Source or Header  |  1993-11-08  |  17KB  |  643 lines

  1. /* send.c:
  2.  *
  3.  * send an Image to an X pixmap
  4.  *
  5.  * jim frost 10.02.89
  6.  *
  7.  * Copyright 1989, 1990, 1991 Jim Frost.
  8.  * See included file "copyright.h" for complete copyright information.
  9.  */
  10.  
  11. #include "copyright.h"
  12. #include "xloadimage.h"
  13.  
  14. static int GotError;
  15.  
  16. static int pixmapErrorTrap(disp, pErrorEvent)
  17.     Display    *disp;
  18.     XErrorEvent * pErrorEvent;
  19. {
  20. #define MAXERRORLEN 100
  21.     char buf[MAXERRORLEN+1];
  22.     GotError = 1;
  23.     XGetErrorText(disp, pErrorEvent->error_code, buf, MAXERRORLEN);
  24.     printf("serial #%d (request code %d) Got Error %s\n",
  25.     pErrorEvent->serial,
  26.     pErrorEvent->request_code,
  27.     buf);
  28.     return(0);
  29. }
  30.  
  31. Pixmap ximageToPixmap(disp, parent, ximageinfo)
  32.      Display    *disp;
  33.      Window      parent;
  34.      XImageInfo *ximageinfo;
  35. {
  36.   int         (*old_handler)();
  37.   Pixmap        pixmap;
  38.  
  39.   GotError = 0;
  40.   old_handler = XSetErrorHandler(pixmapErrorTrap);
  41.   XSync(disp, False);
  42.   pixmap= XCreatePixmap(disp, parent,
  43.             ximageinfo->ximage->width, ximageinfo->ximage->height,
  44.             ximageinfo->depth);
  45.   (void)XSetErrorHandler(old_handler);
  46.   if (GotError)
  47.     return(None);
  48.   ximageinfo->drawable= pixmap;
  49.   sendXImage(ximageinfo, 0, 0, 0, 0,
  50.          ximageinfo->ximage->width, ximageinfo->ximage->height);
  51.   return(pixmap);
  52. }
  53.  
  54. /* find the best pixmap depth supported by the server for a particular
  55.  * visual and return that depth.
  56.  *
  57.  * this is complicated by R3's lack of XListPixmapFormats so we fake it
  58.  * by looking at the structure ourselves.
  59.  */
  60.  
  61. static unsigned int bitsPerPixelAtDepth(disp, scrn, depth)
  62.      Display      *disp;
  63.      int           scrn;
  64.      unsigned int  depth;
  65. {
  66. #if XlibSpecificationRelease < 4 /* the way things were */
  67.   unsigned int a;
  68.  
  69.   for (a= 0; a < disp->nformats; a++)
  70.     if (disp->pixmap_format[a].depth == depth)
  71.       return(disp->pixmap_format[a].bits_per_pixel);
  72.  
  73. #else /* the way things should be */
  74.   XPixmapFormatValues *xf;
  75.   unsigned int nxf, a;
  76.  
  77.   xf = XListPixmapFormats(disp, (int *)&nxf);
  78.   for (a = 0; a < nxf; a++)
  79.     if (xf[a].depth == depth)
  80.       return(xf[a].bits_per_pixel);
  81. #endif
  82.  
  83.   /* this should never happen; if it does, we're in trouble
  84.    */
  85.  
  86.   fprintf(stderr, "bitsPerPixelAtDepth: Can't find pixmap depth info!\n");
  87.   exit(1);
  88. }
  89.      
  90. XImageInfo *imageToXImage(disp, scrn, visual, ddepth, image, private_cmap, fit,
  91.               verbose)
  92.      Display      *disp;
  93.      int           scrn;
  94.      Visual       *visual; /* visual to use */
  95.      unsigned int  ddepth; /* depth of the visual to use */
  96.      Image        *image;
  97.      unsigned int  private_cmap;
  98.      unsigned int  fit;
  99.      unsigned int  verbose;
  100. { Pixel        *index, *redvalue, *greenvalue, *bluevalue;
  101.   unsigned int  a, b, newmap, x, y, linelen, dpixlen, dbits;
  102.   XColor        xcolor;
  103.   XGCValues     gcv;
  104.   XImageInfo   *ximageinfo;
  105.   Image        *orig_image;
  106.  
  107.   goodImage(image, "imageToXimage");
  108.  
  109.   xcolor.flags= DoRed | DoGreen | DoBlue;
  110.   index= redvalue= greenvalue= bluevalue= NULL;
  111.   orig_image= image;
  112.   ximageinfo= (XImageInfo *)lmalloc(sizeof(XImageInfo));
  113.   ximageinfo->disp= disp;
  114.   ximageinfo->scrn= scrn;
  115.   ximageinfo->depth= 0;
  116.   ximageinfo->drawable= None;
  117.   ximageinfo->foreground= ximageinfo->background= 0;
  118.   ximageinfo->gc= NULL;
  119.   ximageinfo->ximage= NULL;
  120.  
  121.   /* process image based on type of visual we're sending to
  122.    */
  123.  
  124.   switch (image->type) {
  125.   case ITRUE:
  126.     switch (visual->class) {
  127.     case TrueColor:
  128.     case DirectColor:
  129.       /* goody goody */
  130.       break;
  131.     default:
  132.       if (visual->bits_per_rgb > 1)
  133.     image= reduce(image, depthToColors(visual->bits_per_rgb), verbose);
  134.       else
  135.     image= dither(image, verbose);
  136.     }
  137.     break;
  138.  
  139.   case IRGB:
  140.     switch(visual->class) {
  141.     case TrueColor:
  142.     case DirectColor:
  143.       /* no problem, we handle this just fine */
  144.       break;
  145.     default:
  146.       if (visual->bits_per_rgb < 2)
  147.     image= dither(image, verbose);
  148.       break;
  149.     }
  150.  
  151.   case IBITMAP:
  152.     /* no processing ever needs to be done for bitmaps */
  153.     break;
  154.   }
  155.  
  156.   /* do color allocation
  157.    */
  158.  
  159.   switch (visual->class) {
  160.   case TrueColor:
  161.   case DirectColor:
  162.     if (!BITMAPP(image)) { /* bitmaps don't need all of this */
  163.       Pixel pixval;
  164.       unsigned int redcolors, greencolors, bluecolors;
  165.       unsigned int redstep, greenstep, bluestep;
  166.       unsigned int redbottom, greenbottom, bluebottom;
  167.       unsigned int redtop, greentop, bluetop;
  168.  
  169.       redvalue= (Pixel *)lmalloc(sizeof(Pixel) * 256);
  170.       greenvalue= (Pixel *)lmalloc(sizeof(Pixel) * 256);
  171.       bluevalue= (Pixel *)lmalloc(sizeof(Pixel) * 256);
  172.  
  173.       if (visual == DefaultVisual(disp, scrn))
  174.     ximageinfo->cmap= DefaultColormap(disp, scrn);
  175.       else
  176.     ximageinfo->cmap= XCreateColormap(disp, RootWindow(disp, scrn),
  177.                       visual, AllocNone);
  178.  
  179.       retry_direct: /* tag we hit if a DirectColor allocation fails on
  180.              * default colormap */
  181.  
  182.       /* calculate number of distinct colors in each band
  183.        */
  184.  
  185.       redcolors= greencolors= bluecolors= 1;
  186.       for (pixval= 1; pixval; pixval <<= 1) {
  187.     if (pixval & visual->red_mask)
  188.       redcolors <<= 1;
  189.     if (pixval & visual->green_mask)
  190.       greencolors <<= 1;
  191.     if (pixval & visual->blue_mask)
  192.       bluecolors <<= 1;
  193.       }
  194.       
  195.       /* sanity check
  196.        */
  197.  
  198.       if ((redcolors > visual->map_entries) ||
  199.       (greencolors > visual->map_entries) ||
  200.       (bluecolors > visual->map_entries)) {
  201.     fprintf(stderr, "\
  202. Warning: inconsistency in color information (this may be ugly)\n");
  203.       }
  204.  
  205.       redstep= 256 / redcolors;
  206.       greenstep= 256 / greencolors;
  207.       bluestep= 256 / bluecolors;
  208.       redbottom= greenbottom= bluebottom= 0;
  209.       for (a= 0; a < visual->map_entries; a++) {
  210.     if (redbottom < 256)
  211.       redtop= redbottom + redstep;
  212.     if (greenbottom < 256)
  213.       greentop= greenbottom + greenstep;
  214.     if (bluebottom < 256)
  215.       bluetop= bluebottom + bluestep;
  216.  
  217.     xcolor.red= (redtop - 1) << 8;
  218.     xcolor.green= (greentop - 1) << 8;
  219.     xcolor.blue= (bluetop - 1) << 8;
  220.     if (! XAllocColor(disp, ximageinfo->cmap, &xcolor)) {
  221.  
  222.       /* if an allocation fails for a DirectColor default visual then
  223.        * we should create a private colormap and try again.
  224.        */
  225.  
  226.       if ((visual->class == DirectColor) &&
  227.           (visual == DefaultVisual(disp, scrn))) {
  228.         ximageinfo->cmap= XCreateColormap(disp, RootWindow(disp, scrn),
  229.                           visual, AllocNone);
  230.         goto retry_direct;
  231.       }
  232.  
  233.       /* something completely unexpected happened
  234.        */
  235.  
  236.       fprintf(stderr, "\
  237. imageToXImage: XAllocColor failed on a TrueColor/Directcolor visual\n");
  238.       return(NULL);
  239.     }
  240.  
  241.     /* fill in pixel values for each band at this intensity
  242.      */
  243.  
  244.     while ((redbottom < 256) && (redbottom < redtop))
  245.       redvalue[redbottom++]= xcolor.pixel & visual->red_mask;
  246.     while ((greenbottom < 256) && (greenbottom < greentop))
  247.       greenvalue[greenbottom++]= xcolor.pixel & visual->green_mask;
  248.     while ((bluebottom < 256) && (bluebottom < bluetop))
  249.       bluevalue[bluebottom++]= xcolor.pixel & visual->blue_mask;
  250.       }
  251.       break;
  252.     }
  253.     /* bitmaps will fall through to the default case */
  254.     /* FALLTHRU */
  255.  
  256.   default:
  257.   retry: /* this tag is used when retrying because we couldn't get a fit */
  258.     compress(image, verbose);
  259.  
  260.     index= (Pixel *)lmalloc(sizeof(Pixel) * image->rgb.used);
  261.  
  262.     /* private_cmap flag is invalid if not a dynamic visual
  263.      */
  264.  
  265.     switch (visual->class) {
  266.     case StaticColor:
  267.     case StaticGray:
  268.       private_cmap= 0;
  269.     }
  270.  
  271.     /* get the colormap to use.
  272.      */
  273.  
  274.     if (private_cmap) { /* user asked us to use a private cmap */
  275.       newmap= 1;
  276.       fit= 0;
  277.     }
  278.     else if ((visual == DefaultVisual(disp, scrn)) ||
  279.          (visual->class == StaticGray) ||
  280.          (visual->class == StaticColor) ||
  281.          (visual->class == TrueColor) ||
  282.          (visual->class == DirectColor)) {
  283.  
  284.       /* if we're using the default visual, try to alloc colors shareable.
  285.        * otherwise we're using a static visual and should treat it
  286.        * accordingly.
  287.        */
  288.  
  289.       if (visual == DefaultVisual(disp, scrn))
  290.     ximageinfo->cmap= DefaultColormap(disp, scrn);
  291.       else
  292.     ximageinfo->cmap= XCreateColormap(disp, RootWindow(disp, scrn),
  293.                       visual, AllocNone);
  294.       newmap= 0;
  295.  
  296.       /* allocate colors shareable (if we can)
  297.        */
  298.  
  299.       for (a= 0; a < image->rgb.used; a++) {
  300.     xcolor.red= *(image->rgb.red + a);
  301.     xcolor.green= *(image->rgb.green + a);
  302.     xcolor.blue= *(image->rgb.blue + a);
  303.     if (! XAllocColor(disp, ximageinfo->cmap, &xcolor))
  304.       if ((visual->class == StaticColor) ||
  305.           (visual->class == StaticGray) ||
  306.           (visual->class == TrueColor) ||
  307.           (visual->class == DirectColor)) {
  308.         printf("imageToXImage: XAllocColor failed on a static visual\n");
  309.         return(NULL);
  310.       }
  311.       else {
  312.  
  313.         /* we can't allocate the colors shareable so free all the colors
  314.          * we had allocated and create a private colormap (or fit
  315.          * into the default cmap if `fit' is true).
  316.          */
  317.  
  318.         XFreeColors(disp, ximageinfo->cmap, index, a, 0);
  319.         newmap= 1;
  320.         break;
  321.       }
  322.     *(index + a)= xcolor.pixel;
  323.       }
  324.     }
  325.     else {
  326.       newmap= 1;
  327.       fit= 0;
  328.     }
  329.  
  330.     if (newmap) {
  331.  
  332.       /* either create a new colormap or fit the image into the one we
  333.        * have.  to create a new one, we create a private cmap and allocate
  334.        * the colors writable.  fitting the colors is harder, we have to:
  335.        *  1. grab the server so no one can goof with the colormap.
  336.        *  2. count the available colors using XAllocColorCells.
  337.        *  3. free the colors we just allocated.
  338.        *  4. reduce the depth of the image to fit.
  339.        *  5. allocate the colors again shareable.
  340.        *  6. ungrab the server and continue on our way.
  341.        * someone should shoot the people who designed X color allocation.
  342.        */
  343.  
  344.       if (fit) {
  345.     if (verbose)
  346.       printf("  Fitting image into default colormap\n");
  347.     XGrabServer(disp);
  348.       }
  349.       else {
  350.     if (verbose)
  351.       printf("  Using private colormap\n");
  352.  
  353.     /* create new colormap
  354.      */
  355.  
  356.     ximageinfo->cmap= XCreateColormap(disp, RootWindow(disp, scrn),
  357.                       visual, AllocNone);
  358.       }
  359.  
  360.       for (a= 0; a < image->rgb.used; a++) /* count entries we got */
  361.     if (! XAllocColorCells(disp, ximageinfo->cmap, False, NULL, 0,
  362.                    index + a, 1))
  363.       break;
  364.  
  365.       if (fit) {
  366.     if (a > 0)
  367.       XFreeColors(disp, ximageinfo->cmap, index, a, 0);
  368.     if (a <= 2) {
  369.       if (verbose) {
  370.         printf("  Cannot fit into default colormap, dithering...");
  371.         fflush(stdout);
  372.       }
  373.       image= dither(image, 0);
  374.       if (verbose)
  375.         printf("done\n");
  376.       fit= 0;
  377.       lfree((byte *)index);
  378.       XUngrabServer(disp);
  379.       goto retry;
  380.     }
  381.       }
  382.  
  383.       if (a == 0) {
  384.     fprintf(stderr, "imageToXImage: Color allocation failed!\n");
  385.     lfree((byte *)index);
  386.     XUngrabServer(disp);
  387.     return(NULL);
  388.       }
  389.  
  390.       if (a < image->rgb.used)
  391.     image= reduce(image, a, verbose);
  392.  
  393.       if (fit) {
  394.     for (a= 0; a < image->rgb.used; a++) {
  395.       xcolor.red= *(image->rgb.red + a);
  396.       xcolor.green= *(image->rgb.green + a);
  397.       xcolor.blue= *(image->rgb.blue + a);
  398.  
  399.       /* if this fails we're in trouble
  400.        */
  401.  
  402.       if (! XAllocColor(disp, ximageinfo->cmap, &xcolor)) {
  403.         XUngrabServer(disp);
  404.         printf("XAllocColor failed while fitting colormap!\n");
  405.         return(NULL);
  406.       }
  407.       *(index + a)= xcolor.pixel;
  408.     }
  409.     XUngrabServer(disp);
  410.       }
  411.       else {
  412.     for (b= 0; b < a; b++) {
  413.       xcolor.pixel= *(index + b);
  414.       xcolor.red= *(image->rgb.red + b);
  415.       xcolor.green= *(image->rgb.green + b);
  416.       xcolor.blue= *(image->rgb.blue + b);
  417.       XStoreColor(disp, ximageinfo->cmap, &xcolor);
  418.     }
  419.       }
  420.     }
  421.     break;
  422.   }
  423.  
  424.   /* create an XImage and related colormap based on the image type
  425.    * we have.
  426.    */
  427.  
  428.   if (verbose) {
  429.     printf("  Building XImage...");
  430.     fflush(stdout);
  431.   }
  432.  
  433.   switch (image->type) {
  434.   case IBITMAP:
  435.     { byte *data;
  436.  
  437.       /* we copy the data to be more consistent
  438.        */
  439.  
  440.       data= lmalloc((image->width + 7) / 8 * image->height);
  441.       bcopy(image->data, data, ((image->width + 7) / 8) * image->height);
  442.  
  443.       gcv.function= GXcopy;
  444.       ximageinfo->ximage= XCreateImage(disp, visual, 1, XYBitmap,
  445.                        0, (char *)data, image->width, image->height,
  446.                        8, 0);
  447.       ximageinfo->depth= ddepth;
  448.       ximageinfo->foreground= *(index + 1);
  449.       ximageinfo->background= *index;
  450.       ximageinfo->ximage->bitmap_bit_order= MSBFirst;
  451.       ximageinfo->ximage->byte_order= MSBFirst;
  452.       break;
  453.     }
  454.  
  455.   case IRGB:
  456.   case ITRUE:
  457.  
  458.     /* modify image data to match visual and colormap
  459.      */
  460.  
  461.     dbits= bitsPerPixelAtDepth(disp, scrn, ddepth);
  462.     ximageinfo->depth= ddepth;
  463.     dpixlen= (dbits + 7) / 8;
  464.  
  465.     switch (visual->class) {
  466.     case DirectColor:
  467.     case TrueColor:
  468.       { byte *data, *destptr, *srcptr;
  469.     Pixel pixval, newpixval;
  470.  
  471.     ximageinfo->ximage = XCreateImage(disp, visual, ddepth, ZPixmap, 0,
  472.                       NULL, image->width, image->height,
  473.                       8, 0);
  474.     data= lmalloc(image->width * image->height * dpixlen);
  475.     ximageinfo->ximage->data= (char *)data;
  476.     destptr= data;
  477.     srcptr= image->data;
  478.     switch (image->type) {
  479.     case ITRUE:
  480.       for (y= 0; y < image->height; y++)
  481.         for (x= 0; x < image->width; x++) {
  482.           pixval= memToVal(srcptr, image->pixlen);
  483.           newpixval= redvalue[TRUE_RED(pixval)] |
  484.         greenvalue[TRUE_GREEN(pixval)] | bluevalue[TRUE_BLUE(pixval)];
  485.           valToMem(newpixval, destptr, dpixlen);
  486.           srcptr += image->pixlen;
  487.           destptr += dpixlen;
  488.         }
  489.       break;
  490.     case IRGB:
  491.       for (y= 0; y < image->height; y++)
  492.         for (x= 0; x < image->width; x++) {
  493.           pixval= memToVal(srcptr, image->pixlen);
  494.           pixval= redvalue[image->rgb.red[pixval] >> 8] |
  495.         greenvalue[image->rgb.green[pixval] >> 8] |
  496.           bluevalue[image->rgb.blue[pixval] >> 8];
  497.           valToMem(pixval, destptr, dpixlen);
  498.           srcptr += image->pixlen;
  499.           destptr += dpixlen;
  500.         }
  501.       break;
  502.     default: /* something's broken */
  503.       printf("Unexpected image type for DirectColor/TrueColor visual!\n");
  504.       exit(0);
  505.     }
  506.     ximageinfo->ximage->byte_order= MSBFirst; /* trust me, i know what
  507.                            * i'm talking about */
  508.     break;
  509.       }
  510.     default:
  511.  
  512.       /* only IRGB images make it this far.
  513.        */
  514.  
  515.       /* if our XImage doesn't have modulus 8 bits per pixel, it's unclear
  516.        * how to pack bits so we instead use an XYPixmap image.  this is
  517.        * slower.
  518.        */
  519.  
  520.       if (dbits % 8) {
  521.     byte *data, *destdata, *destptr, *srcptr, mask;
  522.     Pixel pixmask, pixval;
  523.  
  524.     ximageinfo->ximage = XCreateImage(disp, visual, ddepth, XYPixmap, 0,
  525.                       NULL, image->width, image->height,
  526.                       8, 0);
  527.  
  528.     data= (byte *)lmalloc(image->width * image->height * dpixlen);
  529.     ximageinfo->ximage->data= (char *)data;
  530.     bzero(data, image->width * image->height * dpixlen);
  531.     ximageinfo->ximage->bitmap_bit_order= MSBFirst;
  532.     ximageinfo->ximage->byte_order= MSBFirst;
  533.     linelen= (image->width + 7) / 8;
  534.     for (a= 0; a < dbits; a++) {
  535.       pixmask= 1 << a;
  536.       destdata= data + ((ddepth - a - 1) * image->height * linelen);
  537.       srcptr= image->data;
  538.       for (y= 0; y < image->height; y++) {
  539.         destptr= destdata + (y * linelen);
  540.         *destptr= 0;
  541.         mask= 0x80;
  542.         for (x= 0; x < image->width; x++) {
  543.           pixval= memToVal(srcptr, image->pixlen);
  544.           srcptr += image->pixlen;
  545.           if (index[pixval] & pixmask)
  546.         *destptr |= mask;
  547.           mask >>= 1;
  548.           if (mask == 0) {
  549.         mask= 0x80;
  550.         destptr++;
  551.           }
  552.         }
  553.       }
  554.     }
  555.       }
  556.       else {
  557.     byte *data, *srcptr, *destptr;
  558.  
  559.     ximageinfo->ximage = XCreateImage(disp, visual, ddepth, ZPixmap, 0,
  560.                       NULL, image->width, image->height,
  561.                       8, 0);
  562.  
  563.     dpixlen= (ximageinfo->ximage->bits_per_pixel + 7) / 8;
  564.     data= (byte *)lmalloc(image->width * image->height * dpixlen);
  565.     ximageinfo->ximage->data= (char *)data;
  566.     ximageinfo->ximage->byte_order= MSBFirst; /* trust me, i know what
  567.                            * i'm talking about */
  568.     srcptr= image->data;
  569.     destptr= data;
  570.     for (y= 0; y < image->height; y++)
  571.       for (x= 0; x < image->width; x++) {
  572.         valToMem(index[memToVal(srcptr, image->pixlen)], destptr, dpixlen);
  573.         srcptr += image->pixlen;
  574.         destptr += dpixlen;
  575.       }
  576.       }
  577.       break;
  578.     }
  579.   }
  580.  
  581.   if (verbose)
  582.     printf("done\n");
  583.  
  584.   if (index)
  585.     lfree((byte *)index);
  586.   if (redvalue) {
  587.     lfree((byte *)redvalue);
  588.     lfree((byte *)greenvalue);
  589.     lfree((byte *)bluevalue);
  590.   }
  591.   if (image != orig_image)
  592.     freeImage(image);
  593.   return(ximageinfo);
  594. }
  595.  
  596. /* Given an XImage and a drawable, move a rectangle from the Ximage
  597.  * to the drawable.
  598.  */
  599.  
  600. void sendXImage(ximageinfo, src_x, src_y, dst_x, dst_y, w, h)
  601.      XImageInfo  *ximageinfo;
  602.      int          src_x, src_y, dst_x, dst_y;
  603.      unsigned int w, h;
  604. { XGCValues gcv;
  605.   int a, orig_depth;
  606.   char *orig_data;
  607.  
  608.   /* build and cache the GC
  609.    */
  610.  
  611.   if (!ximageinfo->gc) {
  612.     gcv.function= GXcopy;
  613.     if (ximageinfo->ximage->depth == 1) {
  614.       gcv.foreground= ximageinfo->foreground;
  615.       gcv.background= ximageinfo->background;
  616.       ximageinfo->gc= XCreateGC(ximageinfo->disp, ximageinfo->drawable,
  617.                 GCFunction | GCForeground | GCBackground,
  618.                 &gcv);
  619.     }
  620.     else
  621.       ximageinfo->gc= XCreateGC(ximageinfo->disp, ximageinfo->drawable,
  622.                 GCFunction, &gcv);
  623.   }
  624.  
  625.   XPutImage(ximageinfo->disp, ximageinfo->drawable, ximageinfo->gc,
  626.         ximageinfo->ximage, src_x, src_y, dst_x, dst_y, w, h);
  627. }
  628.  
  629. /* free up anything cached in the local Ximage structure.
  630.  */
  631.  
  632. void freeXImage(image, ximageinfo)
  633.      Image        *image;
  634.      XImageInfo   *ximageinfo;
  635. {
  636.   if (ximageinfo->gc)
  637.     XFreeGC(ximageinfo->disp, ximageinfo->gc);
  638.   lfree((byte *)ximageinfo->ximage->data);
  639.   ximageinfo->ximage->data= NULL;
  640.   XDestroyImage(ximageinfo->ximage);
  641.   lfree((byte *)ximageinfo);
  642. }
  643.