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