1 /* +-------------------------------------------------------------------+ */
2 /* | Copyright 1993, David Koblas (koblas@netcom.com)		       | */
3 /* | Copyright 1995, 1996 Torsten Martinsen (bullestock@dk-online.dk)  | */
4 /* |								       | */
5 /* | Permission to use, copy, modify, and to distribute this software  | */
6 /* | and its documentation for any purpose is hereby granted without   | */
7 /* | fee, provided that the above copyright notice appear in all       | */
8 /* | copies and that both that copyright notice and this permission    | */
9 /* | notice appear in supporting documentation.	 There is no	       | */
10 /* | representations about the suitability of this software for	       | */
11 /* | any purpose.  this software is provided "as is" without express   | */
12 /* | or implied warranty.					       | */
13 /* |								       | */
14 /* +-------------------------------------------------------------------+ */
15 
16 /* $Id: image.c,v 1.17 2005/03/20 20:15:32 demailly Exp $ */
17 
18 #ifdef __VMS
19 #define XtDisplay XTDISPLAY
20 #define XtScreen XTSCREEN
21 #endif
22 
23 #include <X11/Intrinsic.h>
24 #include <X11/StringDefs.h>
25 #include "Paint.h"
26 #include "PaintP.h"
27 #include "xpaint.h"
28 #include "image.h"
29 #include "hash.h"
30 #include "palette.h"
31 #include "misc.h"
32 #include "protocol.h"
33 
34 #define HASH_SIZE	128
35 
36 /*
37 **  Faster macros for "fast" Image <-> XImage loops
38  */
39 
40 #define ZINDEX(x, y, img) (((y) * img->bytes_per_line) + \
41 			   (((x) * img->bits_per_pixel) >> 3))
42 
43 #define ZINDEX32(x, y, img) ((y) * img->bytes_per_line) + ((x) << 2)
44 #define ZINDEX8(x, y, img)  ((y) * img->bytes_per_line) + (x)
45 #define ZINDEX1(x, y, img)  ((y) * img->bytes_per_line) + ((x) >> 3)
46 
47 static void
48 imageToPixmapLoop(Display *, Image *, Palette *, XImage *, Pixmap *);
49 
50 /*
51  * The functions below are written from X11R5 MIT's code (XImUtil.c)
52  *
53  * The idea is to have faster functions than the standard XGetPixel function
54  * to scan the image data. Indeed we can speed up things by suppressing tests
55  * performed for each pixel. We do exactly the same tests but at the image
56  * level. Assuming that we use only ZPixmap images.
57  */
58 
59 static unsigned long low_bits_table[] =
60 {
61     0x00000000, 0x00000001, 0x00000003, 0x00000007,
62     0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
63     0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
64     0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
65     0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
66     0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
67     0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
68     0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
69     0xffffffff
70 };
71 
72 /*
73 **  Actual Image routines
74 **
75 **
76  */
77 
78 
79 Image *
ImageNew(int width,int height)80 ImageNew(int width, int height)
81 {
82     Image *image = XtNew(Image);
83 
84     image->refCount = 1;
85     image->isBW = False;
86     image->isGrey = False;
87     image->cmapPacked = False;
88     image->cmapSize = 0;
89     image->cmapData = NULL;
90     image->width = width;
91     image->height = height;
92     image->sourceColormap = None;
93     image->sourcePixmap = None;
94     image->sourceMask = None;
95     image->scale = 3;
96     image->alpha = NULL;
97     if (width == 0 || height == 0)
98 	image->data = NULL;
99     else
100 	image->data = (unsigned char *) XtMalloc(width * height * sizeof(char) * 3);
101     return image;
102 }
103 
104 Image *
ImageNewCmap(int width,int height,int size)105 ImageNewCmap(int width, int height, int size)
106 {
107     Image *image = ImageNew(0, 0);
108 
109     if (size == 0)
110 	image->scale = 3;
111     else if (size <= 256)
112 	image->scale = 1;
113     else
114 	image->scale = sizeof(short) / sizeof(char);
115 
116     image->width = width;
117     image->height = height;
118     image->data = (unsigned char *)
119 	XtMalloc(width * height * sizeof(char) * image->scale);
120     if (size != 0)
121 	image->cmapData = (unsigned char *) XtMalloc(size * sizeof(char) * 3);
122     image->cmapSize = size;
123 
124     return image;
125 }
126 
127 Image *
ImageNewBW(int width,int height)128 ImageNewBW(int width, int height)
129 {
130     Image *image = ImageNewCmap(width, height, 2);
131 
132     image->isBW = True;
133     image->cmapData[0] = 0;
134     image->cmapData[1] = 0;
135     image->cmapData[2] = 0;
136     image->cmapData[3] = 255;
137     image->cmapData[4] = 255;
138     image->cmapData[5] = 255;
139 
140     return image;
141 }
142 
143 Image *
ImageNewGrey(int width,int height)144 ImageNewGrey(int width, int height)
145 {
146     int i;
147     Image *image = ImageNewCmap(width, height, 256);
148 
149     image->isGrey = True;
150     for (i = 0; i < image->cmapSize; i++) {
151 	image->cmapData[i * 3 + 0] = i;
152 	image->cmapData[i * 3 + 1] = i;
153 	image->cmapData[i * 3 + 2] = i;
154     }
155 
156     return image;
157 }
158 
159 void
ImageMakeMask(Image * image)160 ImageMakeMask(Image * image)
161 {
162     image->alpha = (unsigned char *)
163 	XtMalloc(image->width * image->height * sizeof(char));
164 }
165 
166 void
ImageDelete(Image * image)167 ImageDelete(Image * image)
168 {
169     image->refCount--;
170     if (image->refCount > 0)
171 	return;
172 
173     if (image->cmapSize > 0 && image->cmapData != NULL)
174 	XtFree((XtPointer) image->cmapData);
175     if (image->data != NULL)
176 	XtFree((XtPointer) image->data);
177     if (image->alpha != NULL)
178 	XtFree((XtPointer) image->alpha);
179     XtFree((XtPointer) image);
180 }
181 
182 /*
183  * Straightforward image copy to full color image
184  */
185 void
ImageCopyData(Image * image,Image * output)186 ImageCopyData(Image * image, Image * output)
187 {
188     unsigned char *ip, *op;
189     int x, y;
190 
191     if (output->cmapData) {
192         op = output->data;
193         for (y = 0; y < image->height; y++)
194         for (x = 0; x < image->width; x++) {
195             ip = ImagePixel(image, x, y);
196             *op++ = *ip;
197 	}
198     } else {
199         for (y = 0; y < image->height; y++)
200         for (x = 0; x < image->width; x++) {
201             ip = ImagePixel(image, x, y);
202             op = ImagePixel(output, x, y);
203             memcpy(op, ip, 3);
204 	}
205     }
206 }
207 
208 /*
209 **  Convert a colormap image into a RGB image
210 **    useful for writers which only deal with RGB and not
211 **    colormaps
212  */
213 Image *
ImageToRGB(Image * image)214 ImageToRGB(Image * image)
215 {
216     unsigned char *ip, *op;
217     Image *out;
218     int x, y;
219 
220     if (image->cmapSize == 0) {
221 	image->refCount++;
222 	return image;
223     }
224     out = ImageNew(image->width, image->height);
225     op = image->data;
226 
227     for (y = 0; y < image->height; y++) {
228 	for (x = 0; x < image->width; x++) {
229 	    ip = ImagePixel(image, x, y);
230 	    *op++ = *ip++;
231 	    *op++ = *ip++;
232 	    *op++ = *ip++;
233 	}
234     }
235 
236     out->isBW = image->isBW;
237     out->isGrey = False;
238     out->width = image->width;
239     out->height = image->height;
240 
241     image->cmapPacked = False;
242 
243     return out;
244 }
245 
246 /*
247 **  Create a nice image for writing routines.
248  */
249 Image *
PixmapToImage(Widget w,Pixmap pix,Colormap cmap)250 PixmapToImage(Widget w, Pixmap pix, Colormap cmap)
251 {
252     XImage *xim;
253     Image *image;
254     Display *dpy = XtDisplay(w);
255     int x, y;
256     int width, height;
257     unsigned char *ptr, *data;
258     unsigned short *sptr;
259     int format = 0;
260     void *htable = NULL;
261     Palette *map = PaletteFind(w, cmap);
262     unsigned long lbt;
263 
264     GetPixmapWHD(dpy, pix, &width, &height, NULL);
265     xim = XGetImage(dpy, pix, 0, 0, width, height, AllPlanes, ZPixmap);
266 
267     if (map == NULL)
268 	map = PaletteGetDefault(w);
269 
270     if (map->isMapped) {
271 	unsigned char *cptr;
272 
273 	image = ImageNewCmap(width, height, map->ncolors);
274 	cptr = image->cmapData;
275 
276 	for (y = 0; y < map->ncolors; y++, cptr += 3) {
277 	    XColor *col = PaletteLookup(map, y);
278 	    unsigned char r = col->red >> 8;
279 	    unsigned char g = col->green >> 8;
280 	    unsigned char b = col->blue >> 8;
281 
282 	    cptr[0] = r;
283 	    cptr[1] = g;
284 	    cptr[2] = b;
285 	}
286     } else {
287 	image = ImageNew(width, height);
288     }
289 
290     ptr = image->data;
291     sptr = (unsigned short *) image->data;
292     data = (unsigned char *) xim->data;
293     lbt = low_bits_table[xim->depth];
294 
295     for (y = 0; y < height; y++) {
296 	for (x = 0; x < width; x++) {
297 	    XColor *col;
298 	    Pixel pixel;
299 	    unsigned char r, g, b;
300 
301 	    if (xim->bits_per_pixel == 8)
302 		pixel = data[ZINDEX8(x, y, xim)] & lbt;
303 	    else
304 		pixel = XGetPixel(xim, x, y);
305 
306 	    if (map->isMapped) {
307 		if (map->ncolors <= 256)
308 		    *ptr++ = pixel;
309 		else
310 		    *sptr++ = pixel;
311 
312 		r = image->cmapData[pixel * 3 + 0];
313 		g = image->cmapData[pixel * 3 + 1];
314 		b = image->cmapData[pixel * 3 + 2];
315 	    } else {
316 		col = PaletteLookup(map, pixel);
317 
318 		*ptr++ = r = col->red >> 8;
319 		*ptr++ = g = col->green >> 8;
320 		*ptr++ = b = col->blue >> 8;
321 	    }
322 
323 	    if (r != g || g != b)
324 		format = 2;
325 	    else if (format == 0 && r != 0 && r != 255)
326 		format = 1;
327 	}
328 
329 	if (y % 64 == 0)
330 	    StateTimeStep();
331     }
332 
333     /*
334     **	Check to see if we just created a B&W or Grey scale image?
335      */
336     if (format == 0 || format == 1) {
337 	int newSize;
338 	unsigned char *newMap;
339 	unsigned char *ip;
340 
341 	if (format == 0) {
342 	    newSize = 2;
343 	    newMap = (unsigned char *) XtCalloc(sizeof(char) * 3, 2);
344 	    newMap[0 + 0] = 0;
345 	    newMap[0 + 1] = 0;
346 	    newMap[0 + 2] = 0;
347 	    newMap[3 + 0] = 255;
348 	    newMap[3 + 1] = 255;
349 	    newMap[3 + 2] = 255;
350 	} else {
351 	    newSize = 256;
352 	    newMap = (unsigned char *) XtCalloc(sizeof(char) * 3, 256);
353 	    for (y = 0; y < 256; y++) {
354 		newMap[y * 3 + 0] = y;
355 		newMap[y * 3 + 1] = y;
356 		newMap[y * 3 + 2] = y;
357 	    }
358 	}
359 
360 	/* overwrite top of image->data with compressed version (scale == 1) */
361 	ip = image->data;
362 	for (y = 0; y < height; y++) {
363 	    for (x = 0; x < width; x++, ip++) {
364 		unsigned char *rgb;
365 
366 		/* [image.h] return pointer to RGB triplet for pixel (x,y) */
367 		rgb = ImagePixel(image, x, y);
368 
369 		/* we know we're B&W or grayscale, so check only red values */
370 		if (format == 0 && *rgb == 255) {
371 		    *ip = 1;
372 		} else {
373 		    *ip = *rgb;
374 		}
375 	    }
376 	}
377 
378 	if (image->cmapData != NULL)
379 	    XtFree((XtPointer) image->cmapData);
380 
381 	image->cmapSize = newSize;
382 	image->cmapData = newMap;
383 
384 	if (format == 0)
385 	    image->isBW = True;
386 	else /* if (format == 1) */	/* [GRR 20010720:  necessarily true] */
387 	    image->isGrey = True;
388 	image->scale = 1;
389     }
390     image->sourceColormap = (unsigned long) cmap;
391     image->sourcePixmap = (unsigned long) pix;
392 
393 
394     if (htable != NULL)
395 	HashDestroy(htable);
396     XDestroyImage(xim);
397 
398     return image;
399 }
400 
401 void
PixmapToImageMask(Widget w,Image * image,Pixmap mask)402 PixmapToImageMask(Widget w, Image * image, Pixmap mask)
403 {
404     XImage *xim;
405     int width, height;
406     int x, y, endX, endY;
407     unsigned char *ip;
408     Display *dpy = XtDisplay(w);
409 
410     if (!image->alpha) return;
411     image->sourceMask = mask;
412     GetPixmapWHD(dpy, mask, &width, &height, NULL);
413     xim = XGetImage(dpy, mask, 0, 0, width, height, AllPlanes, ZPixmap);
414 
415     ImageMakeMask(image);
416     ip = image->alpha;
417 
418     if ((endX = image->width) > width)
419 	endX = width;
420     if ((endY = image->height) > height)
421 	endY = height;
422 
423     for (y = 0; y < endY; y++) {
424 	for (x = 0; x < endX; x++)
425 	    *ip++ = (XGetPixel(xim, x, y))? 255:0;
426 	for (; x < image->width; x++)
427 	    *ip++ = 255;
428     }
429     XDestroyImage(xim);
430 }
431 
432 Image *
ClipboardGetImage(int num)433 ClipboardGetImage(int num)
434 {
435     Image *image;
436     Colormap cmap;
437     if (num<0 || num>=Global.numregions || !Global.toplevel) return NULL;
438 
439     XtVaGetValues(Global.toplevel, XtNcolormap, &cmap, NULL);
440     image = PixmapToImage(Global.toplevel, Global.regiondata[num].pix, cmap);
441     if (image && Global.regiondata[num].mask)
442        PixmapToImageMask(Global.toplevel, image, Global.regiondata[num].mask);
443     return image;
444 }
445 
446 
447 /*
448 **  Compress an image into a nice number of
449 **   colors for display purposes.
450  */
451 static Image *
quantizeColormap(Image * input,Palette * map,Boolean flag)452 quantizeColormap(Image * input, Palette * map, Boolean flag)
453 {
454     Image *output;
455     unsigned char *op;
456     int x, y;
457     int ncol;
458 
459     /*
460     **	If the output is either B&W or grey do something
461     **	 fast and easy.
462      */
463     if (!map->isGrey)
464 	return ImageCompress(input, map->ncolors, 0);
465 
466     ncol = map->ncolors > 256 ? 256 : map->ncolors;
467     output = ImageNewCmap(input->width, input->height, ncol);
468 
469     op = output->data;
470 
471     for (y = 0; y < ncol; y++) {
472 	unsigned char v = ((double) y / (double) (ncol - 1)) * 255.0;
473 	ImageSetCmap(output, y, v, v, v);
474     }
475 
476     for (y = 0; y < input->height; y++) {
477 	for (x = 0; x < input->width; x++, op++) {
478 	    unsigned char *dp, v;
479 
480 	    dp = ImagePixel(input, x, y);
481 	    v = GreyScale(dp[0], dp[1], dp[2]);
482 	    *op = (int) (((double) v / 256.0) * (double) ncol);
483 	}
484     }
485 
486     output->alpha = input->alpha;
487     input->alpha = NULL;
488     ImageDelete(input);
489     return output;
490 }
491 
492 /* static */ void 			/* non-static for WritePNG() */
compressColormap(Image * image)493 compressColormap(Image * image)
494 {
495     unsigned char used[32768];
496     int size = image->width * image->height;
497     int i, count, newSize;
498     unsigned char *newMap;
499     unsigned short *isp;
500     unsigned char *icp;
501 
502     if (image->cmapSize <= 2 || image->cmapPacked)
503 	return;
504 
505     memset(used, False, sizeof(used));
506 
507     /*
508     **	Find out usage information over the colormap
509      */
510     count = 0;
511     if (image->cmapSize > 256) {
512 	isp = (unsigned short *) image->data;
513 	for (i = 0; i < size && count != image->cmapSize; i++, isp++) {
514 	    if (!used[*isp]) {
515 		used[*isp] = True;
516 		count++;
517 	    }
518 	}
519     } else {
520 	icp = image->data;
521 	for (i = 0; i < size && count != image->cmapSize; i++, icp++) {
522 	    if (!used[*icp]) {
523 		used[*icp] = True;
524 		count++;
525 	    }
526 	}
527     }
528 
529     /*
530     **	Colormap is fully used.
531      */
532     if (count == image->cmapSize) {
533 	image->cmapPacked = True;
534 	return;
535     }
536     /*
537     **	Now build the remapping colormap, and
538     **	  set the index.
539      */
540     newSize = count;
541     newMap = (unsigned char *) XtCalloc(count, sizeof(unsigned char) * 3);
542     for (count = i = 0; i < image->cmapSize; i++) {
543 	if (!used[i])
544 	    continue;
545 	newMap[count * 3 + 0] = image->cmapData[i * 3 + 0];
546 	newMap[count * 3 + 1] = image->cmapData[i * 3 + 1];
547 	newMap[count * 3 + 2] = image->cmapData[i * 3 + 2];
548 	used[i] = count++;
549     }
550 
551     if (image->cmapSize > 256 && newSize > 256) {
552 	isp = (unsigned short *) image->data;
553 	for (i = 0; i < size; i++, isp++)
554 	    *isp = used[*isp];
555     } else if (image->cmapSize > 256 && newSize <= 256) {
556 	/*
557 	**  Map a big colormap down to a small one.
558 	 */
559 	isp = (unsigned short *) image->data;
560 	icp = image->data;
561 	for (i = 0; i < size; i++, icp++, isp++)
562 	    *icp = used[*isp];
563 
564 	image->data = (unsigned char *)
565 	    XtRealloc((XtPointer) image->data, size * sizeof(unsigned char));
566     } else {
567 	icp = image->data;
568 	for (i = 0; i < size; i++, icp++)
569 	    *icp = used[*icp];
570     }
571 
572     XtFree((XtPointer) image->cmapData);
573     image->cmapData = newMap;
574     image->cmapSize = newSize;
575     image->cmapPacked = True;
576     image->isGrey = False;
577 }
578 
579 /*
580 **  Convert an input image into a nice pixmap
581 **   so we can edit it.
582 **
583 **  Side effect	 -- always destroy the input image
584  */
585 Boolean
ImageToPixmap(Image * image,Widget w,Pixmap * pix,Colormap * cmap)586 ImageToPixmap(Image * image, Widget w, Pixmap * pix, Colormap * cmap)
587 {
588     Display *dpy = XtDisplay(w);
589     Palette *map;
590     XImage *xim;
591     int width = image->width, height = image->height;
592 
593     map = PaletteCreate(w);
594     *cmap = map->cmap;
595 
596     if ((*pix = XCreatePixmap(dpy, DefaultRootWindow(dpy),
597 			      width, height, map->depth)) == None)
598 	return False;
599 
600     if ((xim = NewXImage(dpy, NULL, map->depth, width, height)) == NULL) {
601 	XFreePixmap(dpy, *pix);
602 	return False;
603     }
604     if ((image->cmapSize > map->ncolors) ||
605 	(image->cmapSize == 0 && map->isMapped))
606 	image = quantizeColormap(image, map, False);
607 
608     if (image->cmapSize > 0)
609 	compressColormap(image);
610 
611     imageToPixmapLoop(dpy, image, map, xim, pix);
612 
613     return True;
614 }
615 
616 Pixmap
AlphaToPixmap(Widget w,int width,int height,char * data,XRectangle * rect)617 AlphaToPixmap(Widget w, int width, int height,
618 	      char *data, XRectangle * rect)
619 {
620     Display *dpy = XtDisplay(w);
621     GC gc;
622     Pixmap mask;
623     XImage *xim;
624     int x, y;
625     int xs, ys;
626     unsigned char *ucp;
627     unsigned char threshold;
628     int pWidth, pHeight;
629 
630     if (data == NULL)
631 	return None;
632 
633     if (rect == NULL) {
634 	xs = 0;
635 	ys = 0;
636 	pWidth = width;
637 	pHeight = height;
638     } else {
639 	xs = rect->x;
640 	ys = rect->y;
641 	pWidth = rect->width;
642 	pHeight = rect->height;
643     }
644 
645     mask = XCreatePixmap(dpy, DefaultRootWindow(dpy), pWidth, pHeight, 1);
646     gc = XCreateGC(dpy, mask, 0, 0);
647     xim = NewXImage(dpy, NULL, 1, pWidth, pHeight);
648 
649     if (xim->byte_order != xim->bitmap_bit_order) {
650 	for (y = 0; y < pHeight; y++) {
651 	    ucp = (unsigned char *) (data + (width * (y + ys)) + xs);
652 	    for (x = 0; x < pWidth; x++, ucp++)
653 		XPutPixel(xim, x, y, *ucp);
654 	}
655     } else {
656 	unsigned char *op = (unsigned char *) xim->data;
657 	unsigned char *cp;
658 
659 	if (xim->bitmap_bit_order == MSBFirst) {
660 	    for (y = 0; y < pHeight; y++) {
661 		ucp = (unsigned char *) (data + (width * (y + ys)) + xs);
662 		for (x = 0; x < pWidth; x++, ucp++) {
663 		    unsigned char v = 0x80 >> (x & 7);
664 		    cp = &op[ZINDEX1(x, y, xim)];
665 		    if (*ucp)
666 			*cp |= v;
667 		    else
668 			*cp &= ~v;
669 		}
670 	    }
671 	} else {
672 	    threshold = (unsigned char) Global.alpha_threshold;
673 	    for (y = 0; y < pHeight; y++) {
674 		ucp = (unsigned char *) (data + (width * (y + ys)) + xs);
675 		for (x = 0; x < pWidth; x++, ucp++) {
676 		    unsigned char v = 0x01 << (x & 7);
677 		    cp = &op[ZINDEX1(x, y, xim)];
678 		    if (*ucp >= threshold)
679 			*cp |= v;
680 		    else
681 			*cp &= ~v;
682 		}
683 	    }
684 	}
685 
686     }
687 
688     XPutImage(dpy, mask, gc, xim, 0, 0, 0, 0, pWidth, pHeight);
689     XFreeGC(dpy, gc);
690 
691     XDestroyImage(xim);
692 
693     return mask;
694 }
695 
696 Pixmap
ImageMaskToPixmap(Widget w,Image * image)697 ImageMaskToPixmap(Widget w, Image * image)
698 {
699     return AlphaToPixmap(w, image->width,
700 			    image->height, (char *) image->alpha, NULL);
701 }
702 
703 void
get_color_components(Pixel p,unsigned char * c)704 get_color_components(Pixel p, unsigned char *c)
705 {
706     unsigned char u, v;
707 
708     if (Global.depth >= 24) {
709         c[0] = p>>16;
710         c[1] = (p>>8) & 255;
711         c[2] = p & 255;
712     } else
713     if (Global.depth == 16) {
714 	u = p&255;
715         v = p>>8;
716         c[0] = ((v>>3)*255)/31;
717         c[1] = ((((v&7)<<3) | (u>>5))*255)/63;
718         c[2] = ((u&31)*255)/31;
719     } else
720     if (Global.depth == 15) {
721 	u = p&255;
722         v = p>>8;
723         c[0] = ((v>>2)*255)/31;
724         c[1] = ((((v&3)<<3) | (u>>5))*255)/31;
725         c[2] = ((u&31)*255)/31;
726     } else
727         c[0] = p&255;
728 }
729 
730 Pixel
get_pixel_from_colors(unsigned char * c)731 get_pixel_from_colors(unsigned char *c)
732 {
733     Pixel p;
734     if (Global.depth >= 24) {
735         p = ((unsigned int)c[0]<<16) | ((unsigned int)c[1]<<8) |
736              (unsigned int)c[2];
737     } else
738     if (Global.depth == 16) {
739         p = (((c[2]&248)>>3) | ((c[1]&28)<<3)) |
740             ((((c[1]&224)>>5) | (c[0]&248)) << 8);
741     } else
742     if (Global.depth == 15) {
743         p = (((c[2]&248)>>3) | ((c[1]&56)<<2)) |
744             ((((c[1]&192)>>6) | ((c[0]&248)>>1)) << 8);
745     } else
746         p = c[0]||c[1]||c[2];
747     return p;
748 }
749 
750 /*
751 **  Convert an input image into a nice pixmap
752 **   so we can edit it.
753 **
754 **  Side effect	 -- always destroy the input image
755  */
756 static void
imageToPixmapLoop(Display * dpy,Image * image,Palette * map,XImage * xim,Pixmap * pix)757 imageToPixmapLoop(Display * dpy, Image * image,
758 		  Palette * map, XImage * xim, Pixmap * pix)
759 {
760     GC gc;
761     int x, y;
762     int width = image->width, height = image->height;
763 
764     if (image->cmapSize > 0) {
765 	unsigned short *sdp = (unsigned short *) image->data;
766 	unsigned char *cdp = (unsigned char *) image->data;
767 	Pixel *list = (Pixel *) XtCalloc(sizeof(Pixel), image->cmapSize);
768 	XColor *xcol = (XColor *) XtCalloc(sizeof(XColor), image->cmapSize);
769 
770 	for (y = 0; y < image->cmapSize; y++) {
771 	    xcol[y].red = image->cmapData[y * 3 + 0] << 8;
772 	    xcol[y].green = image->cmapData[y * 3 + 1] << 8;
773 	    xcol[y].blue = image->cmapData[y * 3 + 2] << 8;
774 	}
775 
776 	PaletteAllocN(map, xcol, image->cmapSize, list);
777 
778 	if (xim->bits_per_pixel == 8) {
779 	    unsigned char *data = (unsigned char *) xim->data;
780 
781 	    for (y = 0; y < height; y++)
782 		for (x = 0; x < width; x++, sdp++, cdp++)
783 		    data[ZINDEX8(x, y, xim)] = list[image->cmapSize > 256 ? *sdp : *cdp];
784 	} else {
785 	    /*
786 	    **	Slow loop
787 	     */
788 	    for (y = 0; y < height; y++) {
789 		for (x = 0; x < width; x++, sdp++, cdp++)
790 		    XPutPixel(xim, x, y, list[image->cmapSize > 256 ? *sdp : *cdp]);
791 		if (y % 256 == 0)
792 		    StateTimeStep();
793 	    }
794 	}
795 
796 	XtFree((XtPointer) list);
797 	XtFree((XtPointer) xcol);
798     } else {
799 	int step = 64 * 256 / width;
800         if (step == 0) step = 1;
801 	unsigned char *cp = image->data;
802 
803 	for (y = 0; y < height; y++) {
804 	    for (x = 0; x < width; x++) {
805 		XColor c;
806 		Pixel p;
807 
808 		c.red = *cp++ << 8;
809 		c.green = *cp++ << 8;
810 		c.blue = *cp++ << 8;
811 
812 		p = PaletteAlloc(map, &c);
813 
814 		if (xim->bits_per_pixel == 8)
815 		    xim->data[ZINDEX8(x, y, xim)] = p;
816 		else
817 		    XPutPixel(xim, x, y, p);
818 	    }
819 
820 	    if (y % step == 0)
821 		StateTimeStep();
822 	}
823     }
824 
825     gc = XCreateGC(dpy, *pix, 0, 0);
826     XPutImage(dpy, *pix, gc, xim, 0, 0, 0, 0, width, height);
827     XFreeGC(dpy, gc);
828     XDestroyImage(xim);
829     ImageDelete(image);
830 }
831 
832 /*
833  * Convert an Image to a Pixmap, using specified colormap.
834  * Unless pix == None, a new pixmap is created.
835  */
836 Boolean
ImageToPixmapCmap(Image * image,Widget w,Pixmap * pix,Colormap cmap)837 ImageToPixmapCmap(Image * image, Widget w, Pixmap * pix, Colormap cmap)
838 {
839     Display *dpy = XtDisplay(w);
840     Palette *map;
841     XImage *xim;
842     int width = image->width, height = image->height;
843 
844     if ((map = PaletteFind(w, cmap)) == NULL)
845 	map = PaletteGetDefault(w);
846 
847     if (*pix == None) {
848 	if ((*pix = XCreatePixmap(dpy, RootWindowOfScreen(XtScreen(w)),
849 				  width, height, map->depth)) == None)
850 	    return False;
851     }
852     if ((xim = NewXImage(dpy, NULL, map->depth, width, height)) == NULL) {
853 	XFreePixmap(dpy, *pix);
854 	return False;
855     }
856     if ((image->cmapSize > map->ncolors) ||
857 	(image->cmapSize == 0 && map->isMapped))
858 	image = quantizeColormap(image, map, False);
859 
860     if (image->cmapSize > 0)
861 	compressColormap(image);
862 
863     imageToPixmapLoop(dpy, image, map, xim, pix);
864 
865     return True;
866 }
867 
868 
869