/*********************************************************************
 *
 *         EZWGL, the EZ Widget and Graphics Library
 *
 *             Copyright (C) 1996, 1997  Maorong Zou
 *  
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **********************************************************************/
/*
 *  June 1996.  Beta Release.
 *  Sept 1996.  Release Version 1.0
 *  Dec 1996.  Release Version 1.1 Beta
 *  April 1997.  Release Version 1.2
 *  November 1997.  Release Version 1.3
 */
/*
 *  May 1997. Handling of raw rgb images added by Arno Dabekaussen.
 */
/*********************************************************************
 ***                                                               ***
 ***           Create a pixmap from an image file.                 ***
 ***                                                               ***
 *********************************************************************/
#define _EZ_WIDGET_IMAGE_C_
#include "EZ_Widget.h"
#include <ctype.h>

/*********************************************************************
 * 
 *  Functions implemented in this file:
 */
int   EZ_CreateXPixmapFromImageFile MY_ANSIARGS((char *file, unsigned int *w, unsigned int *h, 
						 Pixmap *pix));
int   EZ_CreateXPixmapFromRawRGB MY_ANSIARGS((char *data, int width, int height, Pixmap *pixmap_return));
void  EZ_RawRGBData2Pixmap MY_ANSIARGS((char *data, int w, int h, Pixmap *pix));
void  EZ_PixelValueData2Pixmap MY_ANSIARGS((unsigned int *data, int w, int h, Pixmap *pix));
/*********************************************************************
 *
 *  Local functions:
 */
static int  EZ_ReadANYToPixmap MY_ANSIARGS((char *data, int *w, int *h, Pixmap *pix));
static int  EZ_ReadPPMToPixmap MY_ANSIARGS((char *file, int *w, int *h, Pixmap *pix));
static int  EZ_ReadPPM_FP_ToPixmap MY_ANSIARGS((FILE *fp, int *w, int *h, Pixmap *pix));
static int  EZ_ReadXPMToPixmap MY_ANSIARGS((char *file, int *w, int *h, Pixmap *pix));
/********************************************************************
 *
 *  This is the list of supported image formats, well, I gave up
 *  on this, I'm really not an expert in deciphering images ...
 *
 */

typedef struct {
  char *Extension;
  int  (*ReadImageToPixmap) MY_ANSIARGS((char *file, int *w, int *h, Pixmap *pix));
} EZ_ImageFormat;


static EZ_ImageFormat EZ_SupportedImageFormats[] =
{
  {"ppm", EZ_ReadPPMToPixmap},       /* PNM/PPM/PGM Format */
  {"gif", EZ_ReadGIFToPixmap},       /* GIF Format         */
  {"xpm", EZ_ReadXPMToPixmap},       /* XPM Format         */
  {"bmp", EZ_ReadBMPToPixmap},       /* BMP Format         */
  {"jpg", EZ_ReadJpegToPixmap},      /* JPEG Format        */
  {"jpeg", EZ_ReadJpegToPixmap},     /* JPEG Format        */
  {"any", EZ_ReadANYToPixmap},       /* try !              */
};

#define UNKNOWN_IMAGE_FORMAT   -1
#define PPM_FORMAT             0
#define GIF_FORMAT             1
#define XPM_FORMAT             2
#define BMP_FORMAT             3
#define JPG_FORMAT             4
#define JPEG_FORMAT            5

#define LAST_IMAGE_FORMAT      5

/********************************************************************
 *
 *  Try to use anytopnm to convert the image into PNM format,
 *  may be we are lucky.
 */
static int  EZ_ReadANYToPixmap(file, width_return, height_return, pixmap_return)
     char     *file;                          /* image file_name         */
     int      *width_return, *height_return;  /* width and height return */
     Pixmap   *pixmap_return;                 /* pixmap return           */
{
  FILE    *fp,*popen();
  char    command[1024];
  int     ans;

  (void) sprintf(command, "anytopnm %s ",file);
  if((fp = popen(command,"r")) == (FILE *)NULL)   return(0);

  ans = EZ_ReadPPM_FP_ToPixmap(fp, width_return, height_return, pixmap_return);

  pclose(fp);
  return(ans);
}
/*************************************************************************
 *
 *   Read a XPM image into an pixmap.
 */
static int EZ_ReadXPMToPixmap(file, width_return, height_return, pixmap_return)
     char     *file;                          /* image file_name         */
     int      *width_return, *height_return;  /* width and height return */
     Pixmap   *pixmap_return;                 /* pixmap return           */
{
  return(EZ_CreateXPixmapFromXpmFile(file, width_return, height_return,
				     pixmap_return, NULL));
}
/*************************************************************************
 *
 *   Read a PPM/PGM/PBM image into an pixmap.
 */

static int EZ_ReadPPMToPixmap(file, width_return, height_return, pixmap_return)
     char     *file;                          /* image file_name         */
     int      *width_return, *height_return;  /* width and height return */
     Pixmap   *pixmap_return;                 /* pixmap return           */
{
  FILE   *fp, *fopen();
  int    ok = 0;
  
  if( (fp = fopen(file,"r")) == (FILE *)NULL)
    {
      (void) fprintf(stderr, "Cannot open image file %s\n", file);
      return(0);
    }
  ok = EZ_ReadPPM_FP_ToPixmap(fp, width_return, height_return, pixmap_return);
  (void) fclose(fp);
  return(ok);
}
/*************************************************************************
 *
 *   Read a PPM/PGM/PBM image (from a stream descriptor) into an pixmap.
 */
static int EZ_ReadPPM_FP_ToPixmap(fp, width_return, height_return, pixmap_return)
     FILE     *fp;                            /* stream descriptor       */
     int      *width_return, *height_return;  /* width and height return */
     Pixmap   *pixmap_return;                 /* pixmap return           */
{
  unsigned char *tmpdata, *tptr;
  char          tbuf[512];
  int           r,g,b,i,j, c, maxval, width,height, fmt;
  Pixmap        pixmap;

  /*----------------------------------------------------------
   * read the PPM Header
   *--------------------------------------------------------*/
  {
    c = getc(fp);
    j = 0;
    for(i = 0; i < 4; i++)
      {
	for(; ;)
	  {
	    while(c == ' ' || c == '\t' || c == '\n') c = getc(fp);
	    if(c == '#')
	      {
		while(c != '\n' && c != EOF) c = getc(fp);  /* comment */
		c = getc(fp);
	      }
	    else break;
	  }
	while(!(isspace(c)) && (c != EOF)  && j < 500)
	  {
	    tbuf[j++] = c;
	    c = getc(fp);
	  }
	tbuf[j++] = ' ';
	tbuf[j] = '\0';
      }

    fmt = -1;
    if(tbuf[0] == 'P')
      {
	if(tbuf[1] == '6')         fmt = 6;
	else if(tbuf[1] == '5')    fmt = 5;
	else if(tbuf[1] == '3')    fmt = 3;
      }
    j = sscanf(tbuf+3,"%d %d %d", &width,&height,&maxval);
    if(fmt == -1 || j != 3 || width <= 0 || height <= 0 || maxval <= 0 || maxval > 255)
      return(0);
  }
  /*-----------------------------------------------------------
   *  PBM/PPM/PGM header is sucessfully read.
   *----------------------------------------------------------*/
  if( (tmpdata = (unsigned char *)my_malloc(4 * (width)*(height) *
					 sizeof(unsigned char),_PPM_TMP_D_)) == (unsigned char *)NULL)
    {
      EZ_OutOfMemory("EZ_ReadPPM_FP_ToPixmap");
      return(0);  
}
  /*---------------------------------------
   * Now read in image data
   *--------------------------------------*/
  if(fmt == 6)  /* PPM */
    {
      int length = width*height*3;

      tptr = tmpdata;
      (void) fread(tptr,1,length,fp);
      if(maxval != 255)
	{
	  tptr = tmpdata;
	  for(i = 0; i < length; i++)
	    {
	      j  = (int)(*tptr)*255/maxval;
	      *tptr = (unsigned char)j;
	      tptr++;
	    }
	}
    }
  else if(fmt == 5)  /* PGM */
    {
      int length = width*height;
      unsigned char uc, *ucptr;

      tptr = tmpdata + 3*length;
      (void) fread(tptr,1,length,fp);
      if(maxval != 255)
	{
	  tptr = tmpdata + 3*length;
	  ucptr = tmpdata;
	  for(i = 0; i < length; i++)
	    {
	      j  = (int)(*tptr)*255/maxval;
	      tptr++;
	      *ucptr++ = (unsigned char)j;
	      *ucptr++ = (unsigned char)j;
	      *ucptr++ = (unsigned char)j;
	    }
	}
      else
	{
	  tptr = tmpdata + 3*length;
	  ucptr = tmpdata;
	  
	  for(i = 0; i < length; i++)
	    {
	      uc = *tptr++;
	      *ucptr++ = uc;
	      *ucptr++ = uc;
	      *ucptr++ = uc;
	    }
	}
    }
  else if(fmt == 3)     /* PPM/ASCII */
    {
      tptr = tmpdata;
      for(i = 0; i < height; i++)
	{
	  for(j = 0; j < width; j++)
	    {
	      fscanf(fp,"%d", &r);
	      fscanf(fp,"%d", &g);
	      fscanf(fp,"%d", &b);
	      if( maxval != 255)
		{
		  r = r*255/maxval;
		  g = r*255/maxval;
		  b = r*255/maxval;
		}
	      *tptr++ = (unsigned char) r;
	      *tptr++ = (unsigned char) g;
	      *tptr++ = (unsigned char) b;
	    }
	}
    }
  /*-------------------------------------------------------------
   * Image is in tmpdata, now dither and render it into a pixmap
   *------------------------------------------------------------*/
  EZ_RawRGBData2Pixmap(tmpdata,width,height, &pixmap);
  (void)my_free( (char *)tmpdata);
  if(pixmap != (Pixmap )NULL && width > 0 && height > 0)
    {
      *width_return = width;
      *height_return = height;
      *pixmap_return = pixmap;
      return(1);
    }
  else
    return(0);
}

/**IF*********************   Internal Function   **************************

    int EZ_CreateXPixmapFromRawRGB(data, width, height, pixmap_return)

Purpose: Create an Xpixmap from raw rgb data.

Returns: 1 if successful, 0 if not.

Author : Arno Dabekaussen, 04-05-97 Maastricht, NL

***/

int EZ_CreateXPixmapFromRawRGB(data, width, height, pixmap_return)
     char     *data;
     int      width, height;
     Pixmap   *pixmap_return;     
{
    Pixmap    pixmap;


    /*-------------------------------------------------------------
     * Image is in rgbdata, now dither and render it into a pixmap
     *------------------------------------------------------------*/

    EZ_RawRGBData2Pixmap(data, width, height, &pixmap);

 
    if (pixmap != (Pixmap ) NULL)
      {
	*pixmap_return = pixmap;
	return(1);  
      }
    else
      {
	return(0); 
      }

}


/*********************************************************************
 *
 *  Given a RGB array repsenting an image of width X height,
 *  create a pixmap form of the image using the current color setup.
 */

void  EZ_RawRGBData2Pixmap(sdata, width,height,pixmap_return)
     char *sdata;                   /* raw RGB data, one byte for each primary component */
     int           width, height;   /* dimension.  data is of length width * height * 3  */
     Pixmap        *pixmap_return;  /* place to return the created pixmap                */
{
  XImage *image;
  int    bytes_per_line, i,j;
  Pixmap pixmap;
  unsigned char *data = (unsigned char *)sdata;

  /*----------------------------------------------
   * Create an XImage structure, render image
   * to this XImage.
   *---------------------------------------------*/
  image = XCreateImage(EZ_Display,
		       EZ_Visual,
		       EZ_Depth,
		       ZPixmap,
		       0,
		       (char *)NULL,
		       width,
		       height,
		       (EZ_Depth > 16)? 32 : ((EZ_Depth > 8)? 16 : 8),
		       0);
  if(image == (XImage *)NULL)
    {
      *pixmap_return = (Pixmap )NULL;
      EZ_OutOfMemory("EZ_RawRGBData2Pixmap");
      return;
    }
  bytes_per_line = image->bytes_per_line;

  image->data = (char *)my_malloc(bytes_per_line * height, _PPM_TMP_IMAGE_D_);
  if(image->data == (char *)NULL)
    {
      *pixmap_return = (Pixmap )NULL;
      XDestroyImage(image);
      EZ_OutOfMemory("EZ_RawRGBData2Pixmap");
      return;
    }

  /*-------------------------------------------------------
   * Now render the image
   *-----------------------------------------------------*/
  if(EZ_Depth <= 8)
    {
      {
	/*------------------------------------------------
	 * We are on a 8bit display, which means we cannot
	 * allocate enough exact colors most of the time. 
	 * So we dither the image. 
	 * We use the Floyd-Steinberg error diffusion 
	 * algorithm, it produces images better than our
	 * 3D canvas dithering algorithm.
	 *-----------------------------------------------*/
	unsigned char *pixel, *dptr;
	char          *row = image->data;
	int            *errorstorage, *err, *rerr1, *rerr2, *gerr1,*gerr2,*berr1,*berr2;
	int            r,g,b, ir,ig,ib, index, rerror,gerror,berror,hstep;
	int            r1,g1,b1,mmaaxx;
	XColor         *xc;

	errorstorage = (int *)my_malloc( 6 * (width + 3 ) * sizeof(int), _DITHER_TMP_D_);
	if(errorstorage == (int *)NULL)
	  {
	    *pixmap_return = (Pixmap )NULL;
	    XDestroyImage(image);
	    EZ_OutOfMemory("EZ_RawRGBData2Pixmap");
	    return;
	  }
	err = errorstorage;                /* initialize error terms    */
	memset(err, 0, 6*(width+3)*sizeof(int));

	/*-------------------------------------------
	 * storage for errors for R G B components.
	 *-------------------------------------------*/
	i = width + 3;
	rerr1 = errorstorage + 2;         /* current row  */
	rerr2 = errorstorage + i + 2;     /* next row     */
	gerr1 = errorstorage + 2*i + 2;
	gerr2 = errorstorage + 3*i + 2;
	berr1 = errorstorage + 4*i + 2;
	berr2 = errorstorage + 5*i + 2;

	/*-----------------------------------------
	 * Create the dithering map. We need a way
	 * to check when we have to do this !!
	 *----------------------------------------*/
	EZ_CreateDitheringMap();
	mmaaxx = DitherIntensityLevels[255]; 

	/*-----------------------------------------
	 * Half step between consecutive levels in
	 * the dithering map.
	 *----------------------------------------*/
	if(EZ_TotalNumOfColors > 232)        hstep = 25;
	else if(EZ_TotalNumOfColors > 141)   hstep = 31;
	else if(EZ_TotalNumOfColors > 80)    hstep = 42;
	else if(EZ_TotalNumOfColors > 43)    hstep = 63;
	else                                 hstep = 126; 
	/*-------------------------------------------
	 * Now dither the image.
	 *-------------------------------------------*/
	for(i = 0; i <= height; i++) 
	  {
	    if(i == height) 
	      {
		data = (unsigned char *)sdata;
		row = (unsigned char *)(image->data);
		pixel = (unsigned char *)row;
	      }
	    else pixel = (unsigned char *)row;
	    dptr = data;
	    for(j = 0; j <= width; j++)
	      {
		if(j < width) { r1 = (int)(*data++); g1 = (int)(*data++); b1 = (int)(*data++);}
		else { r1 = (int)(*dptr++);  g1 = (int)(*dptr++);  b1 = (int)(*dptr++);}

		r = r1 + rerr1[j]/16; g = g1 + gerr1[j]/16;  b = b1 + berr1[j]/16;
		
		r = (r < 0? 0: (r > 255 ? 255: r));
		g = (g < 0? 0: (g > 255 ? 255: g));
		b = (b < 0? 0: (b > 255 ? 255: b));

		ir = DitherIntensityLevels[r]; 
		ig = DitherIntensityLevels[g];
		ib = DitherIntensityLevels[b];
		if(r - ir > hstep && ir < mmaaxx) ir++;
		if(g - ig > hstep && ig < mmaaxx) ig++;
		if(b - ib > hstep && ib < mmaaxx) ib++;

		/*----------------------------------------------
		 * Approximate color for this pixel 
		 *---------------------------------------------*/
		index = 16 + ir + DitherIndexTable[ig + DitherIndexTable[ib]];
		
		if(j < width) *pixel++ = (unsigned char) (EZ_ColorArray[index]);
		else row[0] = (unsigned char) (EZ_ColorArray[index]);
		
		/*-----------
		 * errors
		 *-----------*/
		xc = &(EZ_XColorArray[index]);
		rerror = r - (int)((xc->red) >> 8);
		gerror = g - (int)((xc->green)>> 8);
		berror = b - (int)((xc->blue) >> 8);
		
		/*-----------------------------------------
		 * done with this pixel, zero the errors 
		 *----------------------------------------*/
		rerr1[j] = 0; 	gerr1[j] = 0; 	berr1[j] = 0;

		/*-----------------------------
		 * diffuse the current errors 
		 *----------------------------*/
		rerr1[j+1] += 7 * rerror;
		rerr2[j] += 5 * rerror;
		rerr2[j+1] += rerror;
		gerr1[j+1] += 7 * gerror; 
		gerr2[j] += 5 * gerror;
		gerr2[j+1] += gerror;
		berr1[j+1] += 7 * berror;
		berr2[j] += 5 * berror;
		berr2[j+1] += berror;
		if(j != 0)
		  {
		    rerr2[j-1] += 3 * rerror;
		    gerr2[j-1] += 3 * gerror; 
		    berr2[j-1] += 3 * berror;
		  }
		else
		  {
		    rerr2[width] += 3 * rerror;
		    gerr2[width] += 3 * gerror; 
		    berr2[width] += 3 * berror;
		  }
	      }
	    row += bytes_per_line;  /* advance to the next row */
	    /*-----------------------------------
	     * swamp the error pointers
	     *----------------------------------*/
	    err = rerr1; rerr1 = rerr2; rerr2 = err;
	    err = gerr1; gerr1 = gerr2; gerr2 = err;
	    err = berr1; berr1 = berr2; berr2 = err; 
	  }
	/*-------------------------------------------------------
	 * finish dithering, create an image and copy the image
	 * into the pixmap
	 *------------------------------------------------------*/
	pixmap = XCreatePixmap(EZ_Display,
			       EZ_DummyWindow,
			       width,
			       height,
			       EZ_Depth);
	if(pixmap != (Pixmap )NULL)
	  XPutImage(EZ_Display,pixmap, EZ_WRITABLEGC,image,0,0,0,0,width,height);
	else
	  (void)fprintf(stderr, "Out of memory\n");

	(void)my_free( (char *)image->data); 
	(void)my_free( (char *)errorstorage);
	image->data = (char *)NULL;
	XDestroyImage(image);
	*pixmap_return = pixmap;
	return;
      }
    }
  else if(EZ_Depth <= 16)
    {
      {
	/*--------------------------------------
	 * we are on a 16 bit TrueColor visual 
	 *--------------------------------------*/
	char           *row;
	unsigned short *pixel;
	int             r,g,b;

	row = image->data;
	for(i = 0; i < height; i++)
	  {
	    pixel = (unsigned short *)row;
	    for(j = 0; j < width; j++)
	      {
		r = (int)(*data++);
		g = (int)(*data++);
		b = (int)(*data++);
		*pixel++ = (unsigned short)RGB2PixelLookUp_Fix(r, g, b);
	      }
	    row += bytes_per_line;
	  }
	pixmap = XCreatePixmap(EZ_Display,
			       EZ_DummyWindow,
			       width,
			       height,
			       EZ_Depth);
	if(pixmap != (Pixmap )NULL)
	  XPutImage(EZ_Display,pixmap, EZ_WRITABLEGC,image,0,0,0,0,width,height);
	else
	  (void)fprintf(stderr, "Out of memory\n");

	(void)my_free( (char *)image->data); 
	image->data = (char *)NULL;
	XDestroyImage(image);
	*pixmap_return = pixmap;
	return;
      }
    }
  else if(EZ_Depth >= 24 && EZ_BitsPerPixel == 32)
    {
      {
	/*--------------------------------------
	 * we are on a 24 bit TrueColor visual 
	 *--------------------------------------*/
	char           *row;
	unsigned int   *pixel;
	int             r,g,b;

	row = image->data;
	for(i = 0; i < height; i++)
	  {
	    pixel = (unsigned int *)row;
	    for(j = 0; j < width; j++)
	      {
		r = (int)(*data++);
		g = (int)(*data++);
		b = (int)(*data++);
		*pixel++ = (unsigned int)RGB2PixelLookUp_Fix(r, g, b);
	      }
	    row += bytes_per_line;
	  }
	pixmap = XCreatePixmap(EZ_Display,
			       EZ_DummyWindow,
			       width,
			       height,
			       EZ_Depth);
	if(pixmap != (Pixmap )NULL)
	  XPutImage(EZ_Display,pixmap, EZ_WRITABLEGC,image,0,0,0,0,width,height);
	else
	  (void)fprintf(stderr, "Out of memory\n");

	(void)my_free( (char *)image->data); 
	image->data = (char *)NULL;
	XDestroyImage(image);
	*pixmap_return = pixmap;
	return;
      }
    }
  else if(EZ_Depth >= 24 && EZ_BitsPerPixel == 24)
    {
      {
	/*--------------------------------------
	 * we are on a 24 bit TrueColor visual 
	 *--------------------------------------*/
	unsigned char   *row, *ddd;
	unsigned char   *pixel;
	int             r,g,b, bpl;
	unsigned long   pv;
	unsigned char   *pv4 = (unsigned char *)&pv;

	ddd = (unsigned char *)(image->data);
	bpl = bytes_per_line;
	for(row = ddd, i = 0; i < height; i++, row += bpl)
	  {
	    for(pixel=row, j = 0; j < width; j++)
	      {
		r = (int)(*data++);
		g = (int)(*data++);
		b = (int)(*data++);
		pv = RGB2PixelLookUp_Fix(r, g, b);
		*pixel++ = pv4[0];
		*pixel++ = pv4[1];
		*pixel++ = pv4[2];
	      }
	  }
	pixmap = XCreatePixmap(EZ_Display,
			       EZ_DummyWindow,
			       width,
			       height,
			       EZ_Depth);
	if(pixmap != (Pixmap )NULL)
	  XPutImage(EZ_Display,pixmap, EZ_WRITABLEGC,image,0,0,0,0,width,height);
	else
	  (void)fprintf(stderr, "Out of memory\n");

	(void)my_free( (char *)image->data); 
	image->data = (char *)NULL;
	XDestroyImage(image);
	*pixmap_return = pixmap;
	return;
      }
    }
  else if(EZ_Depth >= 8)
    {
      {
	unsigned long  pixel;
	int             r,g,b;

	for(i = 0; i < height; i++)
	  {
	    for(j = 0; j < width; j++)
	      {
		r = (int)(*data++);
		g = (int)(*data++);
		b = (int)(*data++);
		pixel = (unsigned int)RGB2PixelLookUp(r, g, b);
		XPutPixel(image, j, i, pixel);
	      }
	    
	  }
	pixmap = XCreatePixmap(EZ_Display,
			       EZ_DummyWindow,
			       width,
			       height,
			       EZ_Depth);
	if(pixmap != (Pixmap )NULL)
	  XPutImage(EZ_Display,pixmap, EZ_WRITABLEGC,image,0,0,0,0,width,height);
	else
	  (void)fprintf(stderr, "Out of memory\n");

	(void)my_free( (char *)image->data); 
	image->data = (char *)NULL;
	XDestroyImage(image);
	*pixmap_return = pixmap;
	return;
      }
    }
  else
    {
      (void)fprintf(stderr, "Unkown visual depth.\n");
      *pixmap_return = (Pixmap )NULL;
      return;
    }
}
/********************************************************************/
void  EZ_PixelValueData2Pixmap(data, width, height, pixmap_return)
     unsigned int *data;           /* pixel values */
     int           width, height;   /* dimension.  */
     Pixmap        *pixmap_return;  /* place to return the created pixmap */
{
  XImage *image;
  int    bytes_per_line, i,j, k;
  Pixmap pixmap;
  
  /*----------------------------------------------
   * Create an XImage structure, render image
   * to this XImage.
   *---------------------------------------------*/
  image = XCreateImage(EZ_Display,
		       EZ_Visual,
		       EZ_Depth,
		       ZPixmap,
		       0,
		       (char *)NULL,
		       width,
		       height,
		       (EZ_Depth > 16)? 32 : ((EZ_Depth > 8)? 16 : 8),
		       0);
  if(image == (XImage *)NULL)
    {
      (void)fprintf(stderr, "Out of memory!\n");
      *pixmap_return = (Pixmap )NULL;
      return;
    }
  bytes_per_line = image->bytes_per_line;

  image->data = (char *)my_malloc(bytes_per_line * height, _PPM_TMP_IMAGE_D_);
  if(image->data == (char *)NULL)
    {
      *pixmap_return = (Pixmap )NULL;
      XDestroyImage(image);
      EZ_OutOfMemory("EZ_RawRGBData2Pixmap");
      return;
    }

  /* write to image */
  k = 0;
  for(i = 0; i < height; i++)
    {
      for(j = 0; j < width; j++)
	XPutPixel(image, j, i, (unsigned long) (data[k +j]));
      k += width;
    }
  /* write to pixmap */
  pixmap = XCreatePixmap(EZ_Display,
			 EZ_DummyWindow,
			 width,
			 height,
			 EZ_Depth);
  if(pixmap != (Pixmap )NULL)
    XPutImage(EZ_Display,pixmap, EZ_WRITABLEGC,image,0,0,0,0,width,height);
  else
    (void)fprintf(stderr, "Out of memory\n");

  (void)my_free( (char *)image->data); 
  image->data = (char *)NULL;
  XDestroyImage(image);
  *pixmap_return = pixmap;
  return;
}
/********************************************************************
 *
 *  Create a pixmap from a given image.
 *
 *   Return 1 if successful, 0 if not.
 *
 ********************************************************************/

int EZ_CreateXPixmapFromImageFile(file, width_return, height_return, pixmap_return)
     char     *file;
     unsigned int      *width_return, *height_return;
     Pixmap   *pixmap_return;     
{
  char    *tmp;
  int     i, j, length, fmt = -1;
  Pixmap  pixmap;
  int     width, height;

  /*------------------------------------------------------
   * need to figure out the file format. We do this in 
   * two steps. 
   *   1. Check for file extension. If a match is found,
   *      read it.
   *   2. If no matching extension found, loop through
   *      all supported formats and try to read it.
   *----------------------------------------------------*/

  pixmap = (Pixmap )NULL;
  width = 0;
  height = 0;

  /*-----------------------------------------------------
   * look for file extension and try to read it.
   *----------------------------------------------------*/
  tmp    = file; 
  length = strlen(tmp);
  tmp    = file + length -1;

  for(i = length-1; i>= 0; i--, tmp--)
    if(*tmp == '.') break;
  if(i != 0 && i < length -1)
    {
      for(j = 0; j < LAST_IMAGE_FORMAT; j++)
	{
	  if(!strcmp((tmp+1),EZ_SupportedImageFormats[j].Extension))
	    {
	      fmt = j;   /* so we recognize the image format, read it */
	      if((EZ_SupportedImageFormats[j].ReadImageToPixmap)(file,&width,&height,&pixmap) == 0)
		(void)fprintf(stderr,"Warning: Error reading image file '%s'\n",file);
	      break;
	    }
	}
    }

  if(fmt == -1)
    {
      /*-------------------------------------------------------
       * no file extension match found or extension doesn't
       * make sense. Loop through all supported formats to
       * see if we can read it.
       *-----------------------------------------------------*/
      for(j = 0; j <= LAST_IMAGE_FORMAT; j++)
	{
	  if((EZ_SupportedImageFormats[j].ReadImageToPixmap)(file,&width,&height,&pixmap) != 0)
	    {
	      fmt = j;
	      break;
	    }
	}
    }
  if(fmt == -1) /* we don't know the image format, give up */
    (void)fprintf(stderr, "Sorry, I don't recognize the image format in %s\n", file);

  /*---------------------------------------------------------
   *  Set the return values
   *--------------------------------------------------------*/
  if(pixmap != (Pixmap )NULL && width > 0 && height > 0)
    {
      *width_return = width;
      *height_return = height;
      *pixmap_return = pixmap;
      return(1);
    }
  else
    return(0);
}
/**********************************************************************************************/

#undef _EZ_WIDGET_IMAGE_C_

