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