2 * Copyright (C) 1989-95 GROUPE BULL
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 * Except as contained in this notice, the name of GROUPE BULL shall not be
22 * used in advertising or otherwise to promote the sale, use or other dealings
23 * in this Software without prior written authorization from GROUPE BULL.
26 /*****************************************************************************\
30 * Scanning utility for XPM file format *
32 * Developed by Arnaud Le Hors *
33 \*****************************************************************************/
36 * The code related to FOR_MSW has been added by
37 * HeDu (hedu@cul-ipn.uni-kiel.de) 4/94
41 * The code related to AMIGA has been added by
42 * Lorens Younes (d93-hyo@nada.kth.se) 4/96
45 /* October 2004, source code review by Thomas Biege <thomas@suse.de> */
52 #define MAXPRINTABLE 92 /* number of printable ascii chars
53 * minus \ and " for string compat
54 * and ? to avoid ANSI trigraphs. */
56 static const char *printable =
57 " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjklzxcvbnmMNBVCZ\
58 ASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
61 * printable begin with a space, so in most case, due to my algorithm, when
62 * the number of different colors is less than MAXPRINTABLE, it will give a
63 * char follow by "nothing" (a space) in the readable xpm file
69 unsigned int *pixelindex;
72 unsigned int mask_pixel; /* whether there is or not */
75 LFUNC(storePixel, int, (Pixel pixel, PixelsMap *pmap,
76 unsigned int *index_return));
78 LFUNC(storeMaskPixel, int, (Pixel pixel, PixelsMap *pmap,
79 unsigned int *index_return));
81 typedef int (*storeFuncPtr)(Pixel pixel, PixelsMap *pmap,
82 unsigned int *index_return);
86 LFUNC(GetImagePixels, int, (XImage *image, unsigned int width,
87 unsigned int height, PixelsMap *pmap));
89 LFUNC(GetImagePixels32, int, (XImage *image, unsigned int width,
90 unsigned int height, PixelsMap *pmap));
92 LFUNC(GetImagePixels16, int, (XImage *image, unsigned int width,
93 unsigned int height, PixelsMap *pmap));
95 LFUNC(GetImagePixels8, int, (XImage *image, unsigned int width,
96 unsigned int height, PixelsMap *pmap));
98 LFUNC(GetImagePixels1, int, (XImage *image, unsigned int width,
99 unsigned int height, PixelsMap *pmap,
100 storeFuncPtr storeFunc));
102 LFUNC(AGetImagePixels, int, (XImage *image, unsigned int width,
103 unsigned int height, PixelsMap *pmap,
104 storeFuncPtr storeFunc));
106 #else /* ndef FOR_MSW */
107 LFUNC(MSWGetImagePixels, int, (Display *d, XImage *image, unsigned int width,
108 unsigned int height, PixelsMap *pmap,
109 storeFuncPtr storeFunc));
111 LFUNC(ScanTransparentColor, int, (XpmColor *color, unsigned int cpp,
112 XpmAttributes *attributes));
114 LFUNC(ScanOtherColors, int, (Display *display, XpmColor *colors,
115 unsigned int ncolors,
116 Pixel *pixels, unsigned int mask,
117 unsigned int cpp, XpmAttributes *attributes));
120 * This function stores the given pixel in the given arrays which are grown
121 * if not large enough.
127 unsigned int *index_return)
131 unsigned int ncolors;
133 if (*index_return) { /* this is a transparent pixel! */
137 ncolors = pmap->ncolors;
138 p = pmap->pixels + pmap->mask_pixel;
139 for (i = pmap->mask_pixel; i < ncolors; i++, p++)
143 if (ncolors >= pmap->size) {
145 p = (Pixel *) XpmRealloc(pmap->pixels, sizeof(Pixel) * pmap->size);
151 (pmap->pixels)[ncolors] = pixel;
162 unsigned int *index_return)
165 if (!pmap->ncolors) {
167 (pmap->pixels)[0] = 0;
168 pmap->mask_pixel = 1;
176 /* function call in case of error */
178 #define RETURN(status) \
180 ErrorStatus = status; \
185 * This function scans the given image and stores the found informations in
186 * the given XpmImage structure.
189 XpmCreateXpmImageFromImage(
194 XpmAttributes *attributes)
196 /* variables stored in the XpmAttributes structure */
199 /* variables to return */
201 XpmColor *colorTable = NULL;
204 /* calculation variables */
205 unsigned int width = 0;
206 unsigned int height = 0;
207 unsigned int cppm; /* minimum chars per pixel */
210 /* initialize pmap */
212 pmap.pixelindex = NULL;
213 pmap.size = 256; /* should be enough most of the time */
221 width = image->width;
222 height = image->height;
223 } else if (shapeimage) {
224 width = shapeimage->width;
225 height = shapeimage->height;
229 * retrieve information from the XpmAttributes
231 if (attributes && (attributes->valuemask & XpmCharsPerPixel
232 /* 3.2 backward compatibility code */
233 || attributes->valuemask & XpmInfos))
235 cpp = attributes->cpp;
239 if ((height > 0 && width >= UINT_MAX / height) ||
240 width * height >= UINT_MAX / sizeof(unsigned int))
243 (unsigned int *) XpmCalloc(width * height, sizeof(unsigned int));
244 if (!pmap.pixelindex)
247 if (pmap.size >= UINT_MAX / sizeof(Pixel))
250 pmap.pixels = (Pixel *) XpmMalloc(sizeof(Pixel) * pmap.size);
255 * scan shape mask if any
260 ErrorStatus = GetImagePixels1(shapeimage, width, height, &pmap,
263 ErrorStatus = AGetImagePixels(shapeimage, width, height, &pmap,
267 ErrorStatus = MSWGetImagePixels(display, shapeimage, width, height,
268 &pmap, storeMaskPixel);
270 if (ErrorStatus != XpmSuccess)
275 * scan the image data
277 * In case depth is 1 or bits_per_pixel is 4, 6, 8, 24 or 32 use optimized
278 * functions, otherwise use slower but sure general one.
285 if (((image->bits_per_pixel | image->depth) == 1) &&
286 (image->byte_order == image->bitmap_bit_order))
287 ErrorStatus = GetImagePixels1(image, width, height, &pmap,
289 else if (image->format == ZPixmap) {
290 if (image->bits_per_pixel == 8)
291 ErrorStatus = GetImagePixels8(image, width, height, &pmap);
292 else if (image->bits_per_pixel == 16)
293 ErrorStatus = GetImagePixels16(image, width, height, &pmap);
294 else if (image->bits_per_pixel == 32)
295 ErrorStatus = GetImagePixels32(image, width, height, &pmap);
297 ErrorStatus = GetImagePixels(image, width, height, &pmap);
299 ErrorStatus = AGetImagePixels(image, width, height, &pmap,
303 ErrorStatus = MSWGetImagePixels(display, image, width, height, &pmap,
306 if (ErrorStatus != XpmSuccess)
311 * get rgb values and a string of char, and possibly a name for each
314 if (pmap.ncolors >= UINT_MAX / sizeof(XpmColor))
316 colorTable = (XpmColor *) XpmCalloc(pmap.ncolors, sizeof(XpmColor));
320 /* compute the minimal cpp */
321 for (cppm = 1, c = MAXPRINTABLE; pmap.ncolors > c; cppm++)
326 if (pmap.mask_pixel) {
327 ErrorStatus = ScanTransparentColor(colorTable, cpp, attributes);
328 if (ErrorStatus != XpmSuccess)
332 ErrorStatus = ScanOtherColors(display, colorTable, pmap.ncolors,
333 pmap.pixels, pmap.mask_pixel, cpp,
335 if (ErrorStatus != XpmSuccess)
339 * store found informations in the XpmImage structure
341 xpmimage->width = width;
342 xpmimage->height = height;
344 xpmimage->ncolors = pmap.ncolors;
345 xpmimage->colorTable = colorTable;
346 xpmimage->data = pmap.pixelindex;
348 XpmFree(pmap.pixels);
351 /* exit point in case of error, free only locally allocated variables */
354 XpmFree(pmap.pixelindex);
356 XpmFree(pmap.pixels);
358 xpmFreeColorTable(colorTable, pmap.ncolors);
360 return (ErrorStatus);
364 ScanTransparentColor(
367 XpmAttributes *attributes)
370 unsigned int a, b, c;
372 /* first get a character string */
374 if (cpp >= UINT_MAX - 1)
375 return (XpmNoMemory);
376 if (!(s = color->string = (char *) XpmMalloc(cpp + 1)))
377 return (XpmNoMemory);
378 *s++ = printable[c = a % MAXPRINTABLE];
379 for (b = 1; b < cpp; b++, s++)
380 *s = printable[c = ((a - c) / MAXPRINTABLE) % MAXPRINTABLE];
383 /* then retreive related info from the attributes if any */
384 if (attributes && (attributes->valuemask & XpmColorTable
385 /* 3.2 backward compatibility code */
386 || attributes->valuemask & XpmInfos)
388 && attributes->mask_pixel != XpmUndefPixel) {
391 char **defaults = (char **) color;
392 char **mask_defaults;
394 /* 3.2 backward compatibility code */
395 if (attributes->valuemask & XpmColorTable)
397 mask_defaults = (char **) (
398 attributes->colorTable + attributes->mask_pixel);
399 /* 3.2 backward compatibility code */
401 mask_defaults = (char **)
402 ((XpmColor **) attributes->colorTable)[attributes->mask_pixel];
404 for (key = 1; key <= NKEYS; key++) {
405 if ((s = mask_defaults[key])) {
406 defaults[key] = (char *) xpmstrdup(s);
408 return (XpmNoMemory);
412 color->c_color = (char *) xpmstrdup(TRANSPARENT_COLOR);
414 return (XpmNoMemory);
423 unsigned int ncolors,
427 XpmAttributes *attributes)
429 /* variables stored in the XpmAttributes structure */
434 xpmRgbName rgbn[MAX_RGBNAMES];
436 xpmRgbName *rgbn = NULL;
439 unsigned int i, j, c, i2;
441 XColor *xcolors = NULL, *xcolor;
443 XpmColor *colorTable = NULL, **oldColorTable = NULL;
444 unsigned int ancolors = 0;
445 Pixel *apixels = NULL;
446 unsigned int mask_pixel = 0;
449 /* retrieve information from the XpmAttributes */
450 if (attributes && (attributes->valuemask & XpmColormap))
451 colormap = attributes->colormap;
453 colormap = XDefaultColormap(display, XDefaultScreen(display));
454 if (attributes && (attributes->valuemask & XpmRgbFilename))
455 rgb_fname = attributes->rgb_fname;
459 /* start from the right element */
466 /* first get character strings and rgb values */
467 if (ncolors >= UINT_MAX / sizeof(XColor) || cpp >= UINT_MAX - 1)
468 return (XpmNoMemory);
469 xcolors = (XColor *) XpmMalloc(sizeof(XColor) * ncolors);
471 return (XpmNoMemory);
473 for (i = 0, i2 = mask, color = colors, xcolor = xcolors;
474 i < ncolors; i++, i2++, color++, xcolor++, pixels++) {
476 if (!(s = color->string = (char *) XpmMalloc(cpp + 1))) {
478 return (XpmNoMemory);
480 *s++ = printable[c = i2 % MAXPRINTABLE];
481 for (j = 1; j < cpp; j++, s++)
482 *s = printable[c = ((i2 - c) / MAXPRINTABLE) % MAXPRINTABLE];
485 xcolor->pixel = *pixels;
487 XQueryColors(display, colormap, xcolors, ncolors);
490 /* read the rgb file if any was specified */
492 rgbn_max = xpmReadRgbNames(attributes->rgb_fname, rgbn);
494 /* FOR_MSW: rgb names and values are hardcoded in rgbtab.h */
495 rgbn_max = xpmReadRgbNames(NULL, NULL);
498 if (attributes && attributes->valuemask & XpmColorTable) {
499 colorTable = attributes->colorTable;
500 ancolors = attributes->ncolors;
501 apixels = attributes->pixels;
502 mask_pixel = attributes->mask_pixel;
504 /* 3.2 backward compatibility code */
505 else if (attributes && attributes->valuemask & XpmInfos) {
506 oldColorTable = (XpmColor **) attributes->colorTable;
507 ancolors = attributes->ncolors;
508 apixels = attributes->pixels;
509 mask_pixel = attributes->mask_pixel;
513 for (i = 0, color = colors, xcolor = xcolors; i < ncolors;
514 i++, color++, xcolor++) {
516 /* look for related info from the attributes if any */
519 unsigned int offset = 0;
521 for (j = 0; j < ancolors; j++) {
522 if (j == mask_pixel) {
526 if (apixels[j - offset] == xcolor->pixel)
531 char **defaults = (char **) color;
534 /* 3.2 backward compatibility code */
536 adefaults = (char **) oldColorTable[j];
539 adefaults = (char **) (colorTable + j);
542 for (key = 1; key <= NKEYS; key++) {
543 if ((s = adefaults[key]))
544 defaults[key] = (char *) xpmstrdup(s);
549 /* if nothing found look for a color name */
552 colorname = xpmGetRgbName(rgbn, rgbn_max, xcolor->red,
553 xcolor->green, xcolor->blue);
555 color->c_color = (char *) xpmstrdup(colorname);
557 /* at last store the rgb value */
560 sprintf(buf, "#%04X%04X%04X",
561 xcolor->red, xcolor->green, xcolor->blue);
563 sprintf(buf, "#%02x%02x%02x",
564 xcolor->red, xcolor->green, xcolor->blue);
566 color->c_color = (char *) xpmstrdup(buf);
568 if (!color->c_color) {
570 xpmFreeRgbNames(rgbn, rgbn_max);
571 return (XpmNoMemory);
577 xpmFreeRgbNames(rgbn, rgbn_max);
584 * The functions below are written from X11R5 MIT's code (XImUtil.c)
586 * The idea is to have faster functions than the standard XGetPixel function
587 * to scan the image data. Indeed we can speed up things by suppressing tests
588 * performed for each pixel. We do exactly the same tests but at the image
592 static unsigned long const low_bits_table[] = {
593 0x00000000, 0x00000001, 0x00000003, 0x00000007,
594 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
595 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
596 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
597 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
598 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
599 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
600 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
605 * Default method to scan pixels of an image data structure.
606 * The algorithm used is:
608 * copy the source bitmap_unit or Zpixel into temp
609 * normalize temp if needed
610 * extract the pixel bits into return value
626 int bits, depth, ibu, ibpp, offset, i;
631 iptr = pmap->pixelindex;
632 depth = image->depth;
633 lbt = low_bits_table[depth];
634 ibpp = image->bits_per_pixel;
635 offset = image->xoffset;
637 if (image->bitmap_unit < 0)
638 return (XpmNoMemory);
640 if ((image->bits_per_pixel | image->depth) == 1) {
641 ibu = image->bitmap_unit;
642 for (y = 0; y < height; y++)
643 for (x = 0; x < width; x++, iptr++) {
644 src = &data[XYINDEX(x, y, image)];
645 dst = (char *) &pixel;
647 for (i = ibu >> 3; --i >= 0;)
649 XYNORMALIZE(&pixel, image);
650 bits = (x + offset) % ibu;
651 pixel = ((((char *) &pixel)[bits >> 3]) >> (bits & 7)) & 1;
654 if (storePixel(pixel, pmap, iptr))
655 return (XpmNoMemory);
657 } else if (image->format == XYPixmap) {
660 ibu = image->bitmap_unit;
662 bpl = image->bytes_per_line;
663 for (y = 0; y < height; y++)
664 for (x = 0; x < width; x++, iptr++) {
667 for (i = depth; --i >= 0;) {
668 src = &data[XYINDEX(x, y, image) + plane];
671 for (j = nbytes; --j >= 0;)
673 XYNORMALIZE(&px, image);
674 bits = (x + offset) % ibu;
675 pixel = (pixel << 1) |
676 (((((char *) &px)[bits >> 3]) >> (bits & 7)) & 1);
677 plane = plane + (bpl * height);
681 if (storePixel(pixel, pmap, iptr))
682 return (XpmNoMemory);
684 } else if (image->format == ZPixmap) {
685 for (y = 0; y < height; y++)
686 for (x = 0; x < width; x++, iptr++) {
687 src = &data[ZINDEX(x, y, image)];
690 for (i = (ibpp + 7) >> 3; --i >= 0;)
692 ZNORMALIZE(&px, image);
694 for (i = sizeof(unsigned long); --i >= 0;)
695 pixel = (pixel << 8) | ((unsigned char *) &px)[i];
704 if (storePixel(pixel, pmap, iptr))
705 return (XpmNoMemory);
708 return (XpmColorError); /* actually a bad image */
713 * scan pixels of a 32-bits Z image data structure
716 #if !defined(WORD64) && !defined(LONG64)
717 static unsigned long byteorderpixel = MSBFirst << 24;
735 data = (unsigned char *) image->data;
736 iptr = pmap->pixelindex;
737 depth = image->depth;
738 lbt = low_bits_table[depth];
739 #if !defined(WORD64) && !defined(LONG64)
740 if (*((char *) &byteorderpixel) == image->byte_order) {
741 for (y = 0; y < height; y++)
742 for (x = 0; x < width; x++, iptr++) {
743 addr = &data[ZINDEX32(x, y, image)];
744 pixel = *((unsigned long *) addr);
747 if (storePixel(pixel, pmap, iptr))
748 return (XpmNoMemory);
752 if (image->byte_order == MSBFirst)
753 for (y = 0; y < height; y++)
754 for (x = 0; x < width; x++, iptr++) {
755 addr = &data[ZINDEX32(x, y, image)];
756 pixel = ((unsigned long) addr[0] << 24 |
757 (unsigned long) addr[1] << 16 |
758 (unsigned long) addr[2] << 8 |
762 if (storePixel(pixel, pmap, iptr))
763 return (XpmNoMemory);
766 for (y = 0; y < height; y++)
767 for (x = 0; x < width; x++, iptr++) {
768 addr = &data[ZINDEX32(x, y, image)];
770 (unsigned long) addr[1] << 8 |
771 (unsigned long) addr[2] << 16 |
772 (unsigned long) addr[3] << 24);
775 if (storePixel(pixel, pmap, iptr))
776 return (XpmNoMemory);
782 * scan pixels of a 16-bits Z image data structure
800 data = (unsigned char *) image->data;
801 iptr = pmap->pixelindex;
802 depth = image->depth;
803 lbt = low_bits_table[depth];
804 if (image->byte_order == MSBFirst)
805 for (y = 0; y < height; y++)
806 for (x = 0; x < width; x++, iptr++) {
807 addr = &data[ZINDEX16(x, y, image)];
808 pixel = addr[0] << 8 | addr[1];
811 if (storePixel(pixel, pmap, iptr))
812 return (XpmNoMemory);
815 for (y = 0; y < height; y++)
816 for (x = 0; x < width; x++, iptr++) {
817 addr = &data[ZINDEX16(x, y, image)];
818 pixel = addr[0] | addr[1] << 8;
821 if (storePixel(pixel, pmap, iptr))
822 return (XpmNoMemory);
828 * scan pixels of a 8-bits Z image data structure
845 data = (unsigned char *) image->data;
846 iptr = pmap->pixelindex;
847 depth = image->depth;
848 lbt = low_bits_table[depth];
849 for (y = 0; y < height; y++)
850 for (x = 0; x < width; x++, iptr++) {
851 pixel = data[ZINDEX8(x, y, image)];
854 if (storePixel(pixel, pmap, iptr))
855 return (XpmNoMemory);
861 * scan pixels of a 1-bit depth Z image data structure
870 storeFuncPtr storeFunc)
876 int xoff, yoff, offset, bpl;
879 iptr = pmap->pixelindex;
880 offset = image->xoffset;
881 bpl = image->bytes_per_line;
883 if (image->bitmap_bit_order == MSBFirst)
884 for (y = 0; y < height; y++)
885 for (x = 0; x < width; x++, iptr++) {
887 yoff = y * bpl + (xoff >> 3);
889 pixel = (data[yoff] & (0x80 >> xoff)) ? 1 : 0;
890 if ((*storeFunc) (pixel, pmap, iptr))
891 return (XpmNoMemory);
894 for (y = 0; y < height; y++)
895 for (x = 0; x < width; x++, iptr++) {
897 yoff = y * bpl + (xoff >> 3);
899 pixel = (data[yoff] & (1 << xoff)) ? 1 : 0;
900 if ((*storeFunc) (pixel, pmap, iptr))
901 return (XpmNoMemory);
908 #define CLEAN_UP(status) \
910 if (pixels) XpmFree (pixels);\
911 if (tmp_img) FreeXImage (tmp_img);\
921 int (*storeFunc) (Pixel, PixelsMap *, unsigned int *))
925 unsigned char *pixels;
928 pixels = XpmMalloc ((((width+15)>>4)<<4)*sizeof (*pixels));
932 tmp_img = AllocXImage ((((width+15)>>4)<<4), 1, image->rp->BitMap->Depth);
934 CLEAN_UP (XpmNoMemory);
936 iptr = pmap->pixelindex;
937 for (y = 0; y < height; ++y)
939 ReadPixelLine8 (image->rp, 0, y, width, pixels, tmp_img->rp);
940 for (x = 0; x < width; ++x, ++iptr)
942 if ((*storeFunc) (pixels[x], pmap, iptr))
943 CLEAN_UP (XpmNoMemory);
947 CLEAN_UP (XpmSuccess);
953 #else /* ndef FOR_MSW */
961 int (*storeFunc) (Pixel, PixelsMap*, unsigned int *))
967 iptr = pmap->pixelindex;
969 SelectObject(*display, image->bitmap);
970 for (y = 0; y < height; y++) {
971 for (x = 0; x < width; x++, iptr++) {
972 pixel = GetPixel(*display, x, y);
973 if ((*storeFunc) (pixel, pmap, iptr))
974 return (XpmNoMemory);
985 XpmCreateXpmImageFromPixmap(
990 XpmAttributes *attributes)
992 XImage *ximage = NULL;
993 XImage *shapeimage = NULL;
994 unsigned int width = 0;
995 unsigned int height = 0;
999 if (attributes && attributes->valuemask & XpmSize) {
1000 width = attributes->width;
1001 height = attributes->height;
1003 /* get the ximages */
1005 xpmCreateImageFromPixmap(display, pixmap, &ximage, &width, &height);
1007 xpmCreateImageFromPixmap(display, shapemask, &shapeimage,
1010 /* create the related XpmImage */
1011 ErrorStatus = XpmCreateXpmImageFromImage(display, ximage, shapeimage,
1012 xpmimage, attributes);
1014 /* destroy the ximages */
1016 XDestroyImage(ximage);
1018 XDestroyImage(shapeimage);
1020 return (ErrorStatus);
1023 # endif/* not AMIGA */
1024 #endif /* ndef FOR_MSW */