/*
        mindlib/read_xwd.c

        This program is free software; you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation; either version 2, or (at your option)
        any later version.

        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.

        You should have received a copy of the GNU General Public License
        along with this program; if not, write to the Free Software
        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/***************************************************************************
 ***************************************************************************
 *
 *  Filename:           read_xwd.c
 *
 *  Description:        Functions to read a xwd-format file.
 *
 *
 ***************************************************************************
 *
 *  Function Export:    XImage ReadXwd(char *file_name)
 *
 *
 ***************************************************************************
 ***************************************************************************/

#define XLIB_ILLEGAL_ACCESS

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/XWDFile.h>
#define  XK_LATIN1
#include <Xm/Xm.h>
#include <X11/keysymdef.h>

extern int errno;
 
#if defined(__cplusplus) || defined(c_plusplus)
#define class c_class
#endif
/* PROTOTYPES */

Bool Read(char *ptr, int size, int nitems, FILE *stream);
void Latin1Upper(unsigned char *str);
void Extract_Plane(register XImage *in_image, register XImage *out_image, int plane);
int EffectiveSize(XVisualInfo *vinfo);
int VisualRank(int c_class);
int IsGray(Display *dpy, XStandardColormap *stdmap);
void Do_StdGray(Display *dpy, XStandardColormap *stdmap, int ncolors, XColor *colors, 
	register XImage *in_image, register XImage *out_image);
void Do_StdCol(Display *dpy, XStandardColormap *stdmap, int ncolors, XColor *colors, 
	register XImage *in_image, register XImage *out_image);
Colormap CopyColormapAndFree(Display *dpy, Colormap colormap);
void Do_Pseudo(Display *dpy, Colormap *colormap, int ncolors, XColor *colors, 
	register XImage *in_image, register XImage *out_image);
void Do_Direct(Display *dpy, XWDFileHeader *header, Colormap *colormap, int ncolors, 
	XColor *colors, XImage *in_image, XImage *out_image);
unsigned Image_Size(XImage *image);
void _swapshort (register char *bp, register unsigned n);
void _swaplong (register char *bp, register unsigned n);

Bool Read(char *ptr, int size, int nitems, FILE *stream)
{
    size *= nitems;
    while (size) {
	nitems = fread(ptr, 1, size, stream);
	if (nitems <= 0) return False;
	size -= nitems;
	ptr += nitems;
    }
    return True;
}

XImage *ReadXWD(char *file_name, Widget parent)
{
    Display *dpy;
    int screen;
    register int i;
    XImage *in_image, *out_image;
    XSetWindowAttributes attributes;
    XVisualInfo vinfo, *vinfos;
    long mask;
    register char *buffer;
    unsigned long swaptest = 1;
    int count, stdcnt;
    unsigned buffer_size;
    int win_name_size;
    int ncolors;
    char *win_name;
    Bool inverse = False, rawbits = False, newmap = False;
    int plane = -1;
    char *std = NULL;
    char *vis = NULL;
    char *fgname = NULL;
    char *bgname = NULL;
    XColor *colors=NULL, color, igncolor;
    Colormap colormap;
    XGCValues gc_val;
    XWDFileHeader header;
    FILE *in_file;
    char *map_name;
    Atom map_prop;
    XStandardColormap *stdmaps, *stdmap=NULL;
    

    if (file_name) {
	in_file = fopen(file_name, "r");
	if (in_file == NULL){
          char buf[1000];
          sprintf(buf,"Can't open file '%s'\n",file_name);
	  XtWarning(buf);
	  return (XImage *) NULL;
        }
    } else return (XImage *) NULL;
    
    dpy = XtDisplay(parent);
    screen = DefaultScreen(dpy);

    /* READ IN HEADER INFORMATION  */
    if(!Read((char *)&header, sizeof(header), 1, in_file)){
      XtWarning("Unable to read dump file header.");
      return (XImage *) NULL;
    }

    if (*(char *) &swaptest) _swaplong((char *) &header, sizeof(header));

    /* CHECK TO SEE IF THE DUMP FILE IS IN THE PROPER FORMAT */
    if (header.file_version != XWD_FILE_VERSION) {
	fprintf(stderr,"xwud: XWD file format version mismatch.");
	return (XImage *) NULL;
    }
    if (header.header_size < sizeof(header)) {
	fprintf(stderr,"xwud: XWD header size is too small.");
	return (XImage *) NULL;
    }

    /* ALLOC WINDOW NAME ********************************************/
    win_name_size = (header.header_size - sizeof(header));
    if((win_name = (char *)malloc((unsigned) win_name_size + 6)) == NULL){
       	XtWarning("Can't malloc window name storage.");
	return (XImage *) NULL;
    }
    strcpy(win_name, "xwud: ");

     /* READ IN WINDOW NAME */
    if(!Read(win_name + 6, sizeof(char), win_name_size, in_file)){
      	XtWarning("Unable to read window name from dump file.");
	return (XImage *) NULL;
    }
    /* ALLOC WINDOW NAME **** This is maybe obsolet!*****************/

    /* INITIALIZE THE INPUT IMAGE */
    {
	Display fakedpy;
	ScreenFormat fakefmt;

	fakedpy.byte_order = (int) header.byte_order;
	fakedpy.bitmap_unit = (int) header.bitmap_unit;
	fakedpy.bitmap_bit_order = (int) header.bitmap_bit_order;
	fakedpy.pixmap_format = &fakefmt;
	fakedpy.nformats = 1;
	fakefmt.depth = (int) header.pixmap_depth;
	fakefmt.bits_per_pixel = (int) header.bits_per_pixel;

	in_image = XCreateImage(&fakedpy, NULL,
				(int) header.pixmap_depth,
				(int) header.pixmap_format,
				(int) header.xoffset, NULL,
				(int) header.pixmap_width,
				(int) header.pixmap_height,
				(int) header.bitmap_pad,
				(int) header.bytes_per_line);
    }

    in_image->red_mask = header.red_mask;
    in_image->green_mask = header.green_mask;
    in_image->blue_mask = header.blue_mask;

    /* READ IN THE COLOR MAP BUFFER */
    if((ncolors = header.ncolors)) {
	colors = (XColor *)malloc((unsigned) ncolors * sizeof(XColor));
	if (!colors){
	    XtWarning("Can't malloc color table");
	    return (XImage *) NULL;
	}
	if(!Read((char *) colors, sizeof(XColor), ncolors, in_file)){
	  XtWarning("Unable to read color map from xwd file.");
	  return (XImage *) NULL;
        }
	if (*(char *) &swaptest) {
	    for (i = 0; i < ncolors; i++) {
		_swaplong((char *) &colors[i].pixel, sizeof(long));
		_swapshort((char *) &colors[i].red, 3 * sizeof(short));
	    }
	}
    }

    /* ALLOC THE PIXEL BUFFER */
    buffer_size = Image_Size(in_image);
    if((buffer = (char *)malloc(buffer_size)) == NULL){
      	XtWarning("Can't malloc data buffer.");
	return (XImage *) NULL;
    }

    /* READ IN THE IMAGE DATA */
    if (!Read(buffer, sizeof(char), (int)buffer_size, in_file)){
        XtWarning("Unable to read pixmap from dump file.");
	return (XImage *) NULL;
    }

     /* CLOSE THE INPUT FILE */
    (void) fclose(in_file);

    if (plane >= in_image->depth) XtWarning("plane number exceeds image depth");
    if ((in_image->format == XYPixmap) && (plane >= 0)) {
	buffer += in_image->bytes_per_line * in_image->height *
		  (in_image->depth - (plane + 1));
	in_image->depth = 1;
	ncolors = 0;
    }
    if (in_image->depth == 1) {
	in_image->format = XYBitmap;
	newmap = False;
	rawbits = True;
    }
    in_image->data = buffer;

    if (std) {
	map_name = (char *)malloc(strlen(std) + 9);
	strcpy(map_name, "RGB_");
	strcat(map_name, std);
	strcat(map_name, "_MAP");
	Latin1Upper((unsigned char*)map_name);
	map_prop = XInternAtom(dpy, map_name, True);
	if (!map_prop || !XGetRGBColormaps(dpy, RootWindow(dpy, screen), &stdmaps, &stdcnt, map_prop)){
	    XtWarning("specified standard colormap does not exist");
	    return (XImage *) NULL;
	}
    }
    vinfo.screen = screen;
    mask = VisualScreenMask;
    if (vis)
    {
	char *vt;
	vt = (char *)malloc(strlen(vis) + 1);
	strcpy(vt, vis);
	Latin1Upper((unsigned char *)vt);
	if (strcmp(vt, "STATICGRAY") == 0) {
	    vinfo.class = StaticGray;
	    mask |= VisualClassMask;
	} else if (strcmp(vt, "GRAYSCALE") == 0) {
	    vinfo.class = GrayScale;
	    mask |= VisualClassMask;
	} else if (strcmp(vt, "STATICCOLOR") == 0) {
	    vinfo.class = StaticColor;
	    mask |= VisualClassMask;
	} else if (strcmp(vt, "PSEUDOCOLOR") == 0) {
	    vinfo.class = PseudoColor;
	    mask |= VisualClassMask;
	} else if (strcmp(vt, "DIRECTCOLOR") == 0) {
	    vinfo.class = DirectColor;
	    mask |= VisualClassMask;
	} else if (strcmp(vt, "TRUECOLOR") == 0) {
	    vinfo.class = TrueColor;
	    mask |= VisualClassMask;
	} else if (strcmp(vt, "MATCH") == 0) {
	    vinfo.class = header.visual_class;
	    mask |= VisualClassMask;
	} else if (strcmp(vt, "DEFAULT") == 0) {
	    vinfo.visualid= XVisualIDFromVisual(DefaultVisual(dpy, screen));
	    mask |= VisualIDMask;
	} else {
	    vinfo.visualid = 0;
	    mask |= VisualIDMask;
	    sscanf(vis, "0x%lx", &vinfo.visualid);
	    if (!vinfo.visualid)
	      sscanf(vis, "%lu", &vinfo.visualid);
	    if (!vinfo.visualid)
	      XtWarning("invalid visual specifier");
	}
    }
    if (rawbits && (in_image->depth > 1) && (plane < 0)) {
	vinfo.depth = in_image->depth;
	mask |= VisualDepthMask;
    }
    vinfos = XGetVisualInfo(dpy, mask, &vinfo, &count);
    if (count == 0){
	XtWarning("no matching visual found");
	return (XImage *) NULL;
    }

    /* FIND A WORKABLE VISUAL */
    if (std) {
	stdmap = &stdmaps[0];
	if (mask & VisualIDMask) {
	    for (i = 0; i < stdcnt; i++) {
		if (stdmaps[i].visualid == vinfo.visualid) {
		    stdmap = &stdmaps[i];
		    break;
		}
	    }
	    if (stdmap->visualid != vinfo.visualid)
		XtWarning("no standard colormap matching specified visual");
	}
	for (i = 0; i < count; i++) {
	    if (stdmap->visualid == vinfos[i].visualid) {
		vinfo = vinfos[i];
		break;
	    }
	}
    } else if ((in_image->depth == 1) ||
	       ((in_image->format == ZPixmap) && (plane >= 0)) ||
	       rawbits) {
	vinfo = vinfos[0];
	if (!(mask & VisualIDMask)) {
	    for (i = 0; i < count; i++) {
		if ((vinfos[i].visualid ==
		     XVisualIDFromVisual(DefaultVisual(dpy, screen))) &&
		    (vinfos[i].depth == DefaultDepth(dpy, screen))) {
		    vinfo = vinfos[i];
		    break;
		}
	    }
	}
    } else {
	/* GET BEST VISUAL */
	vinfo = vinfos[0];
	for (i = 1; i < count; i++) {
	    int z1, z2;
	    z2 = EffectiveSize(&vinfos[i]);
	    if ((z2 >= ncolors) &&
		(vinfos[i].depth == in_image->depth) &&
		(vinfos[i].class == (int)header.visual_class))
	    {
		vinfo = vinfos[i];
		break;
	    }
	    z1 = EffectiveSize(&vinfo);
	    if ((z2 > z1) ||
		((z2 == z1) &&
		 (VisualRank(vinfos[i].class) >= VisualRank(vinfo.class))))
		vinfo = vinfos[i];
	}
	if ((newmap || (vinfo.visual != DefaultVisual(dpy, screen))) &&
	    (vinfo.class != StaticGray) &&
	    (vinfo.class != StaticColor) &&
	    (vinfo.class == (int)header.visual_class) &&
	    (vinfo.depth == in_image->depth) &&
	    ((vinfo.class == PseudoColor) ||
	     (vinfo.class == GrayScale) ||
	     ((vinfo.red_mask == header.red_mask) &&
	      (vinfo.green_mask == header.green_mask) &&
	      (vinfo.blue_mask == header.blue_mask)))) {
	    rawbits = True;
	    newmap = True;
	}
    }

    /* GET THE APPROPRIATE COLORMAP */
    if (newmap && (vinfo.class & 1) &&
	((int) vinfo.depth == in_image->depth) &&
	(vinfo.class == (int) header.visual_class) &&
	(vinfo.colormap_size >= ncolors) &&
	(vinfo.red_mask == header.red_mask) &&
	(vinfo.green_mask == header.green_mask) &&
	(vinfo.blue_mask == header.blue_mask)) {
	colormap = XCreateColormap(dpy, RootWindow(dpy, screen), vinfo.visual,
				   AllocAll);
	if (ncolors) {
	    for (i = 0; i < ncolors; i++)
		colors[i].flags = DoRed|DoGreen|DoBlue;
	    XStoreColors(dpy, colormap, colors, ncolors);
	}
    } else if (std) {
	colormap = stdmap->colormap;
    } else {
	if (!newmap && (vinfo.visual == DefaultVisual(dpy, screen)))
	    colormap = DefaultColormap(dpy, screen);
	else
	    colormap = XCreateColormap(dpy, RootWindow(dpy, screen),
				       vinfo.visual, AllocNone);
	newmap = False;
    }

    /* CREATE THE OUTPUT IMAGE */
    if ((in_image->format == ZPixmap) && (plane >= 0)) {
	out_image = XCreateImage(dpy, vinfo.visual, 1,
				 XYBitmap, 0, NULL,
				 in_image->width, in_image->height,
				 XBitmapPad(dpy), 0);
	out_image->data = (char *)malloc(Image_Size(out_image));
	Extract_Plane(in_image, out_image, plane);
	ncolors = 0;
    } else if (rawbits || newmap) {
	out_image = in_image;
    } else {
	out_image = XCreateImage(dpy, vinfo.visual, vinfo.depth,
				 (vinfo.depth == 1) ? XYBitmap :
						      in_image->format,
				 in_image->xoffset, NULL,
				 in_image->width, in_image->height,
				 XBitmapPad(dpy), 0);
	out_image->data = (char *)malloc(Image_Size(out_image));
	if (std) {
	    if (!stdmap->green_max && !stdmap->blue_max && IsGray(dpy, stdmap))
		Do_StdGray(dpy, stdmap, ncolors, colors, in_image, out_image);
	    else
		Do_StdCol(dpy, stdmap, ncolors, colors, in_image, out_image);
	} else if ((header.visual_class == TrueColor) ||
		   (header.visual_class == DirectColor))
	    Do_Direct(dpy, &header, &colormap, ncolors, colors,
		      in_image, out_image);
	else
	    Do_Pseudo(dpy, &colormap, ncolors, colors, in_image, out_image);
    }

    if (out_image->depth == 1) {
	if (fgname &&
	    XAllocNamedColor(dpy, colormap, fgname, &color, &igncolor))
	    gc_val.foreground = color.pixel;
	else if ((ncolors == 2) && XAllocColor(dpy, colormap, &colors[1]))
	    gc_val.foreground = colors[1].pixel;
	else
	    gc_val.foreground = BlackPixel (dpy, screen);
	if (bgname &&
	    XAllocNamedColor(dpy, colormap, bgname, &color, &igncolor))
	    gc_val.background = color.pixel;
	else if ((ncolors == 2) && XAllocColor(dpy, colormap, &colors[0]))
	    gc_val.background = colors[0].pixel;
	else
	    gc_val.background = WhitePixel (dpy, screen);
	if (inverse) {
	    unsigned long tmp;
	    tmp = gc_val.foreground;
	    gc_val.foreground = gc_val.background;
	    gc_val.background = tmp;
	}
    } else {
	gc_val.background = XGetPixel(out_image, 0, 0);
	gc_val.foreground = 0;
    }

    attributes.background_pixel = gc_val.background;
    attributes.border_pixel = gc_val.background;
    attributes.bit_gravity = NorthWestGravity;
    attributes.event_mask = ButtonPressMask|ButtonReleaseMask|KeyPressMask|
			    ExposureMask;
    attributes.colormap = colormap;

    return out_image;
}

void Latin1Upper(unsigned char *str)
{
    unsigned char c;

    for (; (c = *str); str++)
    {
	if ((c >= XK_a) && (c <= XK_z)) 			*str = c - (XK_a - XK_A);
	else if ((c >= XK_agrave) && (c <= XK_odiaeresis)) 	*str = c - (XK_agrave - XK_Agrave);
	else if ((c >= XK_oslash) && (c <= XK_thorn)) 		*str = c - (XK_oslash - XK_Ooblique);
    }
}

void Extract_Plane(register XImage *in_image, register XImage *out_image, int plane)
{
    register int x, y;

    for (y = 0; y < in_image->height; y++)
	for (x = 0; x < in_image->width; x++)
	    XPutPixel(out_image, x, y,
		      (XGetPixel(in_image, x, y) >> plane) & 1);
}

int EffectiveSize(XVisualInfo *vinfo)
{
    if ((vinfo->class == DirectColor) || (vinfo->class == TrueColor))
	return (vinfo->red_mask | vinfo->green_mask | vinfo->blue_mask) + 1;
    else
	return vinfo->colormap_size;
}

int VisualRank(int class)
{
    switch (class) {
    case PseudoColor:
	return 5;
    case DirectColor:
	return 4;
    case TrueColor:
	return 3;
    case StaticColor:
	return 2;
    case GrayScale:
	return 1;
    case StaticGray:
	return 0;
    }
  return 0;
}

int IsGray(Display *dpy, XStandardColormap *stdmap)
{
    XColor color;

    color.pixel = stdmap->base_pixel + (stdmap->red_max * stdmap->red_mult);
    XQueryColor(dpy, stdmap->colormap, &color);
    return (color.green || color.blue);
}

void Do_StdGray(Display *dpy, XStandardColormap *stdmap, int ncolors, XColor *colors, register XImage *in_image, register XImage *out_image)
{
    register int i, x, y;
    register XColor *color;
    unsigned lim;

    lim = stdmap->red_max + 1;
    for (i = 0, color = colors; i < ncolors; i++, color++)
	color->pixel = stdmap->base_pixel +
		       (((((int)(30L * color->red +
			         59L * color->green +
			         11L * color->blue) / 100)
			  * lim) >> 16) * stdmap->red_mult);
    for (y = 0; y < in_image->height; y++) {
	for (x = 0; x < in_image->width; x++) {
	    XPutPixel(out_image, x, y,
		      colors[XGetPixel(in_image, x, y)].pixel);
	}
    }
}

#define MapVal(val,lim,mult) ((((val * lim) + 32768) / 65535) * mult)

void Do_StdCol(Display *dpy, XStandardColormap *stdmap, int ncolors, XColor *colors, register XImage *in_image, register XImage *out_image)
{
    register int i, x, y;
    register XColor *color;
    unsigned limr, limg, limb;

    limr = stdmap->red_max;
    limg = stdmap->green_max;
    limb = stdmap->blue_max;
    for (i = 0, color = colors; i < ncolors; i++, color++)
	color->pixel = stdmap->base_pixel +
		       MapVal(color->red, limr, stdmap->red_mult) +
		       MapVal(color->green, limg, stdmap->green_mult) +
		       MapVal(color->blue, limb, stdmap->blue_mult);
    for (y = 0; y < in_image->height; y++) {
	for (x = 0; x < in_image->width; x++) {
	    XPutPixel(out_image, x, y,
		      colors[XGetPixel(in_image, x, y)].pixel);
	}
    }
}

Colormap CopyColormapAndFree(Display *dpy, Colormap colormap)
{
    if (colormap == DefaultColormap(dpy, DefaultScreen(dpy)))
	return XCopyColormapAndFree(dpy, colormap);
    XtWarning("Visual type is not large enough to hold all colors of the image.");
    return 0;
}

void Do_Pseudo(Display *dpy, Colormap *colormap, int ncolors, XColor *colors, register XImage *in_image, register XImage *out_image)
{
    register int i, x, y;
    register XColor *color;

    for (i = 0; i < ncolors; i++) colors[i].flags = 0;
    for (y = 0; y < in_image->height; y++) {
	for (x = 0; x < in_image->width; x++) {
	    color = &colors[XGetPixel(in_image, x, y)];
	    if (!color->flags) {
		color->flags = DoRed | DoGreen | DoBlue;
		if (!XAllocColor(dpy, *colormap, color)) {
		    *colormap = CopyColormapAndFree(dpy, *colormap);
		    XAllocColor(dpy, *colormap, color);
		}
	    }
	    XPutPixel(out_image, x, y, color->pixel);
	}
    }
}

void Do_Direct(Display *dpy, XWDFileHeader *header, Colormap *colormap, int ncolors, XColor *colors, XImage *in_image, XImage *out_image)
{
    register int x, y;
    XColor color;
    unsigned long rmask, gmask, bmask;
    int rshift = 0, gshift = 0, bshift = 0;
    int i;
    unsigned long pix, xpix;
    unsigned long *pixels, *rpixels;

    rmask = header->red_mask;
    while (!(rmask & 1)) {
	rmask >>= 1;
	rshift++;
    }
    gmask = header->green_mask;
    while (!(gmask & 1)) {
	gmask >>= 1;
	gshift++;
    }
    bmask = header->blue_mask;
    while (!(bmask & 1)) {
	bmask >>= 1;
	bshift++;
    }
    if (in_image->depth <= 12) {
	pix = 1 << in_image->depth;
	pixels = (unsigned long *)malloc(sizeof(unsigned long) * pix);
	for (i = 0; (unsigned long)i < pix; i++)
	    pixels[i] = ~0L;
	color.flags = DoRed | DoGreen | DoBlue;
	for (y = 0; y < in_image->height; y++) {
	    for (x = 0; x < in_image->width; x++) {
		pix = XGetPixel(in_image, x, y);
		if ((color.pixel = pixels[pix]) == (unsigned long)~0L) {
		    color.red = (pix >> rshift) & rmask;
		    color.green = (pix >> gshift) & gmask;
		    color.blue = (pix >> bshift) & bmask;
		    if (ncolors) {
			color.red = colors[color.red].red;
			color.green = colors[color.green].green;
			color.blue = colors[color.blue].blue;
		    } else {
			color.red = (((unsigned long)color.red * 65535) /
				     rmask);
			color.green = (((unsigned long)color.green * 65535) /
				       gmask);
			color.blue = (((unsigned long)color.blue * 65535) /
				      bmask);
		    }
		    if (!XAllocColor(dpy, *colormap, &color)) {
			*colormap = CopyColormapAndFree(dpy, *colormap);
			XAllocColor(dpy, *colormap, &color);
		    }
		    pixels[pix] = color.pixel;
		}
		XPutPixel(out_image, x, y, color.pixel);
	    }
	}
    } else {
	pix = 1 << 12;
	pixels = (unsigned long *)malloc(sizeof(unsigned long) * pix);
	rpixels = (unsigned long *)malloc(sizeof(unsigned long) * pix);
	for (i = 0; (unsigned long)i < pix; i++) {
	    pixels[i] = ~0L;
	    rpixels[i] = ~0L;
	}
	color.flags = DoRed | DoGreen | DoBlue;
	for (y = 0; y < in_image->height; y++) {
	    for (x = 0; x < in_image->width; x++) {
		pix = XGetPixel(in_image, x, y);
		xpix = ((pix >> 12) ^ pix) & ((1 << 12) - 1);
		if (((color.pixel = pixels[xpix]) == (unsigned long)~0L) ||
		    (rpixels[xpix] != pix)) {
		    color.red = (pix >> rshift) & rmask;
		    color.green = (pix >> gshift) & gmask;
		    color.blue = (pix >> bshift) & bmask;
		    if (ncolors) {
			color.red = colors[color.red].red;
			color.green = colors[color.green].green;
			color.blue = colors[color.blue].blue;
		    } else {
			color.red = (((unsigned long)color.red * 65535) /
				     rmask);
			color.green = (((unsigned long)color.green * 65535) /
				       gmask);
			color.blue = (((unsigned long)color.blue * 65535) /
				      bmask);
		    }
		    if (!XAllocColor(dpy, *colormap, &color)) {
			*colormap = CopyColormapAndFree(dpy, *colormap);
			XAllocColor(dpy, *colormap, &color);
		    }
		    pixels[xpix] = color.pixel;
		    rpixels[xpix] = pix;
		}
		XPutPixel(out_image, x, y, color.pixel);
	    }
	}
    }
}

unsigned Image_Size(XImage *image)
{
    if (image->format != ZPixmap)
      return(image->bytes_per_line * image->height * image->depth);

    return((unsigned)image->bytes_per_line * image->height);
}

void _swapshort (register char *bp, register unsigned n)
{
    register char c;
    register char *ep = bp + n;

    while (bp < ep) {
	c = *bp;
	*bp = *(bp + 1);
	bp++;
	*bp++ = c;
    }
}

void _swaplong (register char *bp, register unsigned n)
{
    register char c;
    register char *ep = bp + n;
    register char *sp;

    while (bp < ep) {
	sp = bp + 3;
	c = *sp;
	*sp = *bp;
	*bp++ = c;
	sp = bp + 1;
	c = *sp;
	*sp = *bp;
	*bp++ = c;
	bp += 2;
    }
}
