/* $XdotOrg: lib/Xpm/src/create.c,v 1.6 2005/05/19 15:02:48 sandmann Exp $ */ /* * Copyright (C) 1989-95 GROUPE BULL * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name of GROUPE BULL shall not be * used in advertising or otherwise to promote the sale, use or other dealings * in this Software without prior written authorization from GROUPE BULL. */ /*****************************************************************************\ * create.c: * * * * XPM library * * Create an X image and possibly its related shape mask * * from the given XpmImage. * * * * Developed by Arnaud Le Hors * \*****************************************************************************/ /* $XFree86: xc/extras/Xpm/lib/create.c,v 1.4 2003/05/27 22:26:20 tsi Exp $ */ /* * The code related to FOR_MSW has been added by * HeDu (hedu@cul-ipn.uni-kiel.de) 4/94 */ /* * The code related to AMIGA has been added by * Lorens Younes (d93-hyo@nada.kth.se) 4/96 */ /* October 2004, source code review by Thomas Biege */ #ifdef HAVE_CONFIG_H #include #endif #include "XpmI.h" #include LFUNC(xpmVisualType, int, (Visual *visual)); LFUNC(AllocColor, int, (Display *display, Colormap colormap, char *colorname, XColor *xcolor, void *closure)); LFUNC(FreeColors, int, (Display *display, Colormap colormap, Pixel *pixels, int n, void *closure)); #ifndef FOR_MSW LFUNC(SetCloseColor, int, (Display *display, Colormap colormap, Visual *visual, XColor *col, Pixel *image_pixel, Pixel *mask_pixel, Pixel *alloc_pixels, unsigned int *nalloc_pixels, XpmAttributes *attributes, XColor *cols, int ncols, XpmAllocColorFunc allocColor, void *closure)); #else /* let the window system take care of close colors */ #endif LFUNC(SetColor, int, (Display *display, Colormap colormap, Visual *visual, char *colorname, unsigned int color_index, Pixel *image_pixel, Pixel *mask_pixel, unsigned int *mask_pixel_index, Pixel *alloc_pixels, unsigned int *nalloc_pixels, Pixel *used_pixels, unsigned int *nused_pixels, XpmAttributes *attributes, XColor *cols, int ncols, XpmAllocColorFunc allocColor, void *closure)); LFUNC(CreateXImage, int, (Display *display, Visual *visual, unsigned int depth, int format, unsigned int width, unsigned int height, XImage **image_return)); LFUNC(CreateColors, int, (Display *display, XpmAttributes *attributes, XpmColor *colors, unsigned int ncolors, Pixel *image_pixels, Pixel *mask_pixels, unsigned int *mask_pixel_index, Pixel *alloc_pixels, unsigned int *nalloc_pixels, Pixel *used_pixels, unsigned int *nused_pixels)); #ifndef FOR_MSW LFUNC(ParseAndPutPixels, int, (xpmData *data, unsigned int width, unsigned int height, unsigned int ncolors, unsigned int cpp, XpmColor *colorTable, xpmHashTable *hashtable, XImage *image, Pixel *image_pixels, XImage *mask, Pixel *mask_pixels)); #else /* FOR_MSW */ LFUNC(ParseAndPutPixels, int, (Display *dc, xpmData *data, unsigned int width, unsigned int height, unsigned int ncolors, unsigned int cpp, XpmColor *colorTable, xpmHashTable *hashtable, XImage *image, Pixel *image_pixels, XImage *mask, Pixel *mask_pixels)); #endif #ifndef FOR_MSW # ifndef AMIGA /* XImage pixel routines */ LFUNC(PutImagePixels, void, (XImage *image, unsigned int width, unsigned int height, unsigned int *pixelindex, Pixel *pixels)); LFUNC(PutImagePixels32, void, (XImage *image, unsigned int width, unsigned int height, unsigned int *pixelindex, Pixel *pixels)); LFUNC(PutImagePixels16, void, (XImage *image, unsigned int width, unsigned int height, unsigned int *pixelindex, Pixel *pixels)); LFUNC(PutImagePixels8, void, (XImage *image, unsigned int width, unsigned int height, unsigned int *pixelindex, Pixel *pixels)); LFUNC(PutImagePixels1, void, (XImage *image, unsigned int width, unsigned int height, unsigned int *pixelindex, Pixel *pixels)); LFUNC(PutPixel1, int, (XImage *ximage, int x, int y, unsigned long pixel)); LFUNC(PutPixel, int, (XImage *ximage, int x, int y, unsigned long pixel)); #if !defined(WORD64) && !defined(LONG64) LFUNC(PutPixel32, int, (XImage *ximage, int x, int y, unsigned long pixel)); #endif LFUNC(PutPixel32MSB, int, (XImage *ximage, int x, int y, unsigned long pixel)); LFUNC(PutPixel32LSB, int, (XImage *ximage, int x, int y, unsigned long pixel)); LFUNC(PutPixel16MSB, int, (XImage *ximage, int x, int y, unsigned long pixel)); LFUNC(PutPixel16LSB, int, (XImage *ximage, int x, int y, unsigned long pixel)); LFUNC(PutPixel8, int, (XImage *ximage, int x, int y, unsigned long pixel)); LFUNC(PutPixel1MSB, int, (XImage *ximage, int x, int y, unsigned long pixel)); LFUNC(PutPixel1LSB, int, (XImage *ximage, int x, int y, unsigned long pixel)); # else /* AMIGA */ LFUNC(APutImagePixels, void, (XImage *ximage, unsigned int width, unsigned int height, unsigned int *pixelindex, Pixel *pixels)); # endif/* AMIGA */ #else /* FOR_MSW */ /* FOR_MSW pixel routine */ LFUNC(MSWPutImagePixels, void, (Display *dc, XImage *image, unsigned int width, unsigned int height, unsigned int *pixelindex, Pixel *pixels)); #endif /* FOR_MSW */ #ifdef NEED_STRCASECMP FUNC(xpmstrcasecmp, int, (char *s1, char *s2)); /* * in case strcasecmp is not provided by the system here is one * which does the trick */ int xpmstrcasecmp(s1, s2) register char *s1, *s2; { register int c1, c2; while (*s1 && *s2) { c1 = tolower(*s1); c2 = tolower(*s2); if (c1 != c2) return (c1 - c2); s1++; s2++; } return (int) (*s1 - *s2); } #endif /* * return the default color key related to the given visual */ static int xpmVisualType(visual) Visual *visual; { #ifndef FOR_MSW # ifndef AMIGA switch (visual->class) { case StaticGray: case GrayScale: switch (visual->map_entries) { case 2: return (XPM_MONO); case 4: return (XPM_GRAY4); default: return (XPM_GRAY); } default: return (XPM_COLOR); } # else /* set the key explicitly in the XpmAttributes to override this */ return (XPM_COLOR); # endif #else /* there should be a similar switch for MSW */ return (XPM_COLOR); #endif } typedef struct { int cols_index; long closeness; } CloseColor; static int closeness_cmp(Const void *a, Const void *b) { CloseColor *x = (CloseColor *) a, *y = (CloseColor *) b; /* cast to int as qsort requires */ return (int) (x->closeness - y->closeness); } /* default AllocColor function: * call XParseColor if colorname is given, return negative value if failure * call XAllocColor and return 0 if failure, positive otherwise */ static int AllocColor(display, colormap, colorname, xcolor, closure) Display *display; Colormap colormap; char *colorname; XColor *xcolor; void *closure; /* not used */ { int status; if (colorname) if (!XParseColor(display, colormap, colorname, xcolor)) return -1; status = XAllocColor(display, colormap, xcolor); return status != 0 ? 1 : 0; } #ifndef FOR_MSW /* * set a close color in case the exact one can't be set * return 0 if success, 1 otherwise. */ static int SetCloseColor(display, colormap, visual, col, image_pixel, mask_pixel, alloc_pixels, nalloc_pixels, attributes, cols, ncols, allocColor, closure) Display *display; Colormap colormap; Visual *visual; XColor *col; Pixel *image_pixel, *mask_pixel; Pixel *alloc_pixels; unsigned int *nalloc_pixels; XpmAttributes *attributes; XColor *cols; int ncols; XpmAllocColorFunc allocColor; void *closure; { /* * Allocation failed, so try close colors. To get here the visual must * be GreyScale, PseudoColor or DirectColor (or perhaps StaticColor? * What about sharing systems like QDSS?). Beware: we have to treat * DirectColor differently. */ long int red_closeness, green_closeness, blue_closeness; int n; Bool alloc_color; if (attributes && (attributes->valuemask & XpmCloseness)) red_closeness = green_closeness = blue_closeness = attributes->closeness; else { red_closeness = attributes->red_closeness; green_closeness = attributes->green_closeness; blue_closeness = attributes->blue_closeness; } if (attributes && (attributes->valuemask & XpmAllocCloseColors)) alloc_color = attributes->alloc_close_colors; else alloc_color = True; /* * We sort the colormap by closeness and try to allocate the color * closest to the target. If the allocation of this close color fails, * which almost never happens, then one of two scenarios is possible. * Either the colormap must have changed (since the last close color * allocation or possibly while we were sorting the colormap), or the * color is allocated as Read/Write by some other client. (Note: X * _should_ allow clients to check if a particular color is Read/Write, * but it doesn't! :-( ). We cannot determine which of these scenarios * occurred, so we try the next closest color, and so on, until no more * colors are within closeness of the target. If we knew that the * colormap had changed, we could skip this sequence. * * If _none_ of the colors within closeness of the target can be allocated, * then we can finally be pretty sure that the colormap has actually * changed. In this case we try to allocate the original color (again), * then try the closecolor stuff (again)... * * In theory it would be possible for an infinite loop to occur if another * process kept changing the colormap every time we sorted it, so we set * a maximum on the number of iterations. After this many tries, we use * XGrabServer() to ensure that the colormap remains unchanged. * * This approach gives particularly bad worst case performance - as many as * colormap reads and sorts may be needed, and as * many as * attempted allocations * may fail. On an 8-bit system, this means as many as 3 colormap reads, * 3 sorts and 768 failed allocations per execution of this code! * Luckily, my experiments show that in general use in a typical 8-bit * color environment only about 1 in every 10000 allocations fails to * succeed in the fastest possible time. So virtually every time what * actually happens is a single sort followed by a successful allocate. * The very first allocation also costs a colormap read, but no further * reads are usually necessary. */ #define ITERATIONS 2 /* more than one is almost never * necessary */ for (n = 0; n <= ITERATIONS; ++n) { CloseColor *closenesses = (CloseColor *) XpmCalloc(ncols, sizeof(CloseColor)); int i, c; for (i = 0; i < ncols; ++i) { /* build & sort closenesses table */ #define COLOR_FACTOR 3 #define BRIGHTNESS_FACTOR 1 closenesses[i].cols_index = i; closenesses[i].closeness = COLOR_FACTOR * (abs((long) col->red - (long) cols[i].red) + abs((long) col->green - (long) cols[i].green) + abs((long) col->blue - (long) cols[i].blue)) + BRIGHTNESS_FACTOR * abs(((long) col->red + (long) col->green + (long) col->blue) - ((long) cols[i].red + (long) cols[i].green + (long) cols[i].blue)); } qsort(closenesses, ncols, sizeof(CloseColor), closeness_cmp); i = 0; c = closenesses[i].cols_index; while ((long) cols[c].red >= (long) col->red - red_closeness && (long) cols[c].red <= (long) col->red + red_closeness && (long) cols[c].green >= (long) col->green - green_closeness && (long) cols[c].green <= (long) col->green + green_closeness && (long) cols[c].blue >= (long) col->blue - blue_closeness && (long) cols[c].blue <= (long) col->blue + blue_closeness) { if (alloc_color) { if ((*allocColor)(display, colormap, NULL, &cols[c], closure)){ if (n == ITERATIONS) XUngrabServer(display); XpmFree(closenesses); *image_pixel = cols[c].pixel; *mask_pixel = 1; alloc_pixels[(*nalloc_pixels)++] = cols[c].pixel; return (0); } else { ++i; if (i == ncols) break; c = closenesses[i].cols_index; } } else { if (n == ITERATIONS) XUngrabServer(display); XpmFree(closenesses); *image_pixel = cols[c].pixel; *mask_pixel = 1; return (0); } } /* Couldn't allocate _any_ of the close colors! */ if (n == ITERATIONS) XUngrabServer(display); XpmFree(closenesses); if (i == 0 || i == ncols) /* no color close enough or cannot */ return (1); /* alloc any color (full of r/w's) */ if ((*allocColor)(display, colormap, NULL, col, closure)) { *image_pixel = col->pixel; *mask_pixel = 1; alloc_pixels[(*nalloc_pixels)++] = col->pixel; return (0); } else { /* colormap has probably changed, so * re-read... */ if (n == ITERATIONS - 1) XGrabServer(display); #if 0 if (visual->class == DirectColor) { /* TODO */ } else #endif XQueryColors(display, colormap, cols, ncols); } } return (1); } #define USE_CLOSECOLOR attributes && \ (((attributes->valuemask & XpmCloseness) && attributes->closeness != 0) \ || ((attributes->valuemask & XpmRGBCloseness) && \ (attributes->red_closeness != 0 \ || attributes->green_closeness != 0 \ || attributes->blue_closeness != 0))) #else /* FOR_MSW part */ /* nothing to do here, the window system does it */ #endif /* * set the color pixel related to the given colorname, * return 0 if success, 1 otherwise. */ static int SetColor(display, colormap, visual, colorname, color_index, image_pixel, mask_pixel, mask_pixel_index, alloc_pixels, nalloc_pixels, used_pixels, nused_pixels, attributes, cols, ncols, allocColor, closure) Display *display; Colormap colormap; Visual *visual; char *colorname; unsigned int color_index; Pixel *image_pixel, *mask_pixel; unsigned int *mask_pixel_index; Pixel *alloc_pixels; unsigned int *nalloc_pixels; Pixel *used_pixels; unsigned int *nused_pixels; XpmAttributes *attributes; XColor *cols; int ncols; XpmAllocColorFunc allocColor; void *closure; { XColor xcolor; int status; if (xpmstrcasecmp(colorname, TRANSPARENT_COLOR)) { status = (*allocColor)(display, colormap, colorname, &xcolor, closure); if (status < 0) /* parse color failed */ return (1); if (status == 0) { #ifndef FOR_MSW if (USE_CLOSECOLOR) return (SetCloseColor(display, colormap, visual, &xcolor, image_pixel, mask_pixel, alloc_pixels, nalloc_pixels, attributes, cols, ncols, allocColor, closure)); else #endif /* ndef FOR_MSW */ return (1); } else alloc_pixels[(*nalloc_pixels)++] = xcolor.pixel; *image_pixel = xcolor.pixel; #ifndef FOR_MSW *mask_pixel = 1; #else *mask_pixel = RGB(0,0,0); #endif used_pixels[(*nused_pixels)++] = xcolor.pixel; } else { *image_pixel = 0; #ifndef FOR_MSW *mask_pixel = 0; #else *mask_pixel = RGB(255,255,255); #endif /* store the color table index */ *mask_pixel_index = color_index; } return (0); } static int CreateColors(display, attributes, colors, ncolors, image_pixels, mask_pixels, mask_pixel_index, alloc_pixels, nalloc_pixels, used_pixels, nused_pixels) Display *display; XpmAttributes *attributes; XpmColor *colors; unsigned int ncolors; Pixel *image_pixels; Pixel *mask_pixels; unsigned int *mask_pixel_index; Pixel *alloc_pixels; unsigned int *nalloc_pixels; Pixel *used_pixels; unsigned int *nused_pixels; { /* variables stored in the XpmAttributes structure */ Visual *visual; Colormap colormap; XpmColorSymbol *colorsymbols = NULL; unsigned int numsymbols; XpmAllocColorFunc allocColor; void *closure; char *colorname; unsigned int color, key; Bool pixel_defined; XpmColorSymbol *symbol = NULL; char **defaults; int ErrorStatus = XpmSuccess; char *s; int default_index; XColor *cols = NULL; unsigned int ncols = 0; /* * retrieve information from the XpmAttributes */ if (attributes && attributes->valuemask & XpmColorSymbols) { colorsymbols = attributes->colorsymbols; numsymbols = attributes->numsymbols; } else numsymbols = 0; if (attributes && attributes->valuemask & XpmVisual) visual = attributes->visual; else visual = XDefaultVisual(display, XDefaultScreen(display)); if (attributes && (attributes->valuemask & XpmColormap)) colormap = attributes->colormap; else colormap = XDefaultColormap(display, XDefaultScreen(display)); if (attributes && (attributes->valuemask & XpmColorKey)) key = attributes->color_key; else key = xpmVisualType(visual); if (attributes && (attributes->valuemask & XpmAllocColor)) allocColor = attributes->alloc_color; else allocColor = AllocColor; if (attributes && (attributes->valuemask & XpmColorClosure)) closure = attributes->color_closure; else closure = NULL; #ifndef FOR_MSW if (USE_CLOSECOLOR) { /* originally from SetCloseColor */ #if 0 if (visual->class == DirectColor) { /* * TODO: Implement close colors for DirectColor visuals. This is * difficult situation. Chances are that we will never get here, * because any machine that supports DirectColor will probably * also support TrueColor (and probably PseudoColor). Also, * DirectColor colormaps can be very large, so looking for close * colors may be too slow. */ } else { #endif unsigned int i; #ifndef AMIGA ncols = visual->map_entries; #else ncols = colormap->Count; #endif cols = (XColor *) XpmCalloc(ncols, sizeof(XColor)); for (i = 0; i < ncols; ++i) cols[i].pixel = i; XQueryColors(display, colormap, cols, ncols); #if 0 } #endif } #endif /* ndef FOR_MSW */ switch (key) { case XPM_MONO: default_index = 2; break; case XPM_GRAY4: default_index = 3; break; case XPM_GRAY: default_index = 4; break; case XPM_COLOR: default: default_index = 5; break; } for (color = 0; color < ncolors; color++, colors++, image_pixels++, mask_pixels++) { colorname = NULL; pixel_defined = False; defaults = (char **) colors; /* * look for a defined symbol */ if (numsymbols) { unsigned int n; s = defaults[1]; for (n = 0, symbol = colorsymbols; n < numsymbols; n++, symbol++) { if (symbol->name && s && !strcmp(symbol->name, s)) /* override name */ break; if (!symbol->name && symbol->value) { /* override value */ int def_index = default_index; while (defaults[def_index] == NULL) /* find defined * colorname */ --def_index; if (def_index < 2) {/* nothing towards mono, so try * towards color */ def_index = default_index + 1; while (def_index <= 5 && defaults[def_index] == NULL) ++def_index; } if (def_index >= 2 && defaults[def_index] != NULL && !xpmstrcasecmp(symbol->value, defaults[def_index])) break; } } if (n != numsymbols) { if (symbol->name && symbol->value) colorname = symbol->value; else pixel_defined = True; } } if (!pixel_defined) { /* pixel not given as symbol value */ unsigned int k; if (colorname) { /* colorname given as symbol value */ if (!SetColor(display, colormap, visual, colorname, color, image_pixels, mask_pixels, mask_pixel_index, alloc_pixels, nalloc_pixels, used_pixels, nused_pixels, attributes, cols, ncols, allocColor, closure)) pixel_defined = True; else ErrorStatus = XpmColorError; } k = key; while (!pixel_defined && k > 1) { if (defaults[k]) { if (!SetColor(display, colormap, visual, defaults[k], color, image_pixels, mask_pixels, mask_pixel_index, alloc_pixels, nalloc_pixels, used_pixels, nused_pixels, attributes, cols, ncols, allocColor, closure)) { pixel_defined = True; break; } else ErrorStatus = XpmColorError; } k--; } k = key + 1; while (!pixel_defined && k < NKEYS + 1) { if (defaults[k]) { if (!SetColor(display, colormap, visual, defaults[k], color, image_pixels, mask_pixels, mask_pixel_index, alloc_pixels, nalloc_pixels, used_pixels, nused_pixels, attributes, cols, ncols, allocColor, closure)) { pixel_defined = True; break; } else ErrorStatus = XpmColorError; } k++; } if (!pixel_defined) { if (cols) XpmFree(cols); return (XpmColorFailed); } } else { /* simply use the given pixel */ *image_pixels = symbol->pixel; /* the following makes the mask to be built even if none is given a particular pixel */ if (symbol->value && !xpmstrcasecmp(symbol->value, TRANSPARENT_COLOR)) { *mask_pixels = 0; *mask_pixel_index = color; } else *mask_pixels = 1; used_pixels[(*nused_pixels)++] = *image_pixels; } } if (cols) XpmFree(cols); return (ErrorStatus); } /* default FreeColors function, simply call XFreeColors */ static int FreeColors(display, colormap, pixels, n, closure) Display *display; Colormap colormap; Pixel *pixels; int n; void *closure; /* not used */ { return XFreeColors(display, colormap, pixels, n, 0); } /* function call in case of error */ #undef RETURN #define RETURN(status) \ do \ { \ ErrorStatus = status; \ goto error; \ } while(0) int XpmCreateImageFromXpmImage(display, image, image_return, shapeimage_return, attributes) Display *display; XpmImage *image; XImage **image_return; XImage **shapeimage_return; XpmAttributes *attributes; { /* variables stored in the XpmAttributes structure */ Visual *visual; Colormap colormap; unsigned int depth; int bitmap_format; XpmFreeColorsFunc freeColors; /* variables to return */ XImage *ximage = NULL; XImage *shapeimage = NULL; unsigned int mask_pixel_index = XpmUndefPixel; int ErrorStatus; /* calculation variables */ Pixel *image_pixels = NULL; Pixel *mask_pixels = NULL; Pixel *alloc_pixels = NULL; Pixel *used_pixels = NULL; unsigned int nalloc_pixels = 0; unsigned int nused_pixels = 0; /* initialize return values */ if (image_return) *image_return = NULL; if (shapeimage_return) *shapeimage_return = NULL; /* retrieve information from the XpmAttributes */ if (attributes && (attributes->valuemask & XpmVisual)) visual = attributes->visual; else visual = XDefaultVisual(display, XDefaultScreen(display)); if (attributes && (attributes->valuemask & XpmColormap)) colormap = attributes->colormap; else colormap = XDefaultColormap(display, XDefaultScreen(display)); if (attributes && (attributes->valuemask & XpmDepth)) depth = attributes->depth; else depth = XDefaultDepth(display, XDefaultScreen(display)); if (attributes && (attributes->valuemask & XpmBitmapFormat)) bitmap_format = attributes->bitmap_format; else bitmap_format = ZPixmap; if (attributes && (attributes->valuemask & XpmFreeColors)) freeColors = attributes->free_colors; else freeColors = FreeColors; ErrorStatus = XpmSuccess; if (image->ncolors >= UINT_MAX / sizeof(Pixel)) return (XpmNoMemory); /* malloc pixels index tables */ image_pixels = (Pixel *) XpmMalloc(sizeof(Pixel) * image->ncolors); if (!image_pixels) return (XpmNoMemory); mask_pixels = (Pixel *) XpmMalloc(sizeof(Pixel) * image->ncolors); if (!mask_pixels) RETURN(XpmNoMemory); /* maximum of allocated pixels will be the number of colors */ alloc_pixels = (Pixel *) XpmMalloc(sizeof(Pixel) * image->ncolors); if (!alloc_pixels) RETURN(XpmNoMemory); /* maximum of allocated pixels will be the number of colors */ used_pixels = (Pixel *) XpmMalloc(sizeof(Pixel) * image->ncolors); if (!used_pixels) RETURN(XpmNoMemory); /* get pixel colors, store them in index tables */ ErrorStatus = CreateColors(display, attributes, image->colorTable, image->ncolors, image_pixels, mask_pixels, &mask_pixel_index, alloc_pixels, &nalloc_pixels, used_pixels, &nused_pixels); if (ErrorStatus != XpmSuccess && (ErrorStatus < 0 || (attributes && (attributes->valuemask & XpmExactColors) && attributes->exactColors))) RETURN(ErrorStatus); /* create the ximage */ if (image_return) { ErrorStatus = CreateXImage(display, visual, depth, (depth == 1 ? bitmap_format : ZPixmap), image->width, image->height, &ximage); if (ErrorStatus != XpmSuccess) RETURN(ErrorStatus); #ifndef FOR_MSW # ifndef AMIGA /* * set the ximage data using optimized functions for ZPixmap */ if (ximage->bits_per_pixel == 8) PutImagePixels8(ximage, image->width, image->height, image->data, image_pixels); else if (((ximage->bits_per_pixel | ximage->depth) == 1) && (ximage->byte_order == ximage->bitmap_bit_order)) PutImagePixels1(ximage, image->width, image->height, image->data, image_pixels); else if (ximage->bits_per_pixel == 16) PutImagePixels16(ximage, image->width, image->height, image->data, image_pixels); else if (ximage->bits_per_pixel == 32) PutImagePixels32(ximage, image->width, image->height, image->data, image_pixels); else PutImagePixels(ximage, image->width, image->height, image->data, image_pixels); # else /* AMIGA */ APutImagePixels(ximage, image->width, image->height, image->data, image_pixels); # endif #else /* FOR_MSW */ MSWPutImagePixels(display, ximage, image->width, image->height, image->data, image_pixels); #endif } /* create the shape mask image */ if (mask_pixel_index != XpmUndefPixel && shapeimage_return) { ErrorStatus = CreateXImage(display, visual, 1, bitmap_format, image->width, image->height, &shapeimage); if (ErrorStatus != XpmSuccess) RETURN(ErrorStatus); #ifndef FOR_MSW # ifndef AMIGA PutImagePixels1(shapeimage, image->width, image->height, image->data, mask_pixels); # else /* AMIGA */ APutImagePixels(shapeimage, image->width, image->height, image->data, mask_pixels); # endif #else /* FOR_MSW */ MSWPutImagePixels(display, shapeimage, image->width, image->height, image->data, mask_pixels); #endif } XpmFree(image_pixels); XpmFree(mask_pixels); /* if requested return used pixels in the XpmAttributes structure */ if (attributes && (attributes->valuemask & XpmReturnPixels || /* 3.2 backward compatibility code */ attributes->valuemask & XpmReturnInfos)) { /* end 3.2 bc */ attributes->pixels = used_pixels; attributes->npixels = nused_pixels; attributes->mask_pixel = mask_pixel_index; } else XpmFree(used_pixels); /* if requested return alloc'ed pixels in the XpmAttributes structure */ if (attributes && (attributes->valuemask & XpmReturnAllocPixels)) { attributes->alloc_pixels = alloc_pixels; attributes->nalloc_pixels = nalloc_pixels; } else XpmFree(alloc_pixels); /* return created images */ if (image_return) *image_return = ximage; if (shapeimage_return) *shapeimage_return = shapeimage; return (ErrorStatus); /* exit point in case of error, free only locally allocated variables */ error: if (ximage) XDestroyImage(ximage); if (shapeimage) XDestroyImage(shapeimage); if (image_pixels) XpmFree(image_pixels); if (mask_pixels) XpmFree(mask_pixels); if (nalloc_pixels) (*freeColors)(display, colormap, alloc_pixels, nalloc_pixels, NULL); if (alloc_pixels) XpmFree(alloc_pixels); if (used_pixels) XpmFree(used_pixels); return (ErrorStatus); } /* * Create an XImage with its data */ static int CreateXImage(display, visual, depth, format, width, height, image_return) Display *display; Visual *visual; unsigned int depth; int format; unsigned int width; unsigned int height; XImage **image_return; { int bitmap_pad; /* first get bitmap_pad */ if (depth > 16) bitmap_pad = 32; else if (depth > 8) bitmap_pad = 16; else bitmap_pad = 8; /* then create the XImage with data = NULL and bytes_per_line = 0 */ *image_return = XCreateImage(display, visual, depth, format, 0, 0, width, height, bitmap_pad, 0); if (!*image_return) return (XpmNoMemory); #if !defined(FOR_MSW) && !defined(AMIGA) if (height != 0 && (*image_return)->bytes_per_line >= INT_MAX / height) { XDestroyImage(*image_return); return XpmNoMemory; } /* now that bytes_per_line must have been set properly alloc data */ if((*image_return)->bytes_per_line == 0 || height == 0) return XpmNoMemory; (*image_return)->data = (char *) XpmMalloc((*image_return)->bytes_per_line * height); if (!(*image_return)->data) { XDestroyImage(*image_return); *image_return = NULL; return (XpmNoMemory); } #else /* under FOR_MSW and AMIGA XCreateImage has done it all */ #endif return (XpmSuccess); } #ifndef FOR_MSW # ifndef AMIGA /* * The functions below are written from X11R5 MIT's code (XImUtil.c) * * The idea is to have faster functions than the standard XPutPixel function * to build the image data. Indeed we can speed up things by suppressing tests * performed for each pixel. We do the same tests but at the image level. * We also assume that we use only ZPixmap images with null offsets. */ LFUNC(_putbits, void, (register char *src, int dstoffset, register int numbits, register char *dst)); LFUNC(_XReverse_Bytes, int, (register unsigned char *bpt, register unsigned int nb)); static unsigned char Const _reverse_byte[0x100] = { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff }; static int _XReverse_Bytes(bpt, nb) register unsigned char *bpt; register unsigned int nb; { do { *bpt = _reverse_byte[*bpt]; bpt++; } while (--nb > 0); /* is nb user-controled? */ return 0; } void xpm_xynormalizeimagebits(bp, img) register unsigned char *bp; register XImage *img; { register unsigned char c; if (img->byte_order != img->bitmap_bit_order) { switch (img->bitmap_unit) { case 16: c = *bp; *bp = *(bp + 1); *(bp + 1) = c; break; case 32: c = *(bp + 3); *(bp + 3) = *bp; *bp = c; c = *(bp + 2); *(bp + 2) = *(bp + 1); *(bp + 1) = c; break; } } if (img->bitmap_bit_order == MSBFirst) _XReverse_Bytes(bp, img->bitmap_unit >> 3); } void xpm_znormalizeimagebits(bp, img) register unsigned char *bp; register XImage *img; { register unsigned char c; switch (img->bits_per_pixel) { case 2: _XReverse_Bytes(bp, 1); break; case 4: *bp = ((*bp >> 4) & 0xF) | ((*bp << 4) & ~0xF); break; case 16: c = *bp; *bp = *(bp + 1); *(bp + 1) = c; break; case 24: c = *(bp + 2); *(bp + 2) = *bp; *bp = c; break; case 32: c = *(bp + 3); *(bp + 3) = *bp; *bp = c; c = *(bp + 2); *(bp + 2) = *(bp + 1); *(bp + 1) = c; break; } } static unsigned char Const _lomask[0x09] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; static unsigned char Const _himask[0x09] = { 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00}; static void _putbits(src, dstoffset, numbits, dst) register char *src; /* address of source bit string */ int dstoffset; /* bit offset into destination; * range is 0-31 */ register int numbits; /* number of bits to copy to * destination */ register char *dst; /* address of destination bit string */ { register unsigned char chlo, chhi; int hibits; dst = dst + (dstoffset >> 3); dstoffset = dstoffset & 7; hibits = 8 - dstoffset; chlo = *dst & _lomask[dstoffset]; for (;;) { chhi = (*src << dstoffset) & _himask[dstoffset]; if (numbits <= hibits) { chhi = chhi & _lomask[dstoffset + numbits]; *dst = (*dst & _himask[dstoffset + numbits]) | chlo | chhi; break; } *dst = chhi | chlo; dst++; numbits = numbits - hibits; chlo = (unsigned char) (*src & _himask[hibits]) >> hibits; src++; if (numbits <= dstoffset) { chlo = chlo & _lomask[numbits]; *dst = (*dst & _himask[numbits]) | chlo; break; } numbits = numbits - dstoffset; } } /* * Default method to write pixels into a Z image data structure. * The algorithm used is: * * copy the destination bitmap_unit or Zpixel to temp * normalize temp if needed * copy the pixel bits into the temp * renormalize temp if needed * copy the temp back into the destination image data */ static void PutImagePixels(image, width, height, pixelindex, pixels) XImage *image; unsigned int width; unsigned int height; unsigned int *pixelindex; Pixel *pixels; { register char *src; register char *dst; register unsigned int *iptr; register unsigned int x, y; register char *data; Pixel pixel, px; int nbytes, depth, ibu, ibpp, i; data = image->data; iptr = pixelindex; depth = image->depth; if (depth == 1) { ibu = image->bitmap_unit; for (y = 0; y < height; y++) /* how can we trust height */ for (x = 0; x < width; x++, iptr++) { /* how can we trust width */ pixel = pixels[*iptr]; for (i = 0, px = pixel; i < sizeof(unsigned long); i++, px >>= 8) ((unsigned char *) &pixel)[i] = px; src = &data[XYINDEX(x, y, image)]; dst = (char *) &px; px = 0; nbytes = ibu >> 3; for (i = nbytes; --i >= 0;) *dst++ = *src++; XYNORMALIZE(&px, image); _putbits((char *) &pixel, (x % ibu), 1, (char *) &px); XYNORMALIZE(&px, image); src = (char *) &px; dst = &data[XYINDEX(x, y, image)]; for (i = nbytes; --i >= 0;) *dst++ = *src++; } } else { ibpp = image->bits_per_pixel; for (y = 0; y < height; y++) for (x = 0; x < width; x++, iptr++) { pixel = pixels[*iptr]; if (depth == 4) pixel &= 0xf; for (i = 0, px = pixel; i < sizeof(unsigned long); i++, px >>= 8) ((unsigned char *) &pixel)[i] = px; src = &data[ZINDEX(x, y, image)]; dst = (char *) &px; px = 0; nbytes = (ibpp + 7) >> 3; for (i = nbytes; --i >= 0;) *dst++ = *src++; ZNORMALIZE(&px, image); _putbits((char *) &pixel, (x * ibpp) & 7, ibpp, (char *) &px); ZNORMALIZE(&px, image); src = (char *) &px; dst = &data[ZINDEX(x, y, image)]; for (i = nbytes; --i >= 0;) *dst++ = *src++; } } } /* * write pixels into a 32-bits Z image data structure */ #if !defined(WORD64) && !defined(LONG64) /* this item is static but deterministic so let it slide; doesn't * hurt re-entrancy of this library. Note if it is actually const then would * be OK under rules of ANSI-C but probably not C++ which may not * want to allocate space for it. */ static unsigned long byteorderpixel = MSBFirst << 24; #endif /* WITHOUT_SPEEDUPS is a flag to be turned on if you wish to use the original 3.2e code - by default you get the speeded-up version. */ static void PutImagePixels32(image, width, height, pixelindex, pixels) XImage *image; unsigned int width; unsigned int height; unsigned int *pixelindex; Pixel *pixels; { unsigned char *data; unsigned int *iptr; unsigned int y; Pixel pixel; #ifdef WITHOUT_SPEEDUPS unsigned int x; unsigned char *addr; data = (unsigned char *) image->data; iptr = pixelindex; #if !defined(WORD64) && !defined(LONG64) if (*((char *) &byteorderpixel) == image->byte_order) { for (y = 0; y < height; y++) for (x = 0; x < width; x++, iptr++) { addr = &data[ZINDEX32(x, y, image)]; *((unsigned long *) addr) = pixels[*iptr]; } } else #endif if (image->byte_order == MSBFirst) for (y = 0; y < height; y++) for (x = 0; x < width; x++, iptr++) { addr = &data[ZINDEX32(x, y, image)]; pixel = pixels[*iptr]; addr[0] = pixel >> 24; addr[1] = pixel >> 16; addr[2] = pixel >> 8; addr[3] = pixel; } else for (y = 0; y < height; y++) for (x = 0; x < width; x++, iptr++) { addr = &data[ZINDEX32(x, y, image)]; pixel = pixels[*iptr]; addr[0] = pixel; addr[1] = pixel >> 8; addr[2] = pixel >> 16; addr[3] = pixel >> 24; } #else /* WITHOUT_SPEEDUPS */ unsigned int bpl = image->bytes_per_line; unsigned char *data_ptr, *max_data; data = (unsigned char *) image->data; iptr = pixelindex; #if !defined(WORD64) && !defined(LONG64) if (*((char *) &byteorderpixel) == image->byte_order) { for (y = 0; y < height; y++) { data_ptr = data; max_data = data_ptr + (width << 2); while (data_ptr < max_data) { *((unsigned long *) data_ptr) = pixels[*(iptr++)]; data_ptr += (1 << 2); } data += bpl; } } else #endif if (image->byte_order == MSBFirst) for (y = 0; y < height; y++) { data_ptr = data; max_data = data_ptr + (width << 2); while (data_ptr < max_data) { pixel = pixels[*(iptr++)]; *data_ptr++ = pixel >> 24; *data_ptr++ = pixel >> 16; *data_ptr++ = pixel >> 8; *data_ptr++ = pixel; } data += bpl; } else for (y = 0; y < height; y++) { data_ptr = data; max_data = data_ptr + (width << 2); while (data_ptr < max_data) { pixel = pixels[*(iptr++)]; *data_ptr++ = pixel; *data_ptr++ = pixel >> 8; *data_ptr++ = pixel >> 16; *data_ptr++ = pixel >> 24; } data += bpl; } #endif /* WITHOUT_SPEEDUPS */ } /* * write pixels into a 16-bits Z image data structure */ static void PutImagePixels16(image, width, height, pixelindex, pixels) XImage *image; unsigned int width; unsigned int height; unsigned int *pixelindex; Pixel *pixels; { unsigned char *data; unsigned int *iptr; unsigned int y; #ifdef WITHOUT_SPEEDUPS unsigned int x; unsigned char *addr; data = (unsigned char *) image->data; iptr = pixelindex; if (image->byte_order == MSBFirst) for (y = 0; y < height; y++) for (x = 0; x < width; x++, iptr++) { addr = &data[ZINDEX16(x, y, image)]; addr[0] = pixels[*iptr] >> 8; addr[1] = pixels[*iptr]; } else for (y = 0; y < height; y++) for (x = 0; x < width; x++, iptr++) { addr = &data[ZINDEX16(x, y, image)]; addr[0] = pixels[*iptr]; addr[1] = pixels[*iptr] >> 8; } #else /* WITHOUT_SPEEDUPS */ Pixel pixel; unsigned int bpl = image->bytes_per_line; unsigned char *data_ptr, *max_data; data = (unsigned char *) image->data; iptr = pixelindex; if (image->byte_order == MSBFirst) for (y = 0; y < height; y++) { data_ptr = data; max_data = data_ptr + (width << 1); while (data_ptr < max_data) { pixel = pixels[*(iptr++)]; data_ptr[0] = pixel >> 8; data_ptr[1] = pixel; data_ptr += (1 << 1); } data += bpl; } else for (y = 0; y < height; y++) { data_ptr = data; max_data = data_ptr + (width << 1); while (data_ptr < max_data) { pixel = pixels[*(iptr++)]; data_ptr[0] = pixel; data_ptr[1] = pixel >> 8; data_ptr += (1 << 1); } data += bpl; } #endif /* WITHOUT_SPEEDUPS */ } /* * write pixels into a 8-bits Z image data structure */ static void PutImagePixels8(image, width, height, pixelindex, pixels) XImage *image; unsigned int width; unsigned int height; unsigned int *pixelindex; Pixel *pixels; { char *data; unsigned int *iptr; unsigned int y; #ifdef WITHOUT_SPEEDUPS unsigned int x; data = image->data; iptr = pixelindex; for (y = 0; y < height; y++) for (x = 0; x < width; x++, iptr++) data[ZINDEX8(x, y, image)] = pixels[*iptr]; #else /* WITHOUT_SPEEDUPS */ unsigned int bpl = image->bytes_per_line; char *data_ptr, *max_data; data = image->data; iptr = pixelindex; for (y = 0; y < height; y++) { data_ptr = data; max_data = data_ptr + width; while (data_ptr < max_data) *(data_ptr++) = pixels[*(iptr++)]; data += bpl; } #endif /* WITHOUT_SPEEDUPS */ } /* * write pixels into a 1-bit depth image data structure and **offset null** */ static void PutImagePixels1(image, width, height, pixelindex, pixels) XImage *image; unsigned int width; unsigned int height; unsigned int *pixelindex; Pixel *pixels; { if (image->byte_order != image->bitmap_bit_order) PutImagePixels(image, width, height, pixelindex, pixels); else { unsigned int *iptr; unsigned int y; char *data; #ifdef WITHOUT_SPEEDUPS unsigned int x; data = image->data; iptr = pixelindex; if (image->bitmap_bit_order == MSBFirst) for (y = 0; y < height; y++) for (x = 0; x < width; x++, iptr++) { if (pixels[*iptr] & 1) data[ZINDEX1(x, y, image)] |= 0x80 >> (x & 7); else data[ZINDEX1(x, y, image)] &= ~(0x80 >> (x & 7)); } else for (y = 0; y < height; y++) for (x = 0; x < width; x++, iptr++) { if (pixels[*iptr] & 1) data[ZINDEX1(x, y, image)] |= 1 << (x & 7); else data[ZINDEX1(x, y, image)] &= ~(1 << (x & 7)); } #else /* WITHOUT_SPEEDUPS */ char value; char *data_ptr, *max_data; int bpl = image->bytes_per_line; int diff, count; data = image->data; iptr = pixelindex; diff = width & 7; width >>= 3; if (image->bitmap_bit_order == MSBFirst) for (y = 0; y < height; y++) { data_ptr = data; max_data = data_ptr + width; while (data_ptr < max_data) { value = 0; value = (value << 1) | (pixels[*(iptr++)] & 1); value = (value << 1) | (pixels[*(iptr++)] & 1); value = (value << 1) | (pixels[*(iptr++)] & 1); value = (value << 1) | (pixels[*(iptr++)] & 1); value = (value << 1) | (pixels[*(iptr++)] & 1); value = (value << 1) | (pixels[*(iptr++)] & 1); value = (value << 1) | (pixels[*(iptr++)] & 1); value = (value << 1) | (pixels[*(iptr++)] & 1); *(data_ptr++) = value; } if (diff) { value = 0; for (count = 0; count < diff; count++) { if (pixels[*(iptr++)] & 1) value |= (0x80 >> count); } *(data_ptr) = value; } data += bpl; } else for (y = 0; y < height; y++) { data_ptr = data; max_data = data_ptr + width; while (data_ptr < max_data) { value = 0; iptr += 8; value = (value << 1) | (pixels[*(--iptr)] & 1); value = (value << 1) | (pixels[*(--iptr)] & 1); value = (value << 1) | (pixels[*(--iptr)] & 1); value = (value << 1) | (pixels[*(--iptr)] & 1); value = (value << 1) | (pixels[*(--iptr)] & 1); value = (value << 1) | (pixels[*(--iptr)] & 1); value = (value << 1) | (pixels[*(--iptr)] & 1); value = (value << 1) | (pixels[*(--iptr)] & 1); iptr += 8; *(data_ptr++) = value; } if (diff) { value = 0; for (count = 0; count < diff; count++) { if (pixels[*(iptr++)] & 1) value |= (1 << count); } *(data_ptr) = value; } data += bpl; } #endif /* WITHOUT_SPEEDUPS */ } } int XpmCreatePixmapFromXpmImage(display, d, image, pixmap_return, shapemask_return, attributes) Display *display; Drawable d; XpmImage *image; Pixmap *pixmap_return; Pixmap *shapemask_return; XpmAttributes *attributes; { XImage *ximage, *shapeimage; int ErrorStatus; /* initialize return values */ if (pixmap_return) *pixmap_return = 0; if (shapemask_return) *shapemask_return = 0; /* create the ximages */ ErrorStatus = XpmCreateImageFromXpmImage(display, image, (pixmap_return ? &ximage : NULL), (shapemask_return ? &shapeimage : NULL), attributes); if (ErrorStatus < 0) return (ErrorStatus); /* create the pixmaps and destroy images */ if (pixmap_return && ximage) { xpmCreatePixmapFromImage(display, d, ximage, pixmap_return); XDestroyImage(ximage); } if (shapemask_return && shapeimage) { xpmCreatePixmapFromImage(display, d, shapeimage, shapemask_return); XDestroyImage(shapeimage); } return (ErrorStatus); } # else /* AMIGA */ static void APutImagePixels ( XImage *image, unsigned int width, unsigned int height, unsigned int *pixelindex, Pixel *pixels) { unsigned int *data = pixelindex; unsigned int x, y; unsigned char *array; XImage *tmp_img; BOOL success = FALSE; array = XpmMalloc ((((width+15)>>4)<<4)*sizeof (*array)); if (array != NULL) { tmp_img = AllocXImage ((((width+15)>>4)<<4), 1, image->rp->BitMap->Depth); if (tmp_img != NULL) { for (y = 0; y < height; ++y) { for (x = 0; x < width; ++x) array[x] = pixels[*(data++)]; WritePixelLine8 (image->rp, 0, y, width, array, tmp_img->rp); } FreeXImage (tmp_img); success = TRUE; } XpmFree (array); } if (!success) { for (y = 0; y < height; ++y) for (x = 0; x < width; ++x) XPutPixel (image, x, y, pixels[*(data++)]); } } # endif/* AMIGA */ #else /* FOR_MSW part follows */ static void MSWPutImagePixels(dc, image, width, height, pixelindex, pixels) Display *dc; XImage *image; unsigned int width; unsigned int height; unsigned int *pixelindex; Pixel *pixels; { unsigned int *data = pixelindex; unsigned int x, y; HBITMAP obm; obm = SelectObject(*dc, image->bitmap); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { SetPixel(*dc, x, y, pixels[*(data++)]); /* data is [x+y*width] */ } } SelectObject(*dc, obm); } #endif /* FOR_MSW */ #if !defined(FOR_MSW) && !defined(AMIGA) static int PutPixel1(ximage, x, y, pixel) register XImage *ximage; int x; int y; unsigned long pixel; { register char *src; register char *dst; register int i; Pixel px; int nbytes; if(x < 0 || y < 0) return 0; for (i=0, px=pixel; i>=8) ((unsigned char *)&pixel)[i] = px; src = &ximage->data[XYINDEX(x, y, ximage)]; dst = (char *)&px; px = 0; nbytes = ximage->bitmap_unit >> 3; for (i = nbytes; --i >= 0; ) *dst++ = *src++; XYNORMALIZE(&px, ximage); i = ((x + ximage->xoffset) % ximage->bitmap_unit); _putbits ((char *)&pixel, i, 1, (char *)&px); XYNORMALIZE(&px, ximage); src = (char *) &px; dst = &ximage->data[XYINDEX(x, y, ximage)]; for (i = nbytes; --i >= 0; ) *dst++ = *src++; return 1; } static int PutPixel(ximage, x, y, pixel) register XImage *ximage; int x; int y; unsigned long pixel; { register char *src; register char *dst; register int i; Pixel px; unsigned int nbytes, ibpp; if(x < 0 || y < 0) return 0; ibpp = ximage->bits_per_pixel; if (ximage->depth == 4) pixel &= 0xf; for (i = 0, px = pixel; i < sizeof(unsigned long); i++, px >>= 8) ((unsigned char *) &pixel)[i] = px; src = &ximage->data[ZINDEX(x, y, ximage)]; dst = (char *) &px; px = 0; nbytes = (ibpp + 7) >> 3; for (i = nbytes; --i >= 0;) *dst++ = *src++; ZNORMALIZE(&px, ximage); _putbits((char *) &pixel, (x * ibpp) & 7, ibpp, (char *) &px); ZNORMALIZE(&px, ximage); src = (char *) &px; dst = &ximage->data[ZINDEX(x, y, ximage)]; for (i = nbytes; --i >= 0;) *dst++ = *src++; return 1; } #if !defined(WORD64) && !defined(LONG64) static int PutPixel32(ximage, x, y, pixel) register XImage *ximage; int x; int y; unsigned long pixel; { unsigned char *addr; if(x < 0 || y < 0) return 0; addr = &((unsigned char *)ximage->data) [ZINDEX32(x, y, ximage)]; *((unsigned long *)addr) = pixel; return 1; } #endif static int PutPixel32MSB(ximage, x, y, pixel) register XImage *ximage; int x; int y; unsigned long pixel; { unsigned char *addr; if(x < 0 || y < 0) return 0; addr = &((unsigned char *)ximage->data) [ZINDEX32(x, y, ximage)]; addr[0] = pixel >> 24; addr[1] = pixel >> 16; addr[2] = pixel >> 8; addr[3] = pixel; return 1; } static int PutPixel32LSB(ximage, x, y, pixel) register XImage *ximage; int x; int y; unsigned long pixel; { unsigned char *addr; if(x < 0 || y < 0) return 0; addr = &((unsigned char *)ximage->data) [ZINDEX32(x, y, ximage)]; addr[3] = pixel >> 24; addr[2] = pixel >> 16; addr[1] = pixel >> 8; addr[0] = pixel; return 1; } static int PutPixel16MSB(ximage, x, y, pixel) register XImage *ximage; int x; int y; unsigned long pixel; { unsigned char *addr; if(x < 0 || y < 0) return 0; addr = &((unsigned char *)ximage->data) [ZINDEX16(x, y, ximage)]; addr[0] = pixel >> 8; addr[1] = pixel; return 1; } static int PutPixel16LSB(ximage, x, y, pixel) register XImage *ximage; int x; int y; unsigned long pixel; { unsigned char *addr; if(x < 0 || y < 0) return 0; addr = &((unsigned char *)ximage->data) [ZINDEX16(x, y, ximage)]; addr[1] = pixel >> 8; addr[0] = pixel; return 1; } static int PutPixel8(ximage, x, y, pixel) register XImage *ximage; int x; int y; unsigned long pixel; { if(x < 0 || y < 0) return 0; ximage->data[ZINDEX8(x, y, ximage)] = pixel; return 1; } static int PutPixel1MSB(ximage, x, y, pixel) register XImage *ximage; int x; int y; unsigned long pixel; { if(x < 0 || y < 0) return 0; if (pixel & 1) ximage->data[ZINDEX1(x, y, ximage)] |= 0x80 >> (x & 7); else ximage->data[ZINDEX1(x, y, ximage)] &= ~(0x80 >> (x & 7)); return 1; } static int PutPixel1LSB(ximage, x, y, pixel) register XImage *ximage; int x; int y; unsigned long pixel; { if(x < 0 || y < 0) return 0; if (pixel & 1) ximage->data[ZINDEX1(x, y, ximage)] |= 1 << (x & 7); else ximage->data[ZINDEX1(x, y, ximage)] &= ~(1 << (x & 7)); return 1; } #endif /* not FOR_MSW && not AMIGA */ /* * This function parses an Xpm file or data and directly create an XImage */ int xpmParseDataAndCreate(display, data, image_return, shapeimage_return, image, info, attributes) Display *display; xpmData *data; XImage **image_return; XImage **shapeimage_return; XpmImage *image; XpmInfo *info; XpmAttributes *attributes; { /* variables stored in the XpmAttributes structure */ Visual *visual; Colormap colormap; unsigned int depth; int bitmap_format; XpmFreeColorsFunc freeColors; /* variables to return */ XImage *ximage = NULL; XImage *shapeimage = NULL; unsigned int mask_pixel_index = XpmUndefPixel; /* calculation variables */ Pixel *image_pixels = NULL; Pixel *mask_pixels = NULL; Pixel *alloc_pixels = NULL; Pixel *used_pixels = NULL; unsigned int nalloc_pixels = 0; unsigned int nused_pixels = 0; unsigned int width, height, ncolors, cpp; unsigned int x_hotspot, y_hotspot, hotspot = 0, extensions = 0; XpmColor *colorTable = NULL; char *hints_cmt = NULL; char *colors_cmt = NULL; char *pixels_cmt = NULL; unsigned int cmts; int ErrorStatus; xpmHashTable hashtable; /* initialize return values */ if (image_return) *image_return = NULL; if (shapeimage_return) *shapeimage_return = NULL; /* retrieve information from the XpmAttributes */ if (attributes && (attributes->valuemask & XpmVisual)) visual = attributes->visual; else visual = XDefaultVisual(display, XDefaultScreen(display)); if (attributes && (attributes->valuemask & XpmColormap)) colormap = attributes->colormap; else colormap = XDefaultColormap(display, XDefaultScreen(display)); if (attributes && (attributes->valuemask & XpmDepth)) depth = attributes->depth; else depth = XDefaultDepth(display, XDefaultScreen(display)); if (attributes && (attributes->valuemask & XpmBitmapFormat)) bitmap_format = attributes->bitmap_format; else bitmap_format = ZPixmap; if (attributes && (attributes->valuemask & XpmFreeColors)) freeColors = attributes->free_colors; else freeColors = FreeColors; cmts = info && (info->valuemask & XpmReturnComments); /* * parse the header */ ErrorStatus = xpmParseHeader(data); if (ErrorStatus != XpmSuccess) return (ErrorStatus); /* * read values */ ErrorStatus = xpmParseValues(data, &width, &height, &ncolors, &cpp, &x_hotspot, &y_hotspot, &hotspot, &extensions); if (ErrorStatus != XpmSuccess) return (ErrorStatus); /* * store the hints comment line */ if (cmts) xpmGetCmt(data, &hints_cmt); /* * init the hastable */ if (USE_HASHTABLE) { ErrorStatus = xpmHashTableInit(&hashtable); if (ErrorStatus != XpmSuccess) return (ErrorStatus); } /* * read colors */ ErrorStatus = xpmParseColors(data, ncolors, cpp, &colorTable, &hashtable); if (ErrorStatus != XpmSuccess) RETURN(ErrorStatus); /* * store the colors comment line */ if (cmts) xpmGetCmt(data, &colors_cmt); /* malloc pixels index tables */ if (ncolors >= UINT_MAX / sizeof(Pixel)) RETURN(XpmNoMemory); image_pixels = (Pixel *) XpmMalloc(sizeof(Pixel) * ncolors); if (!image_pixels) RETURN(XpmNoMemory); mask_pixels = (Pixel *) XpmMalloc(sizeof(Pixel) * ncolors); if (!mask_pixels) RETURN(XpmNoMemory); /* maximum of allocated pixels will be the number of colors */ alloc_pixels = (Pixel *) XpmMalloc(sizeof(Pixel) * ncolors); if (!alloc_pixels) RETURN(XpmNoMemory); /* maximum of allocated pixels will be the number of colors */ used_pixels = (Pixel *) XpmMalloc(sizeof(Pixel) * ncolors); if (!used_pixels) RETURN(XpmNoMemory); /* get pixel colors, store them in index tables */ ErrorStatus = CreateColors(display, attributes, colorTable, ncolors, image_pixels, mask_pixels, &mask_pixel_index, alloc_pixels, &nalloc_pixels, used_pixels, &nused_pixels); if (ErrorStatus != XpmSuccess && (ErrorStatus < 0 || (attributes && (attributes->valuemask & XpmExactColors) && attributes->exactColors))) RETURN(ErrorStatus); /* now create the ximage */ if (image_return) { ErrorStatus = CreateXImage(display, visual, depth, (depth == 1 ? bitmap_format : ZPixmap), width, height, &ximage); if (ErrorStatus != XpmSuccess) RETURN(ErrorStatus); #if !defined(FOR_MSW) && !defined(AMIGA) /* * set the XImage pointer function, to be used with XPutPixel, * to an internal optimized function */ if (ximage->bits_per_pixel == 8) ximage->f.put_pixel = PutPixel8; else if (((ximage->bits_per_pixel | ximage->depth) == 1) && (ximage->byte_order == ximage->bitmap_bit_order)) if (ximage->bitmap_bit_order == MSBFirst) ximage->f.put_pixel = PutPixel1MSB; else ximage->f.put_pixel = PutPixel1LSB; else if (ximage->bits_per_pixel == 16) if (ximage->bitmap_bit_order == MSBFirst) ximage->f.put_pixel = PutPixel16MSB; else ximage->f.put_pixel = PutPixel16LSB; else if (ximage->bits_per_pixel == 32) #if !defined(WORD64) && !defined(LONG64) if (*((char *)&byteorderpixel) == ximage->byte_order) ximage->f.put_pixel = PutPixel32; else #endif if (ximage->bitmap_bit_order == MSBFirst) ximage->f.put_pixel = PutPixel32MSB; else ximage->f.put_pixel = PutPixel32LSB; else if ((ximage->bits_per_pixel | ximage->depth) == 1) ximage->f.put_pixel = PutPixel1; else ximage->f.put_pixel = PutPixel; #endif /* not FOR_MSW && not AMIGA */ } /* create the shape mask image */ if (mask_pixel_index != XpmUndefPixel && shapeimage_return) { ErrorStatus = CreateXImage(display, visual, 1, bitmap_format, width, height, &shapeimage); if (ErrorStatus != XpmSuccess) RETURN(ErrorStatus); #if !defined(FOR_MSW) && !defined(AMIGA) if (shapeimage->bitmap_bit_order == MSBFirst) shapeimage->f.put_pixel = PutPixel1MSB; else shapeimage->f.put_pixel = PutPixel1LSB; #endif } /* * read pixels and put them in the XImage */ ErrorStatus = ParseAndPutPixels( #ifdef FOR_MSW display, #endif data, width, height, ncolors, cpp, colorTable, &hashtable, ximage, image_pixels, shapeimage, mask_pixels); XpmFree(image_pixels); image_pixels = NULL; XpmFree(mask_pixels); mask_pixels = NULL; /* * free the hastable */ if (ErrorStatus != XpmSuccess) RETURN(ErrorStatus); else if (USE_HASHTABLE) xpmHashTableFree(&hashtable); /* * store the pixels comment line */ if (cmts) xpmGetCmt(data, &pixels_cmt); /* * parse extensions */ if (info && (info->valuemask & XpmReturnExtensions)) { if (extensions) { ErrorStatus = xpmParseExtensions(data, &info->extensions, &info->nextensions); if (ErrorStatus != XpmSuccess) RETURN(ErrorStatus); } else { info->extensions = NULL; info->nextensions = 0; } } /* * store found informations in the XpmImage structure */ image->width = width; image->height = height; image->cpp = cpp; image->ncolors = ncolors; image->colorTable = colorTable; image->data = NULL; if (info) { if (cmts) { info->hints_cmt = hints_cmt; info->colors_cmt = colors_cmt; info->pixels_cmt = pixels_cmt; } if (hotspot) { info->x_hotspot = x_hotspot; info->y_hotspot = y_hotspot; info->valuemask |= XpmHotspot; } } /* if requested return used pixels in the XpmAttributes structure */ if (attributes && (attributes->valuemask & XpmReturnPixels || /* 3.2 backward compatibility code */ attributes->valuemask & XpmReturnInfos)) { /* end 3.2 bc */ attributes->pixels = used_pixels; attributes->npixels = nused_pixels; attributes->mask_pixel = mask_pixel_index; } else XpmFree(used_pixels); /* if requested return alloc'ed pixels in the XpmAttributes structure */ if (attributes && (attributes->valuemask & XpmReturnAllocPixels)) { attributes->alloc_pixels = alloc_pixels; attributes->nalloc_pixels = nalloc_pixels; } else XpmFree(alloc_pixels); /* return created images */ if (image_return) *image_return = ximage; if (shapeimage_return) *shapeimage_return = shapeimage; return (XpmSuccess); /* exit point in case of error, free only locally allocated variables */ error: if (USE_HASHTABLE) xpmHashTableFree(&hashtable); if (colorTable) xpmFreeColorTable(colorTable, ncolors); if (hints_cmt) XpmFree(hints_cmt); if (colors_cmt) XpmFree(colors_cmt); if (pixels_cmt) XpmFree(pixels_cmt); if (ximage) XDestroyImage(ximage); if (shapeimage) XDestroyImage(shapeimage); if (image_pixels) XpmFree(image_pixels); if (mask_pixels) XpmFree(mask_pixels); if (nalloc_pixels) (*freeColors)(display, colormap, alloc_pixels, nalloc_pixels, NULL); if (alloc_pixels) XpmFree(alloc_pixels); if (used_pixels) XpmFree(used_pixels); return (ErrorStatus); } static int ParseAndPutPixels( #ifdef FOR_MSW dc, #endif data, width, height, ncolors, cpp, colorTable, hashtable, image, image_pixels, shapeimage, shape_pixels) #ifdef FOR_MSW Display *dc; #endif xpmData *data; unsigned int width; unsigned int height; unsigned int ncolors; unsigned int cpp; XpmColor *colorTable; xpmHashTable *hashtable; XImage *image; Pixel *image_pixels; XImage *shapeimage; Pixel *shape_pixels; { unsigned int a, x, y; switch (cpp) { case (1): /* Optimize for single character * colors */ { unsigned short colidx[256]; #ifdef FOR_MSW HDC shapedc; HBITMAP obm, sobm; if ( shapeimage ) { shapedc = CreateCompatibleDC(*dc); sobm = SelectObject(shapedc, shapeimage->bitmap); } else { shapedc = NULL; } obm = SelectObject(*dc, image->bitmap); #endif if (ncolors > 256) return (XpmFileInvalid); bzero((char *)colidx, 256 * sizeof(short)); for (a = 0; a < ncolors; a++) colidx[(unsigned char)colorTable[a].string[0]] = a + 1; for (y = 0; y < height; y++) { xpmNextString(data); for (x = 0; x < width; x++) { int c = xpmGetC(data); if (c > 0 && c < 256 && colidx[c] != 0) { #ifndef FOR_MSW XPutPixel(image, x, y, image_pixels[colidx[c] - 1]); if (shapeimage) XPutPixel(shapeimage, x, y, shape_pixels[colidx[c] - 1]); #else SetPixel(*dc, x, y, image_pixels[colidx[c] - 1]); if (shapedc) { SetPixel(shapedc, x, y, shape_pixels[colidx[c] - 1]); } #endif } else return (XpmFileInvalid); } } #ifdef FOR_MSW if ( shapedc ) { SelectObject(shapedc, sobm); DeleteDC(shapedc); } SelectObject(*dc, obm); #endif } break; case (2): /* Optimize for double character * colors */ { /* free all allocated pointers at all exits */ #define FREE_CIDX {int f; for (f = 0; f < 256; f++) \ if (cidx[f]) XpmFree(cidx[f]);} /* array of pointers malloced by need */ unsigned short *cidx[256]; unsigned int char1; bzero((char *)cidx, 256 * sizeof(unsigned short *)); /* init */ for (a = 0; a < ncolors; a++) { char1 = (unsigned char) colorTable[a].string[0]; if (cidx[char1] == NULL) { /* get new memory */ cidx[char1] = (unsigned short *) XpmCalloc(256, sizeof(unsigned short)); if (cidx[char1] == NULL) { /* new block failed */ FREE_CIDX; return (XpmNoMemory); } } cidx[char1][(unsigned char)colorTable[a].string[1]] = a + 1; } for (y = 0; y < height; y++) { xpmNextString(data); for (x = 0; x < width; x++) { int cc1 = xpmGetC(data); if (cc1 > 0 && cc1 < 256) { int cc2 = xpmGetC(data); if (cc2 > 0 && cc2 < 256 && cidx[cc1] && cidx[cc1][cc2] != 0) { #ifndef FOR_MSW XPutPixel(image, x, y, image_pixels[cidx[cc1][cc2] - 1]); if (shapeimage) XPutPixel(shapeimage, x, y, shape_pixels[cidx[cc1][cc2] - 1]); #else SelectObject(*dc, image->bitmap); SetPixel(*dc, x, y, image_pixels[cidx[cc1][cc2] - 1]); if (shapeimage) { SelectObject(*dc, shapeimage->bitmap); SetPixel(*dc, x, y, shape_pixels[cidx[cc1][cc2] - 1]); } #endif } else { FREE_CIDX; return (XpmFileInvalid); } } else { FREE_CIDX; return (XpmFileInvalid); } } } FREE_CIDX; } break; default: /* Non-optimized case of long color * names */ { char *s; char buf[BUFSIZ]; if (cpp >= sizeof(buf)) return (XpmFileInvalid); buf[cpp] = '\0'; if (USE_HASHTABLE) { xpmHashAtom *slot; for (y = 0; y < height; y++) { xpmNextString(data); for (x = 0; x < width; x++) { for (a = 0, s = buf; a < cpp; a++, s++) *s = xpmGetC(data); slot = xpmHashSlot(hashtable, buf); if (!*slot) /* no color matches */ return (XpmFileInvalid); #ifndef FOR_MSW XPutPixel(image, x, y, image_pixels[HashColorIndex(slot)]); if (shapeimage) XPutPixel(shapeimage, x, y, shape_pixels[HashColorIndex(slot)]); #else SelectObject(*dc, image->bitmap); SetPixel(*dc, x, y, image_pixels[HashColorIndex(slot)]); if (shapeimage) { SelectObject(*dc, shapeimage->bitmap); SetPixel(*dc, x, y, shape_pixels[HashColorIndex(slot)]); } #endif } } } else { for (y = 0; y < height; y++) { xpmNextString(data); for (x = 0; x < width; x++) { for (a = 0, s = buf; a < cpp; a++, s++) *s = xpmGetC(data); for (a = 0; a < ncolors; a++) if (!strcmp(colorTable[a].string, buf)) break; if (a == ncolors) /* no color matches */ return (XpmFileInvalid); #ifndef FOR_MSW XPutPixel(image, x, y, image_pixels[a]); if (shapeimage) XPutPixel(shapeimage, x, y, shape_pixels[a]); #else SelectObject(*dc, image->bitmap); SetPixel(*dc, x, y, image_pixels[a]); if (shapeimage) { SelectObject(*dc, shapeimage->bitmap); SetPixel(*dc, x, y, shape_pixels[a]); } #endif } } } } break; } return (XpmSuccess); }