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