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