/* Copyright 1990,91 GROUPE BULL -- See licence conditions in file COPYRIGHT */ /*****************************************************************************\ * scan.c: * * * * XPM library * * Scaning utility for XPM file format * * * * Developed by Arnaud Le Hors * \*****************************************************************************/ #include "xpmP.h" #define MAXPRINTABLE 93 /* number of printable ascii chars * minus \ and " for string compat * and / to avoid comment conflicts. */ static char *printable = " .XoO+@#$%&*=-;:?>,<1234567890qwertyuipasdfghjklzxcvbnmMNBVCZ\ ASDFGHJKLPIUYTREWQ!~^/()_`'][{}|"; /* * printable begin with a space, so in most case, due to my algorythm, when * the number of different colors is less than MAXPRINTABLE, it will give a * char follow by "nothing" (a space) in the readable xpm file */ typedef struct { Pixel *pixels; unsigned int *pixelindex; unsigned int size; unsigned int ncolors; unsigned int mask_pixel; /* whether there is or not */ } PixelsMap; LFUNC(storePixel, int, (Pixel pixel, PixelsMap * pmap, unsigned int *index_return)); LFUNC(storeMaskPixel, int, (Pixel pixel, PixelsMap * pmap, unsigned int *index_return)); LFUNC(GetImagePixels, int, (XImage * image, unsigned int width, unsigned int height, PixelsMap * pmap)); LFUNC(GetImagePixels32, int, (XImage * image, unsigned int width, unsigned int height, PixelsMap * pmap)); LFUNC(GetImagePixels16, int, (XImage * image, unsigned int width, unsigned int height, PixelsMap * pmap)); LFUNC(GetImagePixels8, int, (XImage * image, unsigned int width, unsigned int height, PixelsMap * pmap)); LFUNC(GetImagePixels1, int, (XImage * image, unsigned int width, unsigned int height, PixelsMap * pmap, int (*storeFunc) ())); /* * This function stores the given pixel in the given arrays which are grown * if not large enough. */ static int storePixel(pixel, pmap, index_return) Pixel pixel; PixelsMap *pmap; unsigned int *index_return; { unsigned int a; if (*index_return) { /* this is a transparent pixel! */ *index_return = 0; return 0; } for (a = pmap->mask_pixel; a < pmap->ncolors; a++) if ((pmap->pixels)[a] == pixel) break; if (a == pmap->ncolors) { if (pmap->ncolors > pmap->size) { Pixel *p; pmap->size *= 2; p = (Pixel *) realloc(pmap->pixels, sizeof(Pixel) * pmap->size); if (!p) return (1); pmap->pixels = p; } (pmap->pixels)[pmap->ncolors] = pixel; pmap->ncolors++; } *index_return = a; return 0; } static int storeMaskPixel(pixel, pmap, index_return) Pixel pixel; PixelsMap *pmap; unsigned int *index_return; { if (!pixel) { if (!pmap->ncolors) { pmap->ncolors = 1; (pmap->pixels)[0] = 0; pmap->mask_pixel = 1; } *index_return = 1; } else *index_return = 0; return 0; } /* function call in case of error, frees only localy allocated variables */ #undef RETURN #define RETURN(status) \ { if (pmap.pixelindex) free(pmap.pixelindex); \ if (pmap.pixels) free(pmap.pixels); \ if (xcolors) free(xcolors); \ if (colorStrings) { \ for (a = 0; a < pmap.ncolors; a++) \ if (colorStrings[a]) \ free(colorStrings[a]); \ free(colorStrings); \ } \ return(status); } /* * This function scans the given image and stores the found informations in * the xpmInternAttrib structure which is returned. */ int xpmScanImage(display, image, shapeimage, attributes, attrib) Display *display; XImage *image; XImage *shapeimage; XpmAttributes *attributes; xpmInternAttrib *attrib; { /* variables stored in the XpmAttributes structure */ Colormap colormap; unsigned int cpp; /* variables to return */ PixelsMap pmap; char **colorStrings = NULL; XColor *xcolors = NULL; unsigned int ErrorStatus; /* calculation variables */ unsigned int width = 0; unsigned int height = 0; unsigned int cppm; /* minimun chars per pixel */ unsigned int a, b, c; /* intialize pmap */ pmap.pixels = NULL; pmap.pixelindex = NULL; pmap.size = 256; /* should be enough most of the time */ pmap.ncolors = 0; pmap.mask_pixel = 0; /* * get geometry */ if (image) { width = image->width; height = image->height; } else if (shapeimage) { width = image->width; height = image->height; } /* * retrieve information from the XpmAttributes */ if (attributes && attributes->valuemask & XpmColormap) colormap = attributes->colormap; else colormap = DefaultColormap(display, DefaultScreen(display)); if (attributes && (attributes->valuemask & XpmCharsPerPixel || attributes->valuemask & XpmInfos)) cpp = attributes->cpp; else cpp = 0; pmap.pixelindex = (unsigned int *) calloc(width * height, sizeof(unsigned int)); if (!pmap.pixelindex) RETURN(XpmNoMemory); pmap.pixels = (Pixel *) malloc(sizeof(Pixel) * pmap.size); if (!pmap.pixels) RETURN(XpmNoMemory); /* * scan shape mask if any */ if (shapeimage) { ErrorStatus = GetImagePixels1(shapeimage, width, height, &pmap, storeMaskPixel); if (ErrorStatus != XpmSuccess) RETURN(ErrorStatus); } /* * scan the image data * * In case depth is 1 or bits_per_pixel is 4, 6, 8, 24 or 32 use optimized * functions, otherwise use slower but sure general one. * */ if (image) { if (image->depth == 1) ErrorStatus = GetImagePixels1(image, width, height, &pmap, storePixel); else if (image->bits_per_pixel == 8) ErrorStatus = GetImagePixels8(image, width, height, &pmap); else if (image->bits_per_pixel == 16) ErrorStatus = GetImagePixels16(image, width, height, &pmap); else if (image->bits_per_pixel == 32) ErrorStatus = GetImagePixels32(image, width, height, &pmap); else ErrorStatus = GetImagePixels(image, width, height, &pmap); if (ErrorStatus != XpmSuccess) RETURN(ErrorStatus); } /* * get rgb values and a string of char for each color */ xcolors = (XColor *) malloc(sizeof(XColor) * pmap.ncolors); if (!xcolors) RETURN(XpmNoMemory); colorStrings = (char **) calloc(pmap.ncolors, sizeof(char *)); if (!colorStrings) RETURN(XpmNoMemory); for (cppm = 1, c = MAXPRINTABLE; pmap.ncolors > c; cppm++) c *= MAXPRINTABLE; if (cpp < cppm) cpp = cppm; for (a = 0; a < pmap.ncolors; a++) { if (!(colorStrings[a] = (char *) malloc(cpp))) RETURN(XpmNoMemory); *colorStrings[a] = printable[c = a % MAXPRINTABLE]; for (b = 1; b < cpp; b++) colorStrings[a][b] = printable[c = ((a - c) / MAXPRINTABLE) % MAXPRINTABLE]; xcolors[a].pixel = pmap.pixels[a]; } XQueryColors(display, colormap, xcolors, pmap.ncolors); /* * store found informations in the xpmInternAttrib structure */ attrib->width = width; attrib->height = height; attrib->cpp = cpp; attrib->ncolors = pmap.ncolors; attrib->mask_pixel = pmap.mask_pixel ? 0 : UNDEF_PIXEL; attrib->pixelindex = pmap.pixelindex; attrib->xcolors = xcolors; attrib->colorStrings = colorStrings; free(pmap.pixels); return (XpmSuccess); } /* * The functions below are written from X11R5 MIT's code (XImUtil.c) * * The idea is to have faster functions than the standard XGetPixel function * to scan the image data. Indeed we can speed up things by supressing tests * performed for each pixel. We do exactly the same tests but at the image * level. Assuming that we use only ZPixmap images. */ static unsigned long Const low_bits_table[] = { 0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff }; /* * Default method to scan pixels of a Z image data structure. * The algorithm used is: * * copy the source bitmap_unit or Zpixel into temp * normalize temp if needed * extract the pixel bits into return value * */ static int GetImagePixels(image, width, height, pmap) XImage *image; unsigned int width; unsigned int height; PixelsMap *pmap; { Pixel pixel, px; register char *src; register char *dst; register int i; int bits; register unsigned int *iptr; register int x, y; iptr = pmap->pixelindex; if (image->depth == 1) { for (y = 0; y < height; y++) for (x = 0; x < width; x++, iptr++) { src = &image->data[XYINDEX(x, y, image)]; dst = (char *) &pixel; pixel = 0; for (i = image->bitmap_unit >> 3; --i >= 0;) *dst++ = *src++; XYNORMALIZE(&pixel, image); bits = x % image->bitmap_unit; pixel = ((((char *) &pixel)[bits >> 3]) >> (bits & 7)) & 1; if (image->bits_per_pixel != image->depth) pixel &= low_bits_table[image->depth]; if (storePixel(pixel, pmap, iptr)) return (XpmNoMemory); } } else { for (y = 0; y < height; y++) for (x = 0; x < width; x++, iptr++) { src = &image->data[ZINDEX(x, y, image)]; dst = (char *) &px; px = 0; for (i = (image->bits_per_pixel + 7) >> 3; --i >= 0;) *dst++ = *src++; ZNORMALIZE(&px, image); pixel = 0; for (i = sizeof(unsigned long); --i >= 0;) pixel = (pixel << 8) | ((unsigned char *) &px)[i]; if (image->bits_per_pixel == 4) { if (x & 1) pixel >>= 4; else pixel &= 0xf; } if (image->bits_per_pixel != image->depth) pixel &= low_bits_table[image->depth]; if (storePixel(pixel, pmap, iptr)) return (XpmNoMemory); } } return(XpmSuccess); } /* * scan pixels of a 32-bits Z image data structure */ #ifndef WORD64 static unsigned long byteorderpixel = MSBFirst << 24; #endif static int GetImagePixels32(image, width, height, pmap) XImage *image; unsigned int width; unsigned int height; PixelsMap *pmap; { register unsigned char *addr; Pixel pixel; register unsigned int *iptr; register int x, y; iptr = pmap->pixelindex; #ifndef WORD64 if (*((char *) &byteorderpixel) == image->byte_order) { for (y = 0; y < height; y++) for (x = 0; x < width; x++, iptr++) { pixel = image->data[ZINDEX32(x, y, image)]; if (image->depth != 32) pixel &= low_bits_table[image->depth]; if (storePixel(pixel, pmap, iptr)) return (XpmNoMemory); } } else #endif if (image->byte_order == MSBFirst) for (y = 0; y < height; y++) for (x = 0; x < width; x++, iptr++) { addr = &((unsigned char *) image->data)[ZINDEX32(x, y, image)]; pixel = ((unsigned long) addr[0] << 24 | (unsigned long) addr[1] << 16 | (unsigned long) addr[2] << 8 | addr[3]); if (image->depth != 32) pixel &= low_bits_table[image->depth]; if (storePixel(pixel, pmap, iptr)) return (XpmNoMemory); } else for (y = 0; y < height; y++) for (x = 0; x < width; x++, iptr++) { addr = &((unsigned char *) image->data)[ZINDEX32(x, y, image)]; pixel = ((unsigned long) addr[3] << 24 | (unsigned long) addr[2] << 16 | (unsigned long) addr[1] << 8 | addr[0]); if (image->depth != 32) pixel &= low_bits_table[image->depth]; if (storePixel(pixel, pmap, iptr)) return (XpmNoMemory); } return(XpmSuccess); } /* * scan pixels of a 16-bits Z image data structure */ static int GetImagePixels16(image, width, height, pmap) XImage *image; unsigned int width; unsigned int height; PixelsMap *pmap; { register unsigned char *addr; Pixel pixel; register unsigned int *iptr; register int x, y; iptr = pmap->pixelindex; if (image->byte_order == MSBFirst) for (y = 0; y < height; y++) for (x = 0; x < width; x++, iptr++) { addr = &((unsigned char *) image->data)[ZINDEX16(x, y, image)]; pixel = addr[0] << 8 | addr[1]; if (image->depth != 16) pixel &= low_bits_table[image->depth]; if (storePixel(pixel, pmap, iptr)) return (XpmNoMemory); } else for (y = 0; y < height; y++) for (x = 0; x < width; x++, iptr++) { addr = &((unsigned char *) image->data)[ZINDEX16(x, y, image)]; pixel = addr[1] << 8 | addr[0]; if (image->depth != 16) pixel &= low_bits_table[image->depth]; if (storePixel(pixel, pmap, iptr)) return (XpmNoMemory); } return(XpmSuccess); } /* * scan pixels of a 8-bits Z image data structure */ static int GetImagePixels8(image, width, height, pmap) XImage *image; unsigned int width; unsigned int height; PixelsMap *pmap; { Pixel pixel; register unsigned int *iptr; register int x, y; iptr = pmap->pixelindex; for (y = 0; y < height; y++) for (x = 0; x < width; x++, iptr++) { pixel = ((unsigned char *) image->data)[ZINDEX8(x, y, image)]; if (image->depth != 8) pixel &= low_bits_table[image->depth]; if (storePixel(pixel, pmap, iptr)) return (XpmNoMemory); } return(XpmSuccess); } /* * scan pixels of a 1-bit depth Z image data structure */ static int GetImagePixels1(image, width, height, pmap, storeFunc) XImage *image; unsigned int width; unsigned int height; PixelsMap *pmap; int (*storeFunc) (); { Pixel pixel; unsigned char bit; int xoff, yoff; register unsigned int *iptr; register int x, y; if (image->byte_order != image->bitmap_bit_order) return(GetImagePixels(image, width, height, pmap)); else { iptr = pmap->pixelindex; if (image->bitmap_bit_order == MSBFirst) for (y = 0; y < height; y++) for (x = 0; x < width; x++, iptr++) { yoff = ZINDEX1(x, y, image); xoff = x & 7; bit = 0x80 >> xoff; pixel = (image->data[yoff] & bit) ? 1 : 0; if ((*storeFunc) (pixel, pmap, iptr)) return (XpmNoMemory); } else for (y = 0; y < height; y++) for (x = 0; x < width; x++, iptr++) { yoff = ZINDEX1(x, y, image); xoff = x & 7; bit = 1 << xoff; pixel = (image->data[yoff] & bit) ? 1 : 0; if ((*storeFunc) (pixel, pmap, iptr)) return (XpmNoMemory); } } return(XpmSuccess); }