/*********************************************************************
 *
 *         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
 */
/*
 * Contributed by   Arno Dabekaussen <piemail!arnodab@relay.NL.net>
 */
/*********************************************************************
 ***                                                               ***
 ***           Create a pixmap from .bmp file.                     ***
 ***                                                               ***
 *********************************************************************/
#define _EZ_BMP_C_
#include "EZ_Widget.h"
#include <ctype.h>

/*********************************************************************
 * 
 *  Functions implemented in this file:
 */
int EZ_ReadBMPToPixmap MY_ANSIARGS((char *filename, int *width_return, int *height_return,
				    Pixmap *pixmap_return));

/*********************************************************************
 * 
 *  Local Functions
 */
static int EZ_ReadBMP_FP_ToPixmap MY_ANSIARGS((FILE *fp, char *filename, int *width_return, 
					       int *height_return, Pixmap *pixmap_return));
static long BigEndian MY_ANSIARGS((void));

/*
 * some macros for swapping longs and shorts from
 * little endian to big endian and vice versa
 */

#define SWAP(a, b)      { char temp; \
			  temp = a;  \
			  a = b;     \
			  b = temp;  \
		  }

#define SWAPLONG(val)	{ char *help = (char *)&val;\
			  SWAP(help[3], help[0]);   \
			  SWAP(help[1], help[2]);   \
		        }

#define SWAPSHORT(a) {    char *help = (char *)&a;\
			  SWAP(help[0], help[1]); \
                     }


/*
 * file header structure
 */
struct bmp_file_header
{
	char            bfType[2];	/* file ID must be 'BM'  */
	long            bfSize;		/* filelength in bytes 	 */
	short           reserved;	/* must be set to 0    	 */
	short           reserved2;	/* either 		 */
	long            bfOffs;		/* offset to data area 	 */
};
typedef struct bmp_file_header bmp_file_header_t;

/*
 * look up table entry
 */
struct rgb_quad
{
	char            blue;
	char            green;
	char            red;
	char            reserved;
};
typedef struct rgb_quad rgb_quad_t;

/*
 * brief information of the image file
 */
struct bmp_info_header
{
	long            biSize;	      /* bmp_info_header length      	    */
	long            biWidth;      /* width of bitmap in pixels   	    */
	long            biHeight;     /* height of bitmap in pixels  	    */
	short           biPlanes;     /* number of planes, must be set to 1 */
	short           biBitCnt;     /* bits per pixel		            */
	long            biCompr;      /* type of compression		    */
	long            biSizeIm;     /* size of (compressed) image	    */
	long            biXPelsPerM;  /* X pixels per meter	            */
	long            biYPelsPerM;  /* Y pixels per meter	            */
	long            biClrUsed;    /* no. of used colors	            */
	long            biClrImp;     /* no. of important colors            */
	rgb_quad_t     *lut;	      /* lookup table		            */
};
typedef struct bmp_info_header bmp_info_header_t;

/*
 * Compression types
 */
#define BI_RGB	0
#define BI_RLE8	1
#define BI_RLE4	2

/*
 * header size on disk, not that this isn't necessarily the size of
 * the bmp_info_header structure in memory, due to the fact, that
 * intel chips may store longs at misaligned addresses, where other
 * cpu's like 68k, sparc, PowerPC store longs at addresses divisible
 * by 4 (32 bit addresses)!
 */
#define BMP_HEADER_OFFSET 0x36

/*
 * return codes
 */
#define BMP_NO_ERROR		 1
#define BMP_FILE_OPEN_FAILED	 0
#define BMP_FILE_HEADER_CORRUPT	 0
#define BMP_INFO_HEADER_CORRUPT	 0
#define BMP_LOW_MEMORY		 0	/* malloc failed */
#define BMP_LUT_CORRUPT		 0
#define BMP_IMAGE_DATA_CORRUPT	 0
#define BMP_NO_BMP		 0
#define BMP_COMPRESSED		 0
#define BMP_ERROR                0 

/*************************************************************************
 *
 *   Read a MicroSoft BMP image into an pixmap.
 */

int EZ_ReadBMPToPixmap(filename, width_return, height_return, 
		       pixmap_return)
     char     *filename;                      /* image file_name         */
     int      *width_return, *height_return;  /* width and height return */
     Pixmap   *pixmap_return;                 /* pixmap return           */
{
  FILE   *fp, *fopen();
  int    ok = 0;
  char   *fname = "EZ_ReadBMPToPixmap";
  
  if( (fp = fopen(filename,"rb")) == (FILE *) NULL)
  {
      (void) fprintf(stderr, "Cannot open image file %s\n", filename);
      return(0);
  }

  ok = EZ_ReadBMP_FP_ToPixmap(fp, filename, width_return, height_return, 
			      pixmap_return);

  if (fclose(fp) != 0) 
  {  
    fprintf(stderr, "%s: can't close %s\n", fname, filename); 
    exit(EZ_EXIT_ERROR);
  }
  return(ok);
}

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

    static long BigEndian(void)

Return  : long
Purpose : Detects a big or little endian machine.

Notes   : 

***/

static long BigEndian(void)
{
  long            testval = 0x12345678;
  char           *bytep = (char *) &testval;

  return (long) (bytep[0] == (char) 0x12);
}

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

    static int EZ_ReadBMP_FP_ToPixmap(fp, width_return, height_return, 
				      pixmap_return)

Purpose: Read a MicroSoft BMP image (from a stream descriptor) into an pixmap.

         This funtion reads an image in BMP format and stores it into a 
	 given data area. If the look up table pointer is NULL then 
	 workspace for the look up table will be allocated. 
	 Otherwise, look up table data is written to the specified 
	 address (e.g. the look up table ram of a graphic controller
	 If the data pointer is NULL then th function allocates memory 
	 for the image and after the function returns data contains 
	 the address of the image memory start address
 
Parameter:  char *filename		 the name of the image to be 
                                         loaded 
 	    bmp_info_header_t *imageinfo a pointer to an image info
                                         structure to receive
 					 relevant image data after
                                         loading
 	    char **data			 the address of a pointer to 
                                         the data area where
 					 the image should be loaded to

Returns:    BMP_NO_ERROR		 image was loaded correctly
 	    BMP_FILE_OPEN_FAILED	 if the image file couldn't be opened
            BMP_NO_BMP		         if the file that was opened wasn't 
                                         a BMP file
  	    BMP_COMPRESSED		 if the image file was in compressed 
                                         format (not supported)
 	    BMP_LOW_MEMORY		 if memory allocation for the look up 
                                         table or image memory failed
 	    BMP_LUT_CORRUPT		 if the reading of the look up table 
                                         failed
 	    BMP_IMAGE_DATA_CORRUPT       if the image data couldn't be read 

Notes:	    This version expects a consequtive allocated image memory, or
            allocates a consequtive image memory internally.

History:    23-03-95     If columns = 555 then bytesperline is rounded to 558,
                         and thus overflow.
	    07-11-95	 LUT values need not to be swapped on bigendian
	                 machines, because they are written character based.

***/

static int EZ_ReadBMP_FP_ToPixmap(fp, filename, width_return, height_return, 
				  pixmap_return)
     FILE     *fp;                            /* stream descriptor       */
     char     *filename;
     int      *width_return, *height_return;  /* width and height return */
     Pixmap   *pixmap_return;                 /* pixmap return           */
{
  unsigned char         *tmpdata, *rgbdata;
  Pixmap                pixmap;
  bmp_info_header_t     imageinfo;
  bmp_file_header_t 	fheader;
  char	       		pad[4] = { (char) 0x00, (char) 0x00, 
				   (char) 0x00, (char) 0x00 };
  int			padbytes=0, c;
  long            	i, j, k, l, m, n;
  long            	lutentries = 0, bytesperline=0;
  long                  bytesperimageline=0, datasize;
  long            	result;
  char           	*linebuffer = NULL;
  char		        *fname = "EZ_ReadBMP_FP_ToPixmap";

  /*
   * read file header, due to the suckin' Intel address misalignment we
   * need to read each structure element sperately
   */
	
  if (fread(&fheader.bfType, sizeof(fheader.bfType), 1, fp) != 1)
  {
      fprintf(stderr,"%s: ERROR: reading fheader.bfType in %s\n", 
	      fname, filename);

      return BMP_FILE_HEADER_CORRUPT;
 
  }

  if (fread(&fheader.bfSize, sizeof(fheader.bfSize), 1, fp) != 1)
  {
      fprintf(stderr,"%s: ERROR: reading fheader.bfOffs in %s\n", 
	      fname, filename);

      return BMP_FILE_HEADER_CORRUPT;
 
  }


  if (fread(&fheader.reserved, sizeof(fheader.reserved), 2, fp) != 2)
  {
      fprintf(stderr,"%s: ERROR: reading fheader.bfOffs in %s\n", 
	      fname, filename);

      return BMP_FILE_HEADER_CORRUPT;
 
  }
	
  if (fread(&fheader.bfOffs, sizeof(fheader.bfOffs), 1, fp) != 1)
  {
      fprintf(stderr,"%s: ERROR: reading fheader.bfOffs in %s\n", 
	      fname, filename);

      return BMP_FILE_HEADER_CORRUPT;
 
  }

	
  if (BigEndian())
  {
      SWAPLONG(fheader.bfSize);
      SWAPLONG(fheader.bfOffs);
  }


  if (fheader.bfType[0] != 'B' || fheader.bfType[1] != 'M')
  {
      fprintf(stderr, "%s: Not a BMP file\n", fname);

      return BMP_NO_BMP;
  }

  /*
   * read bmp info header
   */
  if (fread(&imageinfo.biSize, sizeof(imageinfo.biSize), 1, fp) != 1)
  {
      fprintf(stderr,"%s: ERROR: reading imageinfo.biSize "
	      "in %s\n", fname, filename);

      return BMP_INFO_HEADER_CORRUPT;
  }

  if (fread(&imageinfo.biWidth, sizeof(imageinfo.biWidth), 1, fp) != 1)
  {
      fprintf(stderr,"%s: ERROR: reading imageinfo.biWidth "
	      "in %s\n", fname, filename);

      return BMP_INFO_HEADER_CORRUPT;
  }
	
  if (fread(&imageinfo.biHeight, sizeof(imageinfo.biHeight), 1, 
	    fp) != 1)
  {
      fprintf(stderr,"%s: ERROR: reading imageinfo.biHeight "
	      "in %s\n", fname, filename);

      return BMP_INFO_HEADER_CORRUPT;
  }

  if (fread(&imageinfo.biPlanes, sizeof(imageinfo.biPlanes), 1, 
	    fp) != 1)
  {
      fprintf(stderr,"%s: ERROR: reading imageinfo.biPlanes "
	      "in %s\n", fname, filename);

      return BMP_INFO_HEADER_CORRUPT;
  }

  if (fread(&imageinfo.biBitCnt, sizeof(imageinfo.biBitCnt), 1, 
	    fp) != 1)
  {
      fprintf(stderr,"%s: ERROR: reading imageinfo.biBitCnt "
	      "in %s\n", fname, filename);

      return BMP_INFO_HEADER_CORRUPT;
  }

  if (fread(&imageinfo.biCompr, sizeof(imageinfo.biCompr), 1, 
	    fp) != 1)
  {
      fprintf(stderr,"%s: ERROR: reading imageinfo.biCompr "
	      "in %s\n", fname, filename);

      return BMP_INFO_HEADER_CORRUPT;
  }

  if (fread(&imageinfo.biSizeIm, sizeof(imageinfo.biSizeIm), 1, 
	    fp) != 1)
  {
      fprintf(stderr,"%s: ERROR: reading imageinfo.biSizeIm "
	      "in %s\n", fname, filename);

      return BMP_INFO_HEADER_CORRUPT;
  }

  if (fread(&imageinfo.biXPelsPerM, sizeof(imageinfo.biXPelsPerM), 
	    1, fp) != 1)
  {
      fprintf(stderr,"%s: ERROR: reading imageinfo.biXPelsPerM "
	      "in %s\n", fname, filename);

      return BMP_INFO_HEADER_CORRUPT;
  }

  if (fread(&imageinfo.biYPelsPerM, sizeof(imageinfo.biYPelsPerM), 
	    1, fp) != 1)
  {
      fprintf(stderr,"%s: ERROR: reading imageinfo.biYPelsPerM "
	      "in %s\n", fname, filename);

      return BMP_INFO_HEADER_CORRUPT;
  }

  if (fread(&imageinfo.biClrUsed, sizeof(imageinfo.biClrUsed), 1, 
		  fp) != 1)
  {
      fprintf(stderr,"%s: ERROR: reading imageinfo.biClrUsed in %s\n", 
	      fname, filename);

      return BMP_INFO_HEADER_CORRUPT;
  }

  if (fread(&imageinfo.biClrImp, sizeof(imageinfo.biClrImp), 1, 
	    fp) != 1)
  {
      fprintf(stderr,"%s: ERROR: reading imageinfo.biClrImp in %s\n", 
	      fname, filename);

      return BMP_INFO_HEADER_CORRUPT;
  }

  if (BigEndian())
  {
      SWAPLONG(imageinfo.biSize);
      SWAPLONG(imageinfo.biWidth);
      SWAPLONG(imageinfo.biHeight);
      SWAPSHORT(imageinfo.biPlanes);
      SWAPSHORT(imageinfo.biBitCnt);
      SWAPLONG(imageinfo.biCompr);
      SWAPLONG(imageinfo.biSizeIm);
      SWAPLONG(imageinfo.biXPelsPerM);
      SWAPLONG(imageinfo.biYPelsPerM);
      SWAPLONG(imageinfo.biClrUsed);
      SWAPLONG(imageinfo.biClrImp);
  }


  if (imageinfo.biCompr != BI_RGB)
  {
      fprintf(stderr, "Unable to load compressed images, not supported!\n");

      return BMP_COMPRESSED;
  }


  /*
   * generate look up table
   */

  if (imageinfo.biBitCnt != 24)
  {
      lutentries = (imageinfo.biClrUsed) 
	           ? imageinfo.biClrUsed : (1L << imageinfo.biBitCnt);
  }


  if (lutentries > 0)
  {

      if ((imageinfo.lut = malloc((size_t) lutentries 
				  * sizeof(rgb_quad_t))) == NULL)
      {
	  fprintf(stderr, "%s: Unable to allocate look up table memory\n", 
		  fname);

	  return BMP_LOW_MEMORY;
      }

      result = (long) fread(imageinfo.lut, sizeof(rgb_quad_t), 
			    (size_t) lutentries, fp);
      if (result != lutentries)
      {
	  fprintf(stderr, "%s: can't read look up table\n", fname);

	  return BMP_LUT_CORRUPT;
      }
  }

  /*
   * read image data, a line must be divisible by 4.
   *
   * This was buggy because bytesperline can get larger then the actual
   * line length:
   *
   *    bytesperline = (bytesperimageline = imageinfo.biWidth) 
   *       + (imageinfo.biWidth % 4); 
   *
   * A. Dabekaussen, Maastricht, 23-03-95
   *
   */
  switch (imageinfo.biBitCnt)
  {
      case 1:
	  bytesperline = (bytesperimageline = imageinfo.biWidth) / 8; 
	  padbytes = ( ((imageinfo.biWidth / 8) % 4) ?
		       (4 - ((imageinfo.biWidth / 8) % 4)) : 0);
	  break;
      case 4:
	  bytesperline = (bytesperimageline = imageinfo.biWidth) / 2; 
	  padbytes = ( ((imageinfo.biWidth / 2) % 4) ?
		       (4 - ((imageinfo.biWidth / 2) % 4)) : 0);
	  break;
      case 8:
	  bytesperline = (bytesperimageline = imageinfo.biWidth); 
	  padbytes = ((imageinfo.biWidth % 4) ? 
		      (4 - (imageinfo.biWidth % 4)) : 0);
	  break;
      case 24:
	  bytesperline = (bytesperimageline = imageinfo.biWidth) * 3; 
	  padbytes = ( ((imageinfo.biWidth * 3) % 4) ?
		       (4 - ((imageinfo.biWidth * 3) % 4)) : 0);
	  break;
      default:
	  fprintf(stderr,"%s: ERROR: imageinfo.biBitCnt invalid "
		  "in %s\n", fname, filename);

	  return BMP_INFO_HEADER_CORRUPT;
  }

  /*
   * calculate the amount of memory to be reserved for image
   * data 24 bit images need 3 bytes all other images need 
   * bytesperimageline for one line.
   */

  if(imageinfo.biBitCnt == 24)
  {
      datasize = imageinfo.biHeight * 3 * (bytesperimageline + padbytes);
  }
  else
  {
      datasize = imageinfo.biHeight * (bytesperimageline + padbytes);
  }


  if ((tmpdata = malloc((size_t) datasize)) == NULL)
  {
      fprintf(stderr, "%s: Unable to allocate %ld bytes of image memory \n", 
	      fname, datasize);

      return BMP_LOW_MEMORY;
  }


  /*
   * images are stored with the last line first
   */

  tmpdata += (imageinfo.biHeight - 1) * (bytesperline+padbytes);

  /*
   * 24 bit images have to be converted from grb to rgb.
   */

  if (imageinfo.biBitCnt == 24)
  {
      if ((linebuffer = malloc((size_t) bytesperline + padbytes)) == NULL)
      {
	  fprintf(stderr, "%s: can't allocate line buffer memory\n",
		  fname);
	  return BMP_LOW_MEMORY;
      }
  }

  for (i = imageinfo.biHeight; i > 0; i--)
  {

      /*
       * read one line
       */
      if (imageinfo.biBitCnt == 24)
      {
	  result = (long) fread(linebuffer, (size_t) bytesperline, 
				1, fp);

	  if (result != 1)
	  {
	      fprintf(stderr, "%s: Unable to read image data line %ld\n", 
		      fname, i);

	      return BMP_IMAGE_DATA_CORRUPT;
	  }

	  /*
	   * Convert from [bgr] to [rgb].
	   */

	  for (j = 0, k = 0; j < bytesperline; j += 3, k += 3)
	  {
	      tmpdata[j] = linebuffer[k + 2];
	      tmpdata[j + 1] = linebuffer[k + 1];
	      tmpdata[j + 2] = linebuffer[k];
	  }

	  /*
	   * read pad bytes because bitmap format expects lines that
	   * are divisible by 4.
	   */

	  result = (long) fread(pad, (size_t) sizeof(char), 
				(size_t) padbytes, fp);

	  if (result != padbytes)
	  {
	      fprintf(stderr, "%s: Unable to read pad bytes at line %ld\n", 
		      fname, i);

	      return BMP_IMAGE_DATA_CORRUPT;
	  }

	  tmpdata -= bytesperline;

      }
      else
      {
	  result = (long) fread(tmpdata, (size_t) bytesperline + padbytes, 
				1, fp);

	  if (result != 1)
	  {
	      fprintf(stderr, "%s: Unable to read image data line %ld\n", 
		      fname, i);

	      return BMP_IMAGE_DATA_CORRUPT;
	  }

	  tmpdata -= bytesperline + padbytes;

      }
  }


  /*
   * we subtracted one line to much so we restore the pointer here
   */

  if (imageinfo.biBitCnt == 24)
  {
      tmpdata += bytesperline;
  }
  else
  {
      tmpdata += bytesperline + padbytes;
  }


  if (linebuffer != NULL)
  {
      free(linebuffer);
  }

  switch (imageinfo.biBitCnt)
  {
      case 1:

	  /*
	   * Now the data is converted with aid of the color lookup table
	   * to RGB data. Watch out the width is expanded because one byte
	   * of tmpdata contains 8 pixels in rgb image.
	   */

	  if( (rgbdata = (unsigned char *) 
	       my_malloc(3 * imageinfo.biWidth * imageinfo.biHeight *
			 sizeof(unsigned char), _BMPM_TMP_D_)) == 
	      (unsigned char *) NULL)
	  {
	      (void) fprintf(stderr, "%s: out of memory\n", fname);
	      return(BMP_ERROR);  
	  }


	  for (i = m = k = l = n = 0; i < imageinfo.biHeight; i++)
	  {
	      for (j = 0; j < 8*(bytesperline+padbytes); j++, l++)
	      {
		  /*
		   * l counts the bits in output image.
		   * k counts the bits in a byte.
		   * m counts the pixels in the rgb image.
		   * n counts the bytes in the packed array.
		   */

		  k = 7 - (l%8);

		  /*
		   * Get the required bit and look it up in the color
		   * lookup table.
		   */

		  c = (tmpdata[n] & (0x01 << k)) >> k;

		  if (k == 0) n++;
 
		  if (j < imageinfo.biWidth) 
		  {
		      rgbdata[m++] = imageinfo.lut[c].red;
		      rgbdata[m++] = imageinfo.lut[c].green;
		      rgbdata[m++] = imageinfo.lut[c].blue;
		  }

	      }
	  }


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

	  EZ_RawRGBData2Pixmap(rgbdata, imageinfo.biWidth, 
			       imageinfo.biHeight, &pixmap);


	  /*
	   * Clean up the memory that isn't used anymore.
	   */

	  (void) my_free( (unsigned char *)tmpdata);
	  (void) my_free( (unsigned char *)rgbdata);

	  if (imageinfo.lut != NULL)
	  {
	      free(imageinfo.lut);
	  }

	  break;

      case 4:

	  /*
	   * Now the data is converted with aid of the color lookup table
	   * to RGB data. Watch out the width is expanded because one byte
	   * of tmpdata contains 2 pixels in rgb image.
	   */

	  if( (rgbdata = (unsigned char *) 
	       my_malloc(3 * imageinfo.biWidth * imageinfo.biHeight *
			 sizeof(unsigned char), _BMPM_TMP_D_)) == 
	      (unsigned char *) NULL)
	  {
	      (void) fprintf(stderr, "%s: out of memory\n", fname);
	      return(BMP_ERROR);  
	  }

	  for (i = m = k = l = n = 0; i < imageinfo.biHeight; i++)
	  {
	      for (j = 0; j < 2*(bytesperline+padbytes); j++, l++)
	      {
		  /*
		   * l counts the bits in output image.
		   * k counts the bits in a byte.
		   * m counts the pixels in the rgb image.
		   * n counts the bytes in the packed array.
		   */

		  k = 4*(l%2);

		  /*
		   * Get the required bit and look it up in the color
		   * lookup table.
		   */

		  c = (tmpdata[n] & (0x0f << k)) >> k;

		  if (k == 0) n++;
 
		  if (j < imageinfo.biWidth) 
		  {
		      rgbdata[m++] = imageinfo.lut[c].red;
		      rgbdata[m++] = imageinfo.lut[c].green;
		      rgbdata[m++] = imageinfo.lut[c].blue;
		  }

	      }
	  }


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

	  EZ_RawRGBData2Pixmap(rgbdata, imageinfo.biWidth, 
			       imageinfo.biHeight, &pixmap);


	  /*
	   * Clean up the memory that isn't used anymore.
	   */

	  (void) my_free( (unsigned char *)tmpdata);
	  (void) my_free( (unsigned char *)rgbdata);

	  if (imageinfo.lut != NULL)
	  {
	      free(imageinfo.lut);
	  }

	  break;


      case 8:

	  /*
	   * Now the data is converted with aid of the color lookup table
	   * to RGB data.
	   */

	  if( (rgbdata = (unsigned char *) 
	       my_malloc(3 * imageinfo.biWidth * imageinfo.biHeight *
			 sizeof(unsigned char), _BMPM_TMP_D_)) == 
	      (unsigned char *) NULL)
	  {
	      (void) fprintf(stderr, "%s: out of memory\n", fname);
	      return(BMP_ERROR);  
	  }


	  for (i = m = l = 0; i < imageinfo.biHeight; i++)
	  {
	      for (j = 0; j < bytesperline+padbytes; j++, l++)
	      {
		  if (j < imageinfo.biWidth) 
		  {
		      rgbdata[m++] = imageinfo.lut[tmpdata[l]].red;
		      rgbdata[m++] = imageinfo.lut[tmpdata[l]].green;
		      rgbdata[m++] = imageinfo.lut[tmpdata[l]].blue;
		  }
	      }
	  }


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

	  EZ_RawRGBData2Pixmap(rgbdata, imageinfo.biWidth, imageinfo.biHeight, 
			       &pixmap);


	  /*
	   * Clean up the memory that isn't used anymore.
	   */

	  (void) my_free( (unsigned char *)tmpdata);
	  (void) my_free( (unsigned char *)rgbdata);

	  if (imageinfo.lut != NULL)
	  {
	      free(imageinfo.lut);
	  }

	  break;

      case 16:

	  /*
	   * Now the data is converted with aid of the color lookup table
	   * to RGB data.
	   */

	  if( (rgbdata = (unsigned char *) 
	       my_malloc(3 * imageinfo.biWidth * imageinfo.biHeight *
			 sizeof(unsigned char), _BMPM_TMP_D_)) == 
	      (unsigned char *) NULL)
	  {
	      (void) fprintf(stderr, "%s: out of memory\n", fname);
	      return(BMP_ERROR);  
	  }


	  for (i = m = l = 0; i < imageinfo.biHeight; i++)
	  {
	      for (j = 0; j < imageinfo.biWidth; j++)
	      {
		  rgbdata[m++] = imageinfo.lut[tmpdata[l]].red;
		  rgbdata[m++] = imageinfo.lut[tmpdata[l]].green;
		  rgbdata[m++] = imageinfo.lut[tmpdata[l++]].blue;
	      }
	  }


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

	  EZ_RawRGBData2Pixmap(rgbdata, imageinfo.biWidth, imageinfo.biHeight, 
			       &pixmap);


	  /*
	   * Clean up the memory that isn't used anymore.
	   */

	  (void) my_free( (unsigned char *)tmpdata);
	  (void) my_free( (unsigned char *)rgbdata);

	  if (imageinfo.lut != NULL)
	  {
	      free(imageinfo.lut);
	  }

	  break;

      case 24:

	  /* 
	   * True color images have been loaded.
	   */

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

	  EZ_RawRGBData2Pixmap(tmpdata, imageinfo.biWidth, imageinfo.biHeight, 
			       &pixmap);


	  /*
	   * Clean up the memory that isn't used anymore.
	   */

	  (void)my_free( (unsigned char *) tmpdata);

	  break;

      default:
	  fprintf(stderr,"%s: ERROR: imageinfo.biBitCnt unvalid"
		  "in %s\n", fname, filename);

	  return BMP_INFO_HEADER_CORRUPT;

  }


 
  if((pixmap != (Pixmap )NULL) && (imageinfo.biWidth > 0) && 
     (imageinfo.biHeight > 0))
  {
      *width_return = imageinfo.biWidth;
      *height_return = imageinfo.biHeight;
      *pixmap_return = pixmap;
      return(BMP_NO_ERROR);       /* was return(1) */
  }
  else
    return(BMP_ERROR);            /* was return(0) */
}
/**********************************************************************************************/
#undef _EZ_BMP_C_

