rnd-19980904-1
[rocksndiamonds.git] / src / send.c
1
2 /* send.c
3  *
4  * send an Image to an X pixmap
5  */
6
7 #include "xli.h"
8
9 /* extra colors to try allocating in private color maps to minimise flashing */
10 #define NOFLASH_COLORS 256
11
12 Image *monochrome(Image *cimage)
13 {
14   Image         *image;
15   unsigned char *sp, *dp, *dp2; /* data pointers */
16   unsigned int   spl;           /* source pixel length in bytes */
17   unsigned int   dll;           /* destination line length in bytes */
18   Pixel          color;         /* pixel color */
19   unsigned int   x, y;          /* random counters */
20   int bitmap_pixel;
21
22   if (BITMAPP(cimage))
23     return(NULL);
24
25   printf("  Converting to monochrome...");
26   fflush(stdout);
27
28   image= newBitImage(cimage->width, cimage->height);
29   if (cimage->title)
30   {
31     image->title= (char *)lmalloc(strlen(cimage->title) + 13);
32     sprintf(image->title, "%s (monochrome)", cimage->title);
33   }
34
35   spl = cimage->pixlen;
36   dll = (image->width / 8) + (image->width % 8 ? 1 : 0);
37
38   sp = cimage->data;
39   dp = image->data;
40
41   for (y= 0; y < cimage->height; y++)
42   {
43     for (x= 0; x < cimage->width; x++)
44     {
45       dp2 = dp + (x / 8);       /* dp + x/8 */
46       color= memToVal(sp, spl);
47
48       if (cimage->rgb.red[color] > 0x0000 ||
49           cimage->rgb.green[color] > 0x0000 ||
50           cimage->rgb.blue[color] > 0x0000)
51         bitmap_pixel = 0x00;
52       else
53         bitmap_pixel = 0x80;
54
55       *dp2 |= bitmap_pixel >> ( x % 8);
56       sp += spl;
57     }
58
59     dp += dll;  /* next row */
60   }
61
62   printf("done\n");
63
64   return(image);
65 }
66
67 static unsigned int *buildIndex(unsigned int width,
68                                 unsigned int zoom,
69                                 unsigned int *rwidth)
70 {
71   float         fzoom;
72   unsigned int *index;
73   unsigned int  a;
74
75   if (!zoom)
76   {
77     fzoom= 100.0;
78     *rwidth= width;
79   }
80   else
81   {
82     fzoom= (float)zoom / 100.0;
83     *rwidth= (unsigned int)(fzoom * width + 0.5);
84   }
85   index= (unsigned int *)lmalloc(sizeof(unsigned int) * *rwidth);
86   for (a= 0; a < *rwidth; a++)
87   {
88     if (zoom)
89       *(index + a)= (unsigned int)((float)a / fzoom + 0.5);
90     else
91       *(index + a)= a;
92   }
93   return(index);
94 }
95
96 Image *zoom(Image *oimage, unsigned int xzoom, unsigned int yzoom)
97 {
98   Image        *image;
99   unsigned int *xindex, *yindex;
100   unsigned int  xwidth, ywidth;
101   unsigned int  x, y, xsrc, ysrc;
102   unsigned int  pixlen;
103   unsigned int  srclinelen;
104   unsigned int  destlinelen;
105   byte         *srcline, *srcptr;
106   byte         *destline, *destptr;
107   byte          srcmask, destmask, bit;
108   Pixel         value;
109
110   if ((!xzoom || xzoom==100) && (!yzoom || yzoom==100)) 
111     return(oimage);
112
113   if (!xzoom)
114     printf("  Zooming image Y axis by %d%%...", yzoom);
115   else if (!yzoom)
116     printf("  Zooming image X axis by %d%%...", xzoom);
117   else if (xzoom == yzoom)
118     printf("  Zooming image by %d%%...", xzoom);
119   else
120     printf("  Zooming image X axis by %d%% and Y axis by %d%%...",
121              xzoom, yzoom);
122   fflush(stdout);
123
124   xindex= buildIndex(oimage->width, xzoom, &xwidth);
125   yindex= buildIndex(oimage->height, yzoom, &ywidth);
126
127   switch (oimage->type)
128   {
129     case IBITMAP:
130       image= newBitImage(xwidth, ywidth);
131       for (x= 0; x < oimage->rgb.used; x++)
132       {
133         *(image->rgb.red + x)= *(oimage->rgb.red + x);
134         *(image->rgb.green + x)= *(oimage->rgb.green + x);
135         *(image->rgb.blue + x)= *(oimage->rgb.blue + x);
136       }
137       image->rgb.used= oimage->rgb.used;
138       destline= image->data;
139       destlinelen= (xwidth / 8) + (xwidth % 8 ? 1 : 0);
140       srcline= oimage->data;
141       srclinelen= (oimage->width / 8) + (oimage->width % 8 ? 1 : 0);
142       for (y= 0, ysrc= *(yindex + y); y < ywidth; y++)
143       {
144         while (ysrc != *(yindex + y))
145         {
146           ysrc++;
147           srcline += srclinelen;
148         }
149         srcptr= srcline;
150         destptr= destline;
151         srcmask= 0x80;
152         destmask= 0x80;
153         bit= srcmask & *srcptr;
154         for (x= 0, xsrc= *(xindex + x); x < xwidth; x++)
155         {
156           if (xsrc != *(xindex + x))
157           {
158             do
159             {
160               xsrc++;
161               if (!(srcmask >>= 1))
162               {
163                 srcmask= 0x80;
164                 srcptr++;
165               }
166             }
167             while (xsrc != *(xindex + x));
168
169             bit= srcmask & *srcptr;
170           }
171           if (bit)
172             *destptr |= destmask;
173           if (!(destmask >>= 1))
174           {
175             destmask= 0x80;
176             destptr++;
177           }
178         }
179         destline += destlinelen;
180       }
181       break;
182
183     case IRGB:
184       image= newRGBImage(xwidth, ywidth, oimage->depth);
185       for (x= 0; x < oimage->rgb.used; x++)
186       {
187         *(image->rgb.red + x)= *(oimage->rgb.red + x);
188         *(image->rgb.green + x)= *(oimage->rgb.green + x);
189         *(image->rgb.blue + x)= *(oimage->rgb.blue + x);
190       }
191       image->rgb.used= oimage->rgb.used;
192
193       pixlen= oimage->pixlen;
194       destptr= image->data;
195       srcline= oimage->data;
196       srclinelen= oimage->width * pixlen;
197       for (y= 0, ysrc= *(yindex + y); y < ywidth; y++)
198       {
199         while (ysrc != *(yindex + y))
200         {
201           ysrc++;
202           srcline += srclinelen;
203         }
204
205         srcptr = srcline;
206         value = memToVal(srcptr, image->pixlen);
207
208         for (x=0, xsrc= *(xindex + x); x<xwidth; x++)
209         {
210           if (xsrc != *(xindex + x))
211           {
212             do
213             {
214               xsrc++;
215               srcptr++;
216             }
217             while (xsrc != *(xindex + x));
218             value = memToVal(srcptr, 1);
219           }
220           valToMem(value, destptr, 1);
221           destptr++;
222         }
223       }
224       break;
225
226     default:
227       /* no zooming */
228       return(oimage);
229       break;
230   }
231
232   image->title = dupString(oimage->title);
233   lfree((byte *)xindex);
234   lfree((byte *)yindex);
235
236   printf("done\n");
237
238   return(image);
239 }
240
241 void compress(Image *image)
242 {
243   unsigned char   *used, fast[32][32][32];
244   unsigned int     dmask;       /* Depth mask protection */
245   Pixel           *map;
246   unsigned int     next_index;
247   Intensity *red = image->rgb.red,
248             *green = image->rgb.green,
249             *blue = image->rgb.blue;
250   Intensity r,g,b;
251   unsigned int x, y, badcount = 0, dupcount = 0, unusedcount = 0;
252   unsigned char *pixptr, *pixend;
253
254   if (!RGBP(image) || image->rgb.compressed)
255     return;
256
257   printf("  Compressing colormap...");
258   fflush(stdout);
259
260   used = (unsigned char *)lcalloc(sizeof(unsigned char) * depthToColors(image->depth));
261   dmask = (1 << image->depth) -1;       /* Mask any illegal bits for that depth */
262   map = (Pixel *)lcalloc(sizeof(Pixel) * depthToColors(image->depth));
263
264   /* init fast duplicate check table */
265   for(r=0;r<32;r++)
266     for(g=0;g<32;g++)
267       for(b=0;b<32;b++)
268         fast[r][g][b] = 0;
269
270   /* do pass 1 through the image to check index usage */
271
272   pixptr = image->data;
273   pixend = pixptr + (image->height * image->width);
274   for(;pixptr < pixend; pixptr++)
275     used[(*pixptr) & dmask] = 1;
276
277   /* count the bad pixels */
278   for (x = image->rgb.used; x < depthToColors(image->depth); x++)
279     if (used[x])
280       badcount++;
281
282   /* figure out duplicates and unuseds, and create the new mapping */
283   next_index = 0;
284   for (x = 0; x < image->rgb.used; x++)
285   {
286     if (!used[x])
287     {
288       unusedcount++;
289       continue;         /* delete this index */
290     }
291
292     /* check for duplicate */
293     r = red[x];
294     g = green[x];
295     b = blue[x];
296     if (fast[r>>11][g>>11][b>>11])      /* if matches fast check */
297     {
298       /* then do a linear search */
299       for (y = x+1; y < image->rgb.used; y++)
300       {
301         if (r == red[y] && g == green[y] && b == blue[y])
302           break;
303       }
304       if (y < image->rgb.used)  /* found match */
305       {
306         map[x] = y;
307         dupcount++;
308         continue;               /* delete this index */
309       }
310       fast[r>>11][g>>11][b>>11] = 1;
311     }
312     /* will map to this index */
313     map[x] = next_index;
314     next_index++;
315   }
316
317   /* change the image pixels */
318   pixptr = image->data;
319   pixend = pixptr + (image->height * image->width);
320   for(;pixptr < pixend; pixptr++)
321     *pixptr = map[(*pixptr) & dmask];
322
323   /* change the colormap */
324   for (x = 0; x < image->rgb.used; x++)
325   {
326     if (!used[x])
327       continue;
328     red[map[x]] = red[x];
329     green[map[x]] = green[x];
330     blue[map[x]] = blue[x];
331   }
332   image->rgb.used = next_index;
333
334   /* clean up */
335   lfree(map);
336   lfree(used);
337
338   if (badcount)
339     printf("%d out-of-range pixels, ", badcount);
340
341   if (!unusedcount && !dupcount)
342     printf("no improvment\n");
343   else
344   {
345     if (dupcount)
346       printf("%d duplicate%s and %d unused color%s removed...",
347              dupcount, (dupcount == 1 ? "" : "s"),
348              unusedcount, (unusedcount == 1 ? "" : "s"));
349     printf("%d unique color%s\n",
350            next_index, (next_index == 1 ? "" : "s"));
351   }
352
353   image->rgb.compressed= TRUE;  /* don't do it again */
354 }
355
356
357
358
359 Pixmap ximageToPixmap(Display *disp, Window parent, XImageInfo *ximageinfo)
360 {
361   Pixmap pixmap;
362
363   pixmap = XCreatePixmap(disp, parent,
364                          ximageinfo->ximage->width, ximageinfo->ximage->height,
365                          ximageinfo->depth);
366
367   ximageinfo->drawable = pixmap;
368
369   sendXImage(ximageinfo, 0, 0, 0, 0,
370              ximageinfo->ximage->width, ximageinfo->ximage->height);
371   return(pixmap);
372 }
373
374 /* find the best pixmap depth supported by the server for a particular
375  * visual and return that depth.
376  *
377  * this is complicated by R3's lack of XListPixmapFormats so we fake it
378  * by looking at the structure ourselves.
379  */
380
381 static unsigned int bitsPerPixelAtDepth(Display *disp, int scrn,
382                                         unsigned int depth)
383 {
384 #if defined(XlibSpecificationRelease) && (XlibSpecificationRelease >= 4)
385   /* the way things are */
386   XPixmapFormatValues *xf;
387   int nxf, a;
388
389   xf = XListPixmapFormats(disp, &nxf);
390   for (a = 0; a < nxf; a++)
391   {
392     if (xf[a].depth == depth)
393     {
394       int bpp;
395       bpp = xf[a].bits_per_pixel;
396       XFree(xf);
397       return (unsigned int) bpp;
398     }
399   }
400   XFree(xf);
401 #else /* the way things were (X11R3) */
402   unsigned int a;
403
404   for (a= 0; a < disp->nformats; a++)
405     if (disp->pixmap_format[a].depth == depth)
406       return(disp->pixmap_format[a].bits_per_pixel);
407 #endif
408
409   /* this should never happen; if it does, we're in trouble
410    */
411
412   fprintf(stderr, "bitsPerPixelAtDepth: Can't find pixmap depth info!\n");
413   exit(1);
414 }
415
416 /*
417   visual: visual to use
418   ddepth: depth of the visual to use
419 */
420 XImageInfo *imageToXImage(Display *disp,
421                           int scrn,
422                           Visual *visual,
423                           unsigned int ddepth,
424                           Image *image)
425 {
426   Pixel        *redvalue, *greenvalue, *bluevalue;
427   unsigned int  a, c=0, x, y, linelen, dpixlen, dbits;
428   XColor        xcolor;
429   XGCValues     gcv;
430   XImageInfo   *ximageinfo;
431   Image        *orig_image;
432
433   static Colormap our_default_cmap = 0;
434   static Pixel *our_default_index;
435   static int free_cmap_entries, max_cmap_entries;
436   int use_cmap_entry;
437
438   if (!our_default_cmap)
439   {
440 #if 0
441     our_default_cmap = DefaultColormap(disp, scrn);
442 #endif
443
444     our_default_cmap = XCreateColormap(disp, RootWindow(disp, scrn),
445                                        visual, AllocNone);
446     our_default_index = (Pixel *)lmalloc(sizeof(Pixel) * NOFLASH_COLORS);
447
448     for (a=0; a<NOFLASH_COLORS; a++)    /* count entries we got */
449       if (!XAllocColorCells(disp, our_default_cmap, FALSE, NULL, 0,
450                             our_default_index + a, 1))
451         break;
452
453     free_cmap_entries = max_cmap_entries = a;
454
455     printf("We've got %d colormap entries.\n", free_cmap_entries);
456
457     for(a=0; a<max_cmap_entries; a++)   /* copy default colors */
458     {
459       xcolor.pixel = *(our_default_index + a);
460       XQueryColor(disp, DefaultColormap(disp, scrn), &xcolor);
461       XStoreColor(disp, our_default_cmap, &xcolor);
462     }
463   }
464
465   xcolor.flags= DoRed | DoGreen | DoBlue;
466   redvalue= greenvalue= bluevalue= NULL;
467   orig_image= image;
468   ximageinfo= (XImageInfo *)lmalloc(sizeof(XImageInfo));
469   ximageinfo->disp= disp;
470   ximageinfo->scrn= scrn;
471   ximageinfo->depth= 0;
472   ximageinfo->drawable= None;
473   ximageinfo->index= NULL;
474   ximageinfo->rootimage= FALSE; /* assume not */
475   ximageinfo->foreground= ximageinfo->background= 0;
476   ximageinfo->gc= NULL;
477   ximageinfo->ximage= NULL;
478
479   /* do color allocation
480    */
481
482   switch (visual->class)
483   {
484     case TrueColor:
485     case DirectColor:
486     {
487       Pixel pixval;
488       unsigned int redcolors, greencolors, bluecolors;
489       unsigned int redstep, greenstep, bluestep;
490       unsigned int redbottom, greenbottom, bluebottom;
491       unsigned int redtop, greentop, bluetop;
492
493       redvalue= (Pixel *)lmalloc(sizeof(Pixel) * 256);
494       greenvalue= (Pixel *)lmalloc(sizeof(Pixel) * 256);
495       bluevalue= (Pixel *)lmalloc(sizeof(Pixel) * 256);
496
497 #if 1
498       if (visual == DefaultVisual(disp, scrn))
499         ximageinfo->cmap= DefaultColormap(disp, scrn);
500       else
501         ximageinfo->cmap= XCreateColormap(disp, RootWindow(disp, scrn),
502                                           visual, AllocNone);
503 #else
504       ximageinfo->cmap = our_default_cmap;
505 #endif
506
507       retry_direct: /* tag we hit if a DirectColor allocation fails on
508                      * default colormap */
509
510       /* calculate number of distinct colors in each band
511        */
512
513       redcolors= greencolors= bluecolors= 1;
514       for (pixval= 1; pixval; pixval <<= 1)
515       {
516         if (pixval & visual->red_mask)
517           redcolors <<= 1;
518         if (pixval & visual->green_mask)
519           greencolors <<= 1;
520         if (pixval & visual->blue_mask)
521           bluecolors <<= 1;
522       }
523       
524       /* sanity check
525        */
526
527       if ((redcolors > visual->map_entries) ||
528           (greencolors > visual->map_entries) ||
529           (bluecolors > visual->map_entries))
530       {
531         fprintf(stderr, "Warning: inconsistency in color information (this may be ugly)\n");
532       }
533
534       redstep = 256 / redcolors;
535       greenstep = 256 / greencolors;
536       bluestep = 256 / bluecolors;
537       redbottom = greenbottom = bluebottom = 0;
538       redtop = greentop = bluetop = 0;
539       for (a= 0; a < visual->map_entries; a++)
540       {
541         if (redbottom < 256)
542           redtop= redbottom + redstep;
543         if (greenbottom < 256)
544           greentop= greenbottom + greenstep;
545         if (bluebottom < 256)
546           bluetop= bluebottom + bluestep;
547
548         xcolor.red= (redtop - 1) << 8;
549         xcolor.green= (greentop - 1) << 8;
550         xcolor.blue= (bluetop - 1) << 8;
551         if (! XAllocColor(disp, ximageinfo->cmap, &xcolor))
552         {
553           /* if an allocation fails for a DirectColor default visual then
554            * we should create a private colormap and try again.
555            */
556
557           if ((visual->class == DirectColor) &&
558               (visual == DefaultVisual(disp, scrn)))
559           {
560 #if 1
561             ximageinfo->cmap = XCreateColormap(disp, RootWindow(disp, scrn),
562                                                visual, AllocNone);
563 #else
564             our_default_cmap = XCopyColormapAndFree(disp, our_default_cmap);
565             ximageinfo->cmap = our_default_cmap;
566 #endif
567             goto retry_direct;
568           }
569
570           /* something completely unexpected happened
571            */
572
573           fprintf(stderr, "imageToXImage: XAllocColor failed on a TrueColor/Directcolor visual\n");
574           lfree((byte *)redvalue);
575           lfree((byte *)greenvalue);
576           lfree((byte *)bluevalue);
577           lfree((byte *)ximageinfo);
578           return(NULL);
579         }
580
581         /* fill in pixel values for each band at this intensity
582          */
583
584         while ((redbottom < 256) && (redbottom < redtop))
585           redvalue[redbottom++]= xcolor.pixel & visual->red_mask;
586         while ((greenbottom < 256) && (greenbottom < greentop))
587           greenvalue[greenbottom++]= xcolor.pixel & visual->green_mask;
588         while ((bluebottom < 256) && (bluebottom < bluetop))
589           bluevalue[bluebottom++]= xcolor.pixel & visual->blue_mask;
590       }
591     }
592     break;
593
594   default:      /* Not TrueColor or DirectColor */
595
596     ximageinfo->index= (Pixel *)lmalloc(sizeof(Pixel) * (image->rgb.used+NOFLASH_COLORS));
597
598
599     /* get the colormap to use.
600      */
601
602     ximageinfo->cmap = our_default_cmap;
603
604     /* allocate colors shareable (if we can)
605      */
606
607     for (a= 0; a < image->rgb.used; a++)
608     {
609       int i;
610       XColor xcolor2;
611
612       xcolor.red= *(image->rgb.red + a);
613       xcolor.green= *(image->rgb.green + a);
614       xcolor.blue= *(image->rgb.blue + a);
615
616       for (i=max_cmap_entries-1; i>=free_cmap_entries; i--)
617       {
618         xcolor2.pixel = *(our_default_index + i);
619         XQueryColor(disp, ximageinfo->cmap, &xcolor2);
620
621         if ((xcolor.red >> 8) == (xcolor2.red >> 8) &&
622             (xcolor.green >> 8) == (xcolor2.green >> 8) &&
623             (xcolor.blue >> 8) == (xcolor2.blue >> 8))
624           break;
625       }
626
627       use_cmap_entry = i;
628
629       if (use_cmap_entry < free_cmap_entries)
630         free_cmap_entries--;
631
632       if (free_cmap_entries < 0)
633       {
634         printf("imageToXImage: too many global colors!\n");
635         exit(0);
636       }
637
638       xcolor.pixel = use_cmap_entry;
639       *(ximageinfo->index + a) = xcolor.pixel;
640       XStoreColor(disp, ximageinfo->cmap, &xcolor);
641     }
642
643     ximageinfo->no = a;    /* number of pixels allocated in default visual */
644
645     printf("still %d free colormap entries\n", free_cmap_entries);
646   }
647
648
649
650   /* create an XImage and related colormap based on the image type
651    * we have.
652    */
653
654   printf("  Building XImage...");
655   fflush(stdout);
656
657   switch (image->type)
658   {
659     case IBITMAP:
660     {
661       byte *data;
662
663       /* we copy the data to be more consistent
664        */
665
666       linelen = ((image->width + 7) / 8);
667       data= lmalloc(linelen * image->height);
668
669       memcpy((char *)data, (char *)image->data, linelen * image->height);
670
671       gcv.function= GXcopy;
672       ximageinfo->ximage= XCreateImage(disp, visual, 1, XYBitmap,
673                                        0, (char *)data, image->width, image->height,
674                                        8, linelen);
675
676       /* use this if you want to use the bitmap as a mask */
677       ximageinfo->depth = image->depth;
678
679       if(visual->class == DirectColor || visual->class == TrueColor)
680       {
681         Pixel pixval;
682         dbits= bitsPerPixelAtDepth(disp, scrn, ddepth);
683         dpixlen= (dbits + 7) / 8;
684         pixval= redvalue[image->rgb.red[0] >> 8] |
685                 greenvalue[image->rgb.green[0] >> 8] |
686                 bluevalue[image->rgb.blue[0] >> 8];
687         ximageinfo->background = pixval;
688         pixval= redvalue[image->rgb.red[1] >> 8] |
689                 greenvalue[image->rgb.green[1] >> 8] |
690                 bluevalue[image->rgb.blue[1] >> 8];
691         ximageinfo->foreground = pixval;
692       }
693       else      /* Not Direct or True Color */
694       {
695         ximageinfo->foreground = BlackPixel(disp,scrn);
696         ximageinfo->background = WhitePixel(disp,scrn);
697       }
698       ximageinfo->ximage->bitmap_bit_order= MSBFirst;
699       ximageinfo->ximage->byte_order= MSBFirst;
700
701       break;
702     }
703
704     case IRGB:
705     {
706       /* modify image data to match visual and colormap
707        */
708
709       byte *data, *destptr, *srcptr;
710
711       dbits = bitsPerPixelAtDepth(disp, scrn, ddepth);  /* bits per pixel */
712       dpixlen = (dbits + 7) / 8;                        /* bytes per pixel */
713
714       ximageinfo->ximage = XCreateImage(disp, visual, ddepth, ZPixmap, 0,
715                                         NULL, image->width, image->height,
716                                         8, image->width * dpixlen);
717
718       data = (byte *)lmalloc(image->width * image->height * dpixlen);
719       ximageinfo->depth = ddepth;
720       ximageinfo->ximage->data = (char *)data;
721       ximageinfo->ximage->byte_order = MSBFirst;
722       srcptr = image->data;
723       destptr = data;
724
725       switch (visual->class)
726       {
727         case DirectColor:
728         case TrueColor:
729         {
730           Pixel pixval;
731
732           for (y=0; y<image->height; y++)
733           {
734             for (x=0; x<image->width; x++)
735             {
736               pixval = memToVal(srcptr, 1);
737               pixval = redvalue[image->rgb.red[pixval] >> 8] |
738                 greenvalue[image->rgb.green[pixval] >> 8] |
739                 bluevalue[image->rgb.blue[pixval] >> 8];
740               valToMem(pixval, destptr, dpixlen);
741               srcptr += 1;
742               destptr += dpixlen;
743             }
744           }
745           break;
746         }
747   
748         default:
749         {  
750           if (dpixlen == 1)                     /* most common */
751           {
752             for (y=0; y<image->height; y++)
753             {
754               for (x=0; x<image->width; x++)
755               {
756                 *destptr = ximageinfo->index[c + *srcptr];
757                 srcptr++;
758                 destptr++;
759               }
760             }
761           }
762           else                                  /* less common */
763           {
764             for (y=0; y<image->height; y++)
765             {
766               for (x=0; x<image->width; x++)
767               {
768                 register unsigned long temp;
769                 temp = memToVal(srcptr, 1);
770                 valToMem(ximageinfo->index[c + temp], destptr, dpixlen);
771                 srcptr += 1;
772                 destptr += dpixlen;
773               }
774             }
775           }
776         }
777         break;
778       }
779     }
780   }
781
782   printf("done\n");
783
784   if (redvalue)
785   {
786     lfree((byte *)redvalue);
787     lfree((byte *)greenvalue);
788     lfree((byte *)bluevalue);
789   }
790
791   if (image != orig_image)
792     freeImage(image);
793   return(ximageinfo);
794 }
795
796 /* Given an XImage and a drawable, move a rectangle from the Ximage
797  * to the drawable.
798  */
799
800 void sendXImage(XImageInfo *ximageinfo,
801                 int src_x, int src_y, int dst_x, int dst_y,
802                 unsigned int w, unsigned int h)
803 {
804   XGCValues gcv;
805
806   /* build and cache the GC
807    */
808
809   if (!ximageinfo->gc)
810   {
811     gcv.function = GXcopy;
812     if (ximageinfo->ximage->depth == 1)
813     {
814       gcv.foreground = ximageinfo->foreground;
815       gcv.background = ximageinfo->background;
816       ximageinfo->gc = XCreateGC(ximageinfo->disp, ximageinfo->drawable,
817                                  GCFunction | GCForeground | GCBackground,
818                                  &gcv);
819     }
820     else
821       ximageinfo->gc = XCreateGC(ximageinfo->disp, ximageinfo->drawable,
822                                  GCFunction, &gcv);
823   }
824
825   XPutImage(ximageinfo->disp, ximageinfo->drawable, ximageinfo->gc,
826             ximageinfo->ximage, src_x, src_y, dst_x, dst_y, w, h);
827 }
828
829 /* free up anything cached in the local Ximage structure.
830  */
831
832 void freeXImage(Image *image, XImageInfo *ximageinfo)
833 {
834   if (ximageinfo->index != NULL)        /* if we allocated colors */
835   {
836     if (ximageinfo->no > 0 && !ximageinfo->rootimage)   /* don't free root colors */
837       XFreeColors(ximageinfo->disp, ximageinfo->cmap, ximageinfo->index, ximageinfo->no, 0);
838     lfree(ximageinfo->index);
839   }
840   if (ximageinfo->gc)
841     XFreeGC(ximageinfo->disp, ximageinfo->gc);
842   lfree((byte *)ximageinfo->ximage->data);
843   ximageinfo->ximage->data= NULL;
844   XDestroyImage(ximageinfo->ximage);
845   lfree((byte *)ximageinfo);
846   /* should we free private color map to ??? */
847 }