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