#define TEST	// EPV_160499
//		Avoid do retrieve properly an XWD image with
//		NT 4.0 Service pack 4

#define IMP080200	//GG
//		Enable to evaluate correctly the fileneme extension
//		according to the CSF_DefaultImageFormat symbol.

#define BUC60837	// GG 07/03/01
//		Enable to read a GIF image file even a if the file contains
//		wrong informations. 

#define IMP100701	// SZV Introduce new function DumpBitmapToFile
//              to bypass problem in WNT_PixMap::Dump()
 
#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <stdio.h>

#ifdef DrawText
# undef DrawText
#endif  /* DrawText */

#include <Aspect_XWD.hxx>

#include <Quantity_Color.hxx>
#include <WNT_GraphicDevice.hxx>
#include <WNT_TypeOfImage.hxx>
//***//
#define I_SUCCESS Standard_True
#define I_ERROR   Standard_False

#define PIXEL4   4
#define PIXEL8   8
#define PIXEL16 16
#define PIXEL24 24
#define PIXEL32 32

#define MAXCOLOR   256
#define PAD(a)     (   ( a ) % sizeof ( LONG ) ?                          \
                   sizeof ( LONG ) - (  ( a ) % sizeof ( LONG )  ) : 0  )
#ifdef _DEBUG
# define MALLOC(s) calloc (  ( s ), 1  )
# define FREE(p)   free   (  ( p )     )
#else
# define MALLOC(s)  HeapAlloc (  hHeap, HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, ( s )  )
# define FREE(p)    HeapFree  (  hHeap, 0, ( p )  )
#endif  /* _DEBUG */
#define WINNT35X() (WNT_osVer.dwPlatformId   == VER_PLATFORM_WIN32_NT && \
                    WNT_osVer.dwMajorVersion == 3 )
//***//
typedef struct {

		 BYTE pixel[ 3 ];

        } TRIPLET, *PTRIPLET;

class _init {

 public:

   _init ();
  ~_init ();

};  // end _init
//***//
OSVERSIONINFO WNT_osVer;

HWINSTA ( WINAPI *NTOpenWindowStation       ) ( LPTSTR, BOOL, DWORD        );
BOOL    ( WINAPI *NTSetProcessWindowStation ) ( HWINSTA                    );
HDESK   ( WINAPI *NTOpenDesktop             ) ( LPTSTR, DWORD, BOOL, DWORD );
BOOL    ( WINAPI *NTSetThreadDesktop        ) ( HDESK                      );
BOOL    ( WINAPI *NTCloseDesktop            ) ( HDESK                      );
BOOL    ( WINAPI *NTCloseWindowStation      ) ( HWINSTA                    );
//***//
static DWORD           dwFileSize;
static LPVOID          lpvFile;
static HDC             hDC;
#ifdef TEST
static BOOL            fWindow=FALSE;
#endif
static WNT_TypeOfImage imgType;
static HANDLE          hHeap;
static _init           init;
//***//
static HBITMAP loadXWD (  Handle( WNT_GraphicDevice )&  );
static HBITMAP loadBMP (  Handle( WNT_GraphicDevice )&  );
static HBITMAP loadGIF (  Handle( WNT_GraphicDevice )&  );
//***//
static int writeXWD ( HANDLE, HBITMAP, Handle( WNT_GraphicDevice )& );
static int writeBMP ( HANDLE, HBITMAP, Handle( WNT_GraphicDevice )& );
static int writeGIF ( HANDLE, HBITMAP, Handle( WNT_GraphicDevice )& );
//***//
static void            __fastcall _swaplong   ( char*, unsigned );
static void            __fastcall _swapshort  ( char*, unsigned );
static int             __fastcall _getshift   ( unsigned long   );
static WNT_TypeOfImage __fastcall _image_type ( LPTSTR, BOOL    );
//***//
static void __fastcall _alloc_colors (
                        PVOID, int, int, int, LPRGBQUAD, Handle( WNT_GraphicDevice )&
                       );
static BOOL __fastcall _convert24to8 (
                        LPRGBQUAD, PBYTE, PBYTE, int, int
                       );
//***//
int SaveBitmapToFile (
     Handle( WNT_GraphicDevice )& , HBITMAP , char*, int, int, int, int
	);
//***//
HBITMAP LoadImageFromFile (
         Handle( WNT_GraphicDevice )& gDev, char* fileName, HDC hDevCtx
	    ) {

 HANDLE   hFile, hFileMap = NULL;
 HBITMAP  retVal = NULL;
 DWORD    dwProtect, dwAccess;

 if ( WNT_osVer.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS ) {

  dwProtect = PAGE_WRITECOPY;
  dwAccess  = GENERIC_READ | GENERIC_WRITE;

 } else {
 
  dwProtect = PAGE_READONLY;
  dwAccess  = GENERIC_READ;
 
 }  // end else

 hDC = ( hDevCtx != NULL ) ? hDevCtx : GetDC ( NULL );

#ifdef IMP080200	// Check extension
 WNT_TypeOfImage iType   = imgType;
 TCHAR           drv[ _MAX_DRIVE ];
 TCHAR           dir[ _MAX_DIR   ];
 TCHAR           fnm[ _MAX_FNAME ];
 TCHAR           ext[ _MAX_EXT   ];
 TCHAR           ifl[ _MAX_PATH  ];

 _splitpath ( fileName, drv, dir, fnm, ext );

 if (  ext[ 0 ] == TEXT( '\x00' )  ) {
   ext[ 0 ] = TEXT( '.'    );
   ext[ 1 ] = TEXT( '\x00' );
 }  // end if

 iType = _image_type ( &ext[ 1 ], FALSE );

 _makepath ( ifl, drv, dir, fnm, ext );
#endif

 __try {
 
  hFile = CreateFile (
#ifdef IMP080200
	ifl, dwAccess, FILE_SHARE_READ, NULL,
#else
	fileName, dwAccess, FILE_SHARE_READ, NULL,
#endif
           OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
		  );

  if ( hFile == INVALID_HANDLE_VALUE ) __leave;

  dwFileSize = GetFileSize ( hFile, NULL );

  if ( dwFileSize == 0xFFFFFFFF ) __leave;

  hFileMap = CreateFileMapping (
              hFile, NULL, dwProtect, 0, dwFileSize, NULL
             );

  if ( hFileMap == NULL ) __leave;

  lpvFile = MapViewOfFile ( hFileMap, FILE_MAP_COPY, 0, 0, 0 );

  if ( lpvFile == NULL ) __leave;

  if (   memcmp (  ( const void* )lpvFile, ( const void* )"BM", 2  ) == 0   )
		
   retVal = loadBMP ( gDev );

  else if (   memcmp (  ( const void* )lpvFile, ( const void* )"GIF87a", 6  ) == 0 ||
              memcmp (  ( const void* )lpvFile, ( const void* )"GIF89a", 6  ) == 0
       )

   retVal = loadGIF ( gDev );

  else  // assume XWD file

   retVal = loadXWD ( gDev );

 }  // end __try

 __finally {

  if ( lpvFile  != NULL ) {
  
   UnmapViewOfFile ( lpvFile );
   lpvFile = NULL;

  }  // end if

  if ( hFileMap != NULL                 ) CloseHandle ( hFileMap );
  if ( hFile    != INVALID_HANDLE_VALUE ) CloseHandle ( hFile    );

 }  // end __finally

 if ( hDevCtx == NULL ) ReleaseDC ( NULL, hDC );
       
 return retVal;

}  // end LoadImageFromFile

int SaveWindowToFile (
     Handle( WNT_GraphicDevice )& gDev,
     HWND hWnd, char* fName, int x, int y, int w, int h
    ) {
    
 int      retVal = I_ERROR;
 HDC      hDCmem;
 HBITMAP  hBmp = NULL, hOldBmp;
 HPALETTE hOldPal;

 __try {
 
  hDC = GetDC ( hWnd );
#ifdef TEST
  fWindow = TRUE;
#endif

  if (  gDev -> IsPaletteDevice ()  ) {
  
   hOldPal = SelectPalette (  hDC, ( HPALETTE )(  gDev -> HPalette ()  ), FALSE  );
   RealizePalette ( hDC );
  
  }  // end if

  hDCmem = CreateCompatibleDC ( hDC );

  hBmp = CreateCompatibleBitmap ( hDC, w, h );

  if ( hBmp == NULL ) __leave;

  hOldBmp = SelectBitmap ( hDCmem, hBmp );

   BitBlt ( hDCmem, 0, 0, w, h, hDC, x, y, SRCCOPY );

  SelectBitmap ( hDCmem, hOldBmp );

  retVal = SaveBitmapToFile ( gDev, hBmp, fName, 0, 0, w, h );
 
 }  // end __try

 __finally {

#ifdef TEST
  fWindow = FALSE;
#endif
 
  if ( hBmp != NULL ) DeleteObject ( hBmp );

  if (  gDev -> IsPaletteDevice ()  )

   SelectPalette ( hDC, hOldPal, FALSE );

  DeleteDC ( hDCmem );
  ReleaseDC ( hWnd, hDC ); 
 
 }  // end __finally
  
 return retVal; 
    
}  // end SaveWindowToFile

#ifdef IMP100701
int DumpBitmapToFile (Handle( WNT_GraphicDevice )& gDev,
                      HDC aDC, HBITMAP aBmp, char* fName)
{
  int    retVal = I_ERROR;

  HANDLE hFile  = INVALID_HANDLE_VALUE;

  __try {

    hDC = aDC;

    TCHAR drv[ _MAX_DRIVE ];
    TCHAR dir[ _MAX_DIR   ];
    TCHAR fnm[ _MAX_FNAME ];
    TCHAR ext[ _MAX_EXT   ];
    TCHAR ifl[ _MAX_PATH  ];

    _splitpath ( fName, drv, dir, fnm, ext );

    _makepath ( ifl, drv, dir, fnm, ext );

    hFile = CreateFile
      ( ifl, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );

    if ( hFile == INVALID_HANDLE_VALUE ) __leave;

    if (  ext[ 0 ] == TEXT( '\0' )  ) {

      ext[ 0 ] = TEXT( '.'    );
      ext[ 1 ] = TEXT( '\0' );

    }  // end if

    WNT_TypeOfImage iType = imgType;
    iType = _image_type ( &ext[ 1 ], FALSE );

    switch ( iType ) {

      case WNT_TOI_XWD: retVal = writeXWD ( hFile, aBmp, gDev ); break;

      case WNT_TOI_BMP: retVal = writeBMP ( hFile, aBmp, gDev ); break;

      case WNT_TOI_GIF: retVal = writeGIF ( hFile, aBmp, gDev );

    }  // end switch

  }  // end __try

  __finally {

    if ( hFile != INVALID_HANDLE_VALUE ) CloseHandle ( hFile );

  }  // end __finally

  return retVal;
}  // end DumpBitmapToFile
#endif

//***//
int SaveBitmapToFile (
     Handle( WNT_GraphicDevice )& gDev,
     HBITMAP hBmp, char* fName, int x, int y, int w, int h
	) {
	
 int             retVal  = I_ERROR;
 HBITMAP         hNewBmp = NULL;
 HPALETTE        hOldPal;
 BOOL            newBmp  = FALSE, newDC = FALSE;
 HANDLE          hFile   = INVALID_HANDLE_VALUE;
 WNT_TypeOfImage iType   = imgType;
 TCHAR           drv[ _MAX_DRIVE ];
 TCHAR           dir[ _MAX_DIR   ];
 TCHAR           fnm[ _MAX_FNAME ];
 TCHAR           ext[ _MAX_EXT   ];
 TCHAR           ifl[ _MAX_PATH  ];
  
 __try {

#ifdef TEST
  if ( !fWindow )
#else
  if ( y != 0 || x != 0 )
#endif
  {
  
   HBITMAP hOldBmp;
   HDC hDCmemSrc, hDCmemDst;

   newDC = TRUE;

   hDC = GetDC ( NULL );

   if (  gDev -> IsPaletteDevice ()  ) {
	
	hOldPal = SelectPalette ( hDC, ( HPALETTE )(  gDev -> HPalette ()  ), FALSE );
	RealizePalette ( hDC );
	
   }  // end if

   hDCmemSrc = CreateCompatibleDC ( hDC );
    hDCmemDst = CreateCompatibleDC ( hDC );

     hNewBmp = CreateCompatibleBitmap ( hDC, w, h );

     if ( hNewBmp != NULL ) {
	 
	  hOldBmp = SelectBitmap ( hDCmemDst, hNewBmp );
	  SelectBitmap ( hDCmemSrc, hBmp    );

	  BitBlt ( hDCmemDst, 0, 0, w, h, hDCmemSrc, x, y, SRCCOPY );

	  newBmp = TRUE;
	  SelectBitmap ( hDCmemDst, hOldBmp );
	 
	 }  // end if

	DeleteDC ( hDCmemDst );
   DeleteDC ( hDCmemSrc );

   if (  gDev -> IsPaletteDevice ()  )

	SelectPalette ( hDC, hOldPal, FALSE );

   if ( hNewBmp == NULL ) __leave;
   
  } else hNewBmp = hBmp;

  _splitpath ( fName, drv, dir, fnm, ext );

  if (  ext[ 0 ] == TEXT( '\x00' )  ) {
  
   ext[ 0 ] = TEXT( '.'    );
   ext[ 1 ] = TEXT( '\x00' );
  
  }  // end if

  iType = _image_type ( &ext[ 1 ], FALSE );

  _makepath ( ifl, drv, dir, fnm, ext );

  hFile = CreateFile (
           ifl, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL
		  );

  if ( hFile == INVALID_HANDLE_VALUE ) __leave;

  switch ( iType ) {
  
   case WNT_TOI_XWD:

    retVal = writeXWD ( hFile, hNewBmp, gDev );

   break;

   case WNT_TOI_BMP:

    retVal = writeBMP ( hFile, hNewBmp, gDev );

   break;

   case WNT_TOI_GIF:

    retVal = writeGIF ( hFile, hNewBmp, gDev );
  
  }  // end switch
 
 }  // end __try

 __finally {
 
  if ( hNewBmp != NULL && newBmp ) DeleteObject ( hNewBmp );

  if ( hFile != INVALID_HANDLE_VALUE ) CloseHandle ( hFile );

  if ( newDC ) ReleaseDC ( NULL, hDC );
 
 }  // end __finally

 return retVal;

}  // end SaveBitmapToFile
//***//
void SetOutputFormat ( WNT_TypeOfImage type ) {

 imgType = type;

}  // end SetOutputFormat
//***//
//**************** Routines to process XWD file ***************************//
//***//
static HBITMAP loadXWD (  Handle( WNT_GraphicDevice )& gDev  ) {

 UINT             i, j, k;
 UINT             red_shift, green_shift, blue_shift;
 HBITMAP          retVal = NULL;
 PBITMAPINFO      pBmi   = NULL;
 PBYTE            pbInit;
 UINT             nBytes, bitmapSize;
 WORD             bitCount;
 HPALETTE         hOldPal;
 LONG             lPixel;
 WORD             wPixel;
 BYTE             bPixel;
 BOOL             newMem = FALSE;
 PBYTE            ptrDIB, ptrXWD;
 UINT             incDIB, incXWD;
 XWDFileHeader*   xwdHdr;
 XColor*          xColor;
 Standard_Integer r, g, b;
 WORD             colors[ MAXCOLOR ];
 LPVOID           imageData;
 DWORD            dataSize;

 __try {

  xwdHdr = ( XWDFileHeader* )lpvFile;

  _swaplong (  ( char* )xwdHdr, sizeof ( XWDFileHeader )  );

  if ( xwdHdr -> file_version  != XWD_FILE_VERSION ||
       xwdHdr -> pixmap_format != ZPixmap          ||
       xwdHdr -> header_size   <  sizeof ( XWDFileHeader )
  ) __leave;

  xColor = ( XColor* )(  ( char* )lpvFile + xwdHdr -> header_size  );

  for ( i = 0; i < xwdHdr -> ncolors; ++i ) {
  
   _swaplong  (  ( char* )&xColor[ i ].pixel, sizeof ( unsigned long  )  );
   _swapshort (  ( char* )&xColor[ i ].red,   sizeof ( unsigned short ) * 3  );
  
  }  // end for

  imageData = ( LPVOID )( xColor + xwdHdr -> ncolors );
  imageData = ( LPVOID )(  ( char* )imageData + xwdHdr -> xoffset  );
  dataSize  = ( DWORD )(  ( char* )lpvFile + dwFileSize - ( char* )imageData  );

  nBytes = sizeof ( BITMAPINFO );

  switch ( xwdHdr -> visual_class ) {
  
   case StaticColor:
   case PseudoColor:

    if ( xwdHdr -> bits_per_pixel < 12 ) {

	 bitCount = ( xwdHdr -> bits_per_pixel <= 4 ) ? 4 : 8;
#ifdef TEST
	 nBytes  += sizeof ( RGBQUAD ) * ( 1 << bitCount );
#else
	 nBytes  += sizeof ( RGBQUAD ) * xwdHdr -> ncolors;
#endif
	} else if ( xwdHdr -> bits_per_pixel == 16 )

	 bitCount = 16;

	else

	 __leave;

    break;
    
   case TrueColor:
   case DirectColor:

     red_shift   = _getshift ( xwdHdr -> red_mask   );
     green_shift = _getshift ( xwdHdr -> green_mask );
     blue_shift  = _getshift ( xwdHdr -> blue_mask  );
   
   	 if ( xwdHdr -> bits_per_pixel < 24 )

	  bitCount = 16;

	 else if ( xwdHdr -> bits_per_pixel == 24 )

	  bitCount = 24;

	 else if ( xwdHdr -> bits_per_pixel == 32 )

	  bitCount = 32;

	 else

	  __leave;
   
    break;   
  
  }  // end switch
 
  pBmi = ( PBITMAPINFO )MALLOC( nBytes );

  if ( pBmi == NULL ) __leave;

  pBmi -> bmiHeader.biSize          = sizeof ( BITMAPINFOHEADER );
  pBmi -> bmiHeader.biWidth	        = xwdHdr -> pixmap_width;
  pBmi -> bmiHeader.biHeight        = -( int )xwdHdr -> pixmap_height;
  pBmi -> bmiHeader.biPlanes        = 1;
  pBmi -> bmiHeader.biBitCount      = bitCount;
  pBmi -> bmiHeader.biCompression   = BI_RGB;

  ZeroMemory (  ( PVOID )&colors, sizeof ( colors )  );

  switch ( xwdHdr -> visual_class ) {
  
   case StaticColor:
   case PseudoColor:

    if ( bitCount != 16 ) {

     for ( i = 0; i < xwdHdr -> ncolors; ++i ) {
      
      pBmi -> bmiColors[ i ].rgbBlue  = ( xColor[ i ].blue  >> 8 );
      pBmi -> bmiColors[ i ].rgbGreen = ( xColor[ i ].green >> 8 );
      pBmi -> bmiColors[ i ].rgbRed   = ( xColor[ i ].red   >> 8 );

     }  // end for

     incXWD = xwdHdr -> bytes_per_line;
     incDIB = incXWD + PAD( incXWD );

     if ( xwdHdr -> bytes_per_line == incDIB )

	  pbInit = ( PBYTE )imageData;

	 else {

	  bitmapSize = xwdHdr -> pixmap_height * incDIB;

	  pbInit = ( PBYTE )MALLOC( bitmapSize );

	  if ( pbInit == NULL ) __leave;

	  newMem = TRUE;

	  ptrDIB = ( PBYTE )pbInit;
	  ptrXWD = ( PBYTE )imageData;

	  for ( i = 0; i < xwdHdr -> pixmap_height; ++i ) {
	  
       CopyMemory ( ptrDIB, ptrXWD, incXWD );

	   ptrDIB += incDIB;
	   ptrXWD += incXWD;
	  
	  }  // end for ( i . . . )

	 }  // end else

     ptrDIB = ( PBYTE )MALLOC( dataSize );

	 if ( ptrDIB == NULL ) __leave;

	 CopyMemory (  ( PVOID )ptrDIB, ( PVOID )pbInit, dataSize  );
	 FillMemory (  ( PVOID )colors, MAXCOLOR * sizeof ( WORD ), 0xFFFF );

	 for ( i = 0; i < dataSize; ++i ) {
	 
	  if ( colors[  ptrDIB[ i ]  ] != 0xFFFF ) continue;

	  for ( j = 0; j < xwdHdr -> ncolors; ++j )

	   if ( xColor[ j ].pixel == pbInit[ i ] )

	    break;

	  for ( k = 0; k < dataSize; ++k )

	   if ( ptrDIB[ k ] == xColor[ j ].pixel )
	   
	    pbInit[ k ] = j;

	  colors[  ptrDIB[ i ]  ] = j;

	 }  // end for

	  if (  gDev -> IsPaletteDevice ()  ) {
	  
	   for ( i = 0; i < MAXCOLOR; ++i ) {

        if ( colors[ i ] == 0xFFFF ) continue;

	    b = ( Standard_Integer )( xColor[  colors[ i ]  ].blue  >> 8 );
	    g = ( Standard_Integer )( xColor[  colors[ i ]  ].green >> 8 );
	    r = ( Standard_Integer )( xColor[  colors[ i ]  ].red   >> 8 );

	    gDev -> SetColor ( r, g, b );

       }  // end for
	  
	  }  // end if

	 FREE( ptrDIB );

    } else {  // bitCount == 16

     WORD red, green, blue;

	 incXWD = xwdHdr -> bytes_per_line;
	 incDIB = xwdHdr -> pixmap_width * sizeof ( WORD );
	 incDIB += PAD( incDIB );

     _swapshort (  ( char* )imageData, dataSize  );
     
     if ( xwdHdr -> bytes_per_line == incDIB )

	  pbInit = ( PBYTE )imageData;

	 else {

	  bitmapSize = xwdHdr -> pixmap_height * incDIB;

	  pbInit = ( PBYTE )MALLOC( bitmapSize );

	  if ( pbInit == NULL ) __leave;

	  newMem = TRUE;

	  ptrDIB = ( PBYTE )pbInit;
	  ptrXWD = ( PBYTE )imageData;

	  for ( i = 0; i < xwdHdr -> pixmap_height; ++i ) {
	  
       CopyMemory ( ptrDIB, ptrXWD, incXWD );

	   ptrDIB += incDIB;
	   ptrXWD += incXWD;
	  
	  }  // end for ( i . . . )

	 }  // end else

     ptrDIB = pbInit;
	 dataSize = xwdHdr -> pixmap_height * incDIB;

	 for ( i = 0; i < xwdHdr -> pixmap_height; ++i ) {

	  for ( j = 0; j < xwdHdr -> pixmap_width; ++j ) {
	 
	   wPixel = (  ( PWORD )ptrDIB  )[ j ];
	   red   = ( xColor[ wPixel ].red   >> 11 ) << 10;
	   green = ( xColor[ wPixel ].green >> 11 ) <<  5;
	   blue  = ( xColor[ wPixel ].blue  >> 11 );
	   wPixel = red | green | blue;
	   (  ( PWORD )ptrDIB  )[ j ] = wPixel;

	  }  // end for ( j . . . )
      
	  ptrDIB += incDIB;

     }  // end for ( i . . . )

AllocColors_16:

	 if (  gDev -> IsPaletteDevice ()  )

	  _alloc_colors (
	   pbInit, xwdHdr -> pixmap_width, xwdHdr -> pixmap_height, PIXEL16, NULL, gDev
	  );

    }  // end else
    
   break;

   case TrueColor:
   case DirectColor:

    switch ( bitCount ) {
     
     case 16:

	  _swapshort (  ( char* )imageData, dataSize  );

	  incXWD = xwdHdr -> bytes_per_line;
	  incDIB = xwdHdr -> pixmap_width * sizeof ( WORD );
	  incDIB += PAD( incDIB );
	  bitmapSize = incDIB * xwdHdr -> pixmap_height;

	  pbInit = ( PBYTE )MALLOC( bitmapSize );

	  if ( pbInit == NULL ) __leave;

	  newMem = TRUE;

	  ptrDIB = ( PBYTE )pbInit;
	  ptrXWD = ( PBYTE )imageData;

      switch ( xwdHdr -> bits_per_pixel ) {
      
       case 8:

        for ( i = 0; i < xwdHdr -> pixmap_height; ++i ) {
        
         for ( j = 0; j < xwdHdr -> pixmap_width; ++j ) {
         
          bPixel = ptrXWD[ j ];
		  b = ( xColor[ ( bPixel & xwdHdr -> blue_mask  ) >> blue_shift  ].blue  ) >> 11;
		  g = ( xColor[ ( bPixel & xwdHdr -> green_mask ) >> green_shift ].green ) >> 11;
		  r = ( xColor[ ( bPixel & xwdHdr -> red_mask   ) >> red_shift   ].red   ) >> 11;
		  (  ( PWORD )ptrDIB  )[ j ] = ( WORD )(  b | ( g << 5 ) | ( r << 10 )  );
         
         }  // end for ( j . . . )

		 ptrDIB += incDIB;
		 ptrXWD += incXWD;
        
        }  // end for ( i . . . )
	    
       break;
              
       case 16:

        for ( i = 0; i < xwdHdr -> pixmap_height; ++i ) {
        
         for ( j = 0; j < xwdHdr -> pixmap_width; ++j ) {
         
          wPixel = (  ( PWORD )ptrXWD  )[ j ];
		  b = ( xColor[ ( wPixel & xwdHdr -> blue_mask  ) >> blue_shift  ].blue  ) >> 11;
		  g = ( xColor[ ( wPixel & xwdHdr -> green_mask ) >> green_shift ].green ) >> 11;
		  r = ( xColor[ ( wPixel & xwdHdr -> red_mask   ) >> red_shift   ].red   ) >> 11;
		  (  ( PWORD )ptrDIB  )[ j ] = ( WORD )(  b | ( g << 5 ) | ( r << 10 )  );
         
         }  // end for ( j . . . )

		 ptrDIB += incDIB;
		 ptrXWD += incXWD;
        
        }  // end for ( i . . . )

	   break;

	   default:

	    __leave;

      }  // end switch ( xwdHdr -> bits_per_pixel . . . )

      goto AllocColors_16;   // not attractive but efficient

	 break;

     case 24:

      __leave;

     case 32:

      _swaplong (  ( char* )imageData, dataSize  );

	  pbInit = ( PBYTE )imageData;
	  bitmapSize = xwdHdr -> pixmap_height *
	               xwdHdr -> pixmap_width * sizeof ( LONG );

      if ( xwdHdr -> ncolors != 0 )

	   for (  i = j = 0; j < bitmapSize; i += sizeof ( LONG )  ) {

        lPixel = ( LONG )*(   ( PLONG )(  ( PBYTE )imageData + j  )   );

	    pbInit[ i ]     =
	     ( BYTE )( xColor[ ( lPixel & xwdHdr -> blue_mask  ) >> blue_shift  ].blue  );
	    pbInit[ i + 1 ] =
	     ( BYTE )( xColor[ ( lPixel & xwdHdr -> green_mask ) >> green_shift ].green );
	    pbInit[ i + 2 ] =								
	     ( BYTE )( xColor[ ( lPixel & xwdHdr -> red_mask   ) >> red_shift   ].red   );
	    pbInit[ i + 3 ] = 0;

	    j += sizeof ( LONG );
	  
	   }  // end for

	  else

	   for (  i = j = 0; j < bitmapSize; i += sizeof ( LONG )  ) {

        lPixel = ( LONG )*(   ( PLONG )(  ( PBYTE )imageData + j  )   );

	    pbInit[ i ]     =
	     ( BYTE )(  ( lPixel & xwdHdr -> blue_mask  ) >> blue_shift  );
	    pbInit[ i + 1 ] =
	     ( BYTE )(  ( lPixel & xwdHdr -> green_mask ) >> green_shift );
	    pbInit[ i + 2 ] =								
	     ( BYTE )(  ( lPixel & xwdHdr -> red_mask   ) >> red_shift   );
	    pbInit[ i + 3 ] = 0;

	    j += sizeof ( LONG );
	  
	   }  // end for

      if (  gDev -> IsPaletteDevice ()  )

	   _alloc_colors (
	    pbInit, xwdHdr -> pixmap_width, xwdHdr -> pixmap_height, PIXEL32, NULL, gDev
	   );

    }  // end switch ( bitCount . . . )

  }  // end switch ( xwdHdr -> visual_class . . . )

  if (  gDev -> IsPaletteDevice ()  ) {
  
   hOldPal = SelectPalette (  hDC, ( HPALETTE )(  gDev -> HPalette ()  ), FALSE  );

   if (  RealizePalette ( hDC )  )
   
    UpdateColors ( hDC );
  
  }  // end if

   retVal = CreateDIBitmap (
             hDC, &pBmi -> bmiHeader, CBM_INIT, pbInit, pBmi, DIB_RGB_COLORS
 	 	    );

  if (  gDev -> IsPaletteDevice ()  )

   SelectPalette ( hDC, hOldPal, FALSE );

 }  // end try

 __finally {
 
  if ( pbInit != NULL && newMem ) FREE( pbInit );
  if ( pBmi   != NULL           ) FREE( pBmi   );
 
 }  // end finally

 return retVal;

}  // end readXWD

static void __fastcall _swaplong ( char* bp, unsigned n ) {

 char  c;
 char* ep = bp + n;
 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;
 
 }  // end while

}  // end _swaplong

static void __fastcall _swapshort ( char* bp, unsigned n ) {

 char  c;
 char* ep = bp + n;

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

}  // end _swapshort

static int __fastcall _getshift ( unsigned long mask ) {

 int retVal = 0;

 while (  !( mask & 1 )  ) {
 
  ++retVal;
  mask >>= 1;

 }  // end while

 return retVal;

}  // end _getshift

static int writeXWD ( HANDLE hFile, HBITMAP hBmp, Handle( WNT_GraphicDevice )& gDev ) {

 UINT          i;
 INT           retVal = I_ERROR;
 XWDFileHeader xwdHdr;
 LPBYTE        xwdData = NULL;
 BITMAP        bmp;
 XColor*       xColor = NULL;
 CARD32        bytes_per_line;
 WORD          cClrBits;
 DWORD         dataSize;
 LPBITMAPINFO  pBmi = NULL;
 BYTE          bTmp;
 DWORD         dwBytesWritten;
 DWORD         dwColorSize = sizeof ( XColor ) * 256;
 HPALETTE      hOldPal;

 __try {

  if (  gDev -> IsPaletteDevice ()  ) {
  
   hOldPal = SelectPalette (   hDC, ( HPALETTE )(  gDev -> HPalette ()  ), FALSE   );
   RealizePalette ( hDC );
  
  }  // end if

  if (   !GetObject (  hBmp, sizeof ( BITMAP ), &bmp  )   ) __leave;

  cClrBits = ( WORD )( bmp.bmPlanes * bmp.bmBitsPixel );
  cClrBits = ( cClrBits <= 8 ) ? 8 : 32;

  bytes_per_line = bmp.bmWidth * ( cClrBits / CHAR_BIT );
  bytes_per_line += PAD( bytes_per_line );

  dataSize = bytes_per_line * bmp.bmHeight;

  pBmi = ( LPBITMAPINFO )MALLOC(
                          sizeof ( BITMAPINFO ) +
			 			  sizeof ( RGBQUAD ) * (  ( cClrBits == 8 ) ? 256 : 1  )
						 );

  if ( pBmi == NULL ) __leave;

  xwdData = ( LPBYTE )MALLOC( dataSize );

  if ( xwdData == NULL ) __leave;

  xColor = ( XColor* )MALLOC( dwColorSize );
  
  if ( xColor == NULL ) __leave;

  pBmi -> bmiHeader.biSize        =  sizeof ( BITMAPINFOHEADER );
  pBmi -> bmiHeader.biWidth	      =  bmp.bmWidth;
  pBmi -> bmiHeader.biHeight      = -bmp.bmHeight;
  pBmi -> bmiHeader.biPlanes      =  bmp.bmPlanes;
  pBmi -> bmiHeader.biBitCount    =  cClrBits;
  pBmi -> bmiHeader.biCompression =  BI_RGB;
  pBmi -> bmiHeader.biClrUsed     =  ( cClrBits == 8 ) ? 256 : 0;

  i = GetDIBits (
       hDC, hBmp, 0, bmp.bmHeight, xwdData, pBmi, DIB_RGB_COLORS
      );

  if ( i == 0 ) __leave;

  if ( cClrBits == 8 )

   for ( i = 0; i < 256; ++i ) {
   
   	xColor[ i ].pixel = i;
	xColor[ i ].red   = pBmi -> bmiColors[ i ].rgbRed   << 8;
	xColor[ i ].green = pBmi -> bmiColors[ i ].rgbGreen << 8;
	xColor[ i ].blue  = pBmi -> bmiColors[ i ].rgbBlue  << 8;
   
   }  // end for

  else

   for ( i = 0; i < 256; ++i ) {
   
   	xColor[ i ].pixel = i;
	xColor[ i ].red   = i;
	xColor[ i ].green = i;
	xColor[ i ].blue  = i;
   
   }  // end for

  xwdHdr.header_size      = sizeof ( XWDFileHeader );
  xwdHdr.file_version     = XWD_FILE_VERSION;
  xwdHdr.pixmap_format    = ZPixmap;
  xwdHdr.pixmap_depth     = ( cClrBits == 8 ) ? 8 : 24;
  xwdHdr.pixmap_width     = bmp.bmWidth;
  xwdHdr.pixmap_height    = bmp.bmHeight;
  xwdHdr.xoffset          = 0;
  xwdHdr.byte_order       = MSBFirst;
  xwdHdr.bitmap_unit      = sizeof ( LONG ) * CHAR_BIT;
  xwdHdr.bitmap_bit_order =	MSBFirst;
  xwdHdr.bitmap_pad       = xwdHdr.bitmap_unit;
  xwdHdr.bits_per_pixel   = cClrBits;
  xwdHdr.bytes_per_line   = bytes_per_line;
  xwdHdr.visual_class     = ( cClrBits == 8 ) ? PseudoColor : TrueColor;
  xwdHdr.red_mask		  = ( cClrBits == 8 ) ? 0 : 0xFF;
  xwdHdr.green_mask       = ( cClrBits == 8 ) ? 0 : ( 0xFF <<  8 );
  xwdHdr.blue_mask        = ( cClrBits == 8 ) ? 0 : ( 0xFF << 16 );
  xwdHdr.bits_per_rgb     = 8;
  xwdHdr.colormap_entries = 256;
  xwdHdr.ncolors          = 256;
  xwdHdr.window_width     = xwdHdr.pixmap_width;
  xwdHdr.window_height    = xwdHdr.pixmap_height;
  xwdHdr.window_x         = 0;
  xwdHdr.window_y         = 0;
  xwdHdr.window_bdrwidth  = 0;

  _swaplong (  ( char* )&xwdHdr, sizeof ( XWDFileHeader )  );

  for ( i = 0; i < 256; ++i ) {
  
   _swaplong  (  ( char* )&xColor[ i ].pixel, sizeof ( unsigned long  )  );
   _swapshort (  ( char* )&xColor[ i ].red,   sizeof ( unsigned short ) * 3  );
  
  }  // end for

  if ( cClrBits == 32 ) {

   for (  i = 0; i < dataSize; i += sizeof ( LONG )  ) {
   
   	bTmp             = xwdData[ i ];
	xwdData[ i ]     = xwdData[ i + 2 ];
	xwdData[ i + 2 ] = bTmp;
   
   }  // end for

   _swaplong (  ( char* )xwdData, dataSize );

  }  // end if

  if (  !WriteFile (
          hFile, ( PVOID )&xwdHdr, sizeof ( XWDFileHeader ), &dwBytesWritten, NULL
		 )
  ) __leave;

  if (  dwBytesWritten != sizeof ( XWDFileHeader )  ) __leave;

  if (  !WriteFile ( hFile, xColor, dwColorSize, &dwBytesWritten, NULL )  ) __leave;

  if (  dwBytesWritten != dwColorSize ) __leave;

  if (  !WriteFile ( hFile, xwdData, dataSize, &dwBytesWritten, NULL )  ) __leave;

  if (  dwBytesWritten != dataSize  ) __leave;

  retVal = I_SUCCESS;

 }  // end __try

 __finally {

  if ( xColor  != NULL ) FREE( xColor   );
  if ( xwdData != NULL ) FREE( xwdData  );
  if ( pBmi    != NULL ) FREE( pBmi     );

  if (  gDev -> IsPaletteDevice ()  )

   SelectPalette ( hDC, hOldPal, FALSE );

 }  // end __finally
 
 return retVal;           

}  // end writeXWD
//***//
//**************** Routines to process BMP file ***************************//
//***//
static HBITMAP loadBMP (  Handle( WNT_GraphicDevice )& gDev  ) {

 HBITMAP           retVal = NULL;
 PBITMAPFILEHEADER pBmfh;
 PBITMAPINFOHEADER pBmih;
 LPRGBQUAD         pRGB;
 PBYTE             pData;
 HPALETTE          hOldPal;
 WORD              bitCount;
 UINT              nColors;
 DWORD             dwWidth, dwHeight;
 BOOL              os2Flag;

 __try {

  pBmfh = ( PBITMAPFILEHEADER )lpvFile;
  pBmih = ( PBITMAPINFOHEADER )(  ( PBYTE )lpvFile + sizeof ( BITMAPFILEHEADER )  );

  if (  pBmih -> biSize == sizeof ( BITMAPCOREHEADER )  ) {  // OS/2 bitmap

   PBITMAPCOREHEADER pBmch = ( PBITMAPCOREHEADER )pBmih;

   bitCount = pBmch -> bcBitCount;
   nColors = ( bitCount < 16 ) ? ( 1 << bitCount ) : 0;

   pBmih = ( PBITMAPINFOHEADER )MALLOC(
                                 sizeof ( BITMAPINFO ) +
						         sizeof ( RGBQUAD ) * nColors
					            );

   if ( pBmih == NULL ) __leave;

   pBmih -> biSize        = sizeof ( BITMAPINFOHEADER );
   pBmih -> biWidth       = pBmch -> bcWidth;
   pBmih -> biHeight      = pBmch -> bcHeight;
   pBmih -> biPlanes      = 1;
   pBmih -> biBitCount    = bitCount;
   pBmih -> biCompression = BI_RGB;

   for ( UINT i = 0; i < nColors; ++i ) {
   
   	(  ( PBITMAPINFO )pBmih  ) -> bmiColors[ i ].rgbRed =
   	 (  ( PBITMAPCOREINFO )pBmch  ) -> bmciColors[ i ].rgbtRed;
   	(  ( PBITMAPINFO )pBmih  ) -> bmiColors[ i ].rgbGreen =
   	 (  ( PBITMAPCOREINFO )pBmch  ) -> bmciColors[ i ].rgbtGreen;
   	(  ( PBITMAPINFO )pBmih  ) -> bmiColors[ i ].rgbBlue =
   	 (  ( PBITMAPCOREINFO )pBmch  ) -> bmciColors[ i ].rgbtBlue;
   
   }  // end for

   pRGB     = (  ( PBITMAPINFO )pBmih  ) -> bmiColors;
   os2Flag  = TRUE;

  } else {  // Windows DIB

   pRGB     = ( LPRGBQUAD )(  ( PBYTE )pBmih + pBmih -> biSize  );
   os2Flag  = FALSE;

  }  // end else

  bitCount = pBmih -> biBitCount;
  dwWidth  = pBmih -> biWidth;
  dwHeight = pBmih -> biHeight;
  pData    = ( PBYTE )(  ( PBYTE )lpvFile + pBmfh -> bfOffBits  );

  if (  gDev -> IsPaletteDevice ()  ) {
  
   _alloc_colors ( pData, dwWidth, dwHeight, bitCount, pRGB, gDev );

   hOldPal = SelectPalette (  hDC, ( HPALETTE )(  gDev -> HPalette ()  ), FALSE  );
   RealizePalette ( hDC );

  }  // end if

  retVal = CreateDIBitmap (
            hDC, pBmih, CBM_INIT, pData, ( PBITMAPINFO )pBmih, DIB_RGB_COLORS
 		   );

  if (  gDev -> IsPaletteDevice ()  )

   SelectPalette ( hDC, hOldPal, FALSE );

 }  // end __try

 __finally {
 
  if ( os2Flag && pBmih ) FREE( pBmih );
 
 }  // end __finally

  return retVal;

}  // end  loadBMP

static int writeBMP ( HANDLE hFile, HBITMAP hBmp, Handle( WNT_GraphicDevice )& gDev ) {
           
 int               i, retVal = I_ERROR;
 BITMAP            bmp;
 BITMAPFILEHEADER  bFh;
 PBITMAPINFO       pBih = NULL;
 WORD              cClrBits;
 DWORD             dwBytesWritten;
 DWORD             imageSize;
 DWORD             hdrSize;
 LONG              bytesPerLine;
 LPBYTE            lpBits;
 HPALETTE          hOldPal;
 DWORD             nColors;

 __try {
 
  if (  !GetObject ( hBmp, sizeof ( BITMAP ), &bmp )  ) __leave;

  cClrBits = ( WORD )( bmp.bmPlanes * bmp.bmBitsPixel );

  if ( cClrBits <=4 ) {

   cClrBits     = 4;
   bytesPerLine = bmp.bmWidth >> 1;

  } else if ( cClrBits <= 8 ) {

   cClrBits     = 8;
   bytesPerLine = bmp.bmWidth;

  } else if ( cClrBits <= 16 ) {

   cClrBits     = 16;
   bytesPerLine = bmp.bmWidth * sizeof ( WORD );

  } else if ( cClrBits <= 24 ) {

   cClrBits     = 24;
   bytesPerLine = bmp.bmWidth * 3;

  } else {

   cClrBits     = 32;
   bytesPerLine	= bmp.bmWidth * sizeof ( LONG );

  }  // end else

  nColors = ( cClrBits < 16 ) ? ( 1 << cClrBits ) : 0;

  pBih = ( PBITMAPINFO )MALLOC(
                         sizeof ( BITMAPINFO ) + sizeof ( RGBQUAD ) * nColors
						);

  if ( pBih == NULL ) __leave;

  bytesPerLine += PAD( bytesPerLine );
  imageSize     = bytesPerLine * bmp.bmHeight;

  lpBits = ( LPBYTE )MALLOC( imageSize );

  if ( lpBits == NULL ) __leave;

  pBih -> bmiHeader.biSize        =  sizeof ( BITMAPINFOHEADER );
  pBih -> bmiHeader.biWidth	      =  bmp.bmWidth;
  pBih -> bmiHeader.biHeight      =  bmp.bmHeight;
  pBih -> bmiHeader.biPlanes      =  1;
  pBih -> bmiHeader.biBitCount    =  cClrBits;
  pBih -> bmiHeader.biCompression =  BI_RGB;

  if (  WINNT35X()  ) pBih -> bmiHeader.biHeight = -pBih -> bmiHeader.biHeight;

  if (  gDev -> IsPaletteDevice ()  ) {
  
   hOldPal = SelectPalette ( hDC, ( HPALETTE )(  gDev -> HPalette ()  ), FALSE );
   RealizePalette ( hDC );
  
  }  // end if

  i = GetDIBits ( hDC, hBmp, 0, bmp.bmHeight, lpBits, pBih, DIB_RGB_COLORS );

  if (  gDev -> IsPaletteDevice ()  )

   SelectPalette ( hDC, hOldPal, FALSE );

  if ( i == 0 ) __leave;

  bFh.bfType      = 0x4D42;
  bFh.bfSize      = sizeof ( BITMAPFILEHEADER ) +
                    pBih -> bmiHeader.biSize +
                    sizeof ( RGBQUAD ) * nColors + imageSize;
  bFh.bfReserved1 = 0;
  bFh.bfReserved2 = 0;
  bFh.bfOffBits   =	sizeof ( BITMAPFILEHEADER ) +
                    pBih -> bmiHeader.biSize + sizeof ( RGBQUAD ) * nColors;

  if (  !WriteFile (
          hFile, &bFh, sizeof ( BITMAPFILEHEADER ), &dwBytesWritten, NULL
		 )
  ) __leave;

  if (  dwBytesWritten != sizeof ( BITMAPFILEHEADER )  ) __leave;

  hdrSize = pBih -> bmiHeader.biSize + sizeof ( RGBQUAD ) * nColors;

  if (  !WriteFile ( hFile, pBih, hdrSize, &dwBytesWritten, NULL )  ) __leave;

  if ( dwBytesWritten != hdrSize ) __leave;

  if (  !WriteFile ( hFile, lpBits, imageSize, &dwBytesWritten, NULL )  ) __leave;

  if ( dwBytesWritten != imageSize ) __leave;

  retVal = I_SUCCESS;

 }  // end __try

 __finally {
  
  if ( lpBits != NULL ) FREE( lpBits );
  if ( pBih   != NULL ) FREE( pBih   );

 }  // end __finally

 return retVal;           
           
}  // end writeBMP
//***//
//**************** Routines to process GIF file ***************************//
//***//
#define NEXT_BYTE      ( *ptr++ )
#define IMAGESEP       0x2C
#define INTERLACE_MASK 0x40
#define COLORMAP_MASK  0x80
#define COMMENT_BYTE   0x21
			   
static UINT        x, y, pass, bytesPerLine, imgWidth, imgHeight;
static PBYTE       pData;
static PBITMAPINFO pBmi;
static BOOL        isInterlace;

static void __fastcall _add_pixel ( UINT );
//***//
static HBITMAP loadGIF (  Handle( WNT_GraphicDevice )& gDev  ) {

 int      i, nColors;
 HBITMAP  retVal = NULL;
 UINT     Bits, BitMask, CodeSize, ClearCode, EOFCode, FreeCode,
          InitCodeSize, MaxCode, ReadMask, FirstFree, OutCount, BitOffset,
          ByteOffset, Code, CurCode, OldCode, FinChar, InCode;
 PUINT    OutCode, Prefix, Suffix;
 BYTE     byte, byte1;
 PBYTE    rasterPtr, ptr1, ptr = (  ( PBYTE )lpvFile  ) + 10;
 BOOL     hasColormap;
 HPALETTE hOldPal;
 DWORD    dataSize;

#ifdef BUC60837
  pBmi = NULL;
  rasterPtr = pData = NULL;
  Suffix = Prefix = OutCode = NULL;
#endif

 __try {
 
#ifdef BUC60837
  OutCode = ( PUINT )MALLOC(  1026 * sizeof ( UINT )  );
#else
  pBmi      = NULL;
  rasterPtr = pData = NULL;
  OutCode = ( PUINT )MALLOC(  1025 * sizeof ( UINT )  );
#endif
  Prefix  = ( PUINT )MALLOC(  4096 * sizeof ( UINT )  );
  Suffix  = ( PUINT )MALLOC(  4096 * sizeof ( UINT )  );

  if ( OutCode == NULL || Prefix == NULL || Suffix == NULL ) __leave;

  byte = NEXT_BYTE;

  hasColormap = ( byte & COLORMAP_MASK ) ? TRUE : FALSE;
  Bits        = ( byte & 0x07 ) + 1;
  nColors     = 1 << Bits;
  BitMask     = nColors - 1;
  ++ptr;

  if ( NEXT_BYTE ) __leave;

  pBmi = ( PBITMAPINFO )MALLOC(
                         sizeof ( BITMAPINFO ) + sizeof ( RGBQUAD ) * 256
					    );
   
  if ( pBmi == NULL ) __leave;
   
  if ( hasColormap ) {

   for ( i = 0; i < nColors; ++i ) {
   
   	pBmi -> bmiColors[ i ].rgbRed   = NEXT_BYTE;
	pBmi -> bmiColors[ i ].rgbGreen = NEXT_BYTE;
	pBmi -> bmiColors[ i ].rgbBlue  = NEXT_BYTE;
   
   }  // end for

  }  // end if

  while ( *ptr == COMMENT_BYTE ) {
  
   ptr += 2;

   while ( *ptr ) ( ptr += *ptr )++;

   NEXT_BYTE;
  
  }  // end while

  if ( NEXT_BYTE != IMAGESEP ) __leave;

  rasterPtr = ( PBYTE )MALLOC( dwFileSize );

  if ( rasterPtr == NULL ) __leave;

  ptr += 4;

  byte      = NEXT_BYTE;
  imgWidth  = byte + 0x100 * NEXT_BYTE;
  byte      = NEXT_BYTE;
  imgHeight	= byte + 0x100 * NEXT_BYTE;

  isInterlace = ( NEXT_BYTE & INTERLACE_MASK ) ? TRUE : FALSE;

  CodeSize  = NEXT_BYTE;
  ClearCode = 1 << CodeSize;
  EOFCode   = ClearCode + 1;
  FreeCode  = FirstFree = EOFCode + 1;

  ++CodeSize;

  InitCodeSize = CodeSize;
  MaxCode      = 1 << CodeSize;
  ReadMask     = MaxCode - 1;

  ptr1 = rasterPtr;

  do {
  
   byte = byte1 = NEXT_BYTE;

   while ( byte != 0 ) {
   
    *ptr1++ = NEXT_BYTE;
	--byte;

   }  // end while

   if (  ( UINT )( ptr1 - rasterPtr ) > dwFileSize  ) __leave;  // corrupt file - unblock
  
  } while ( byte1 );

  bytesPerLine = imgWidth + PAD( imgWidth );
  dataSize     = bytesPerLine * imgHeight;

  pData = ( PBYTE )MALLOC( dataSize );

  if ( pData == NULL ) __leave;

  x = y = pass = OutCount = BitOffset = ByteOffset = 0;

  Code = rasterPtr[ ByteOffset ] + ( rasterPtr[ ByteOffset + 1 ] << 8 );

  if ( CodeSize >= 8 ) Code += ( rasterPtr[ ByteOffset + 2 ] << 16 );

  Code >>= ( BitOffset % 8 );
  BitOffset += CodeSize;
  Code      &= ReadMask;

  while ( Code != EOFCode ) {
  
   if ( Code == ClearCode ) {
   
   	CodeSize   = InitCodeSize;
	MaxCode    = 1 << CodeSize;
	ReadMask   = MaxCode - 1;
	FreeCode   = FirstFree;
	ByteOffset = BitOffset >> 3;
#ifdef BUC60837
      if( ByteOffset > (dwFileSize-3) ) break;
#endif
	Code       = rasterPtr[ ByteOffset ] + ( rasterPtr[ ByteOffset + 1 ] << 8 );

      if ( CodeSize >= 8 ) Code += ( rasterPtr[ ByteOffset + 2 ] << 16 );

	Code      >>= ( BitOffset % 8 );
	BitOffset +=  CodeSize;
	Code      &=  ReadMask;

	CurCode = OldCode = Code;
	FinChar = CurCode & BitMask;

	_add_pixel ( FinChar );
   
   } else {
   
   	CurCode = InCode = Code;

	if ( CurCode >= FreeCode ) {
	
	 CurCode = OldCode;
	 OutCode[ OutCount++ ] = FinChar;

	}  // end if

	while ( CurCode > BitMask ) {
	
 
	 if ( OutCount > 1024 ) 
#ifdef BUC60837
					break;
#else
					__leave;
#endif
	 OutCode[ OutCount++ ] = Suffix[ CurCode ];
	 CurCode               = Prefix[ CurCode ];
	
	}  // end while

	FinChar = CurCode & BitMask;
	OutCode[ OutCount++ ] = FinChar;

	for ( i = OutCount - 1; i >= 0; --i ) _add_pixel ( OutCode[ i ] );

	OutCount = 0;
	Prefix[ FreeCode ] = OldCode;
	Suffix[ FreeCode ] = FinChar;
	OldCode            = InCode;
	++FreeCode;

	if ( FreeCode >= MaxCode ) {
	
     if ( CodeSize < 12 ) {
     
      ++CodeSize;
	  MaxCode <<= 1;
	  ReadMask = ( 1 << CodeSize ) - 1;
     
     } // end if
	
	}  // end if
   
   }  // end else

   ByteOffset = BitOffset >> 3;
#ifdef BUC60837
      if( ByteOffset > (dwFileSize-3) ) break;
#endif
   Code = rasterPtr[ ByteOffset ] + ( rasterPtr[ ByteOffset + 1 ] << 8 );

   if ( CodeSize >= 8 ) Code += ( rasterPtr[ ByteOffset + 2 ] << 16 );

   Code      >>= ( BitOffset % 8 );
   BitOffset +=	 CodeSize;
   Code      &=  ReadMask;
  
  }  // end while

  pBmi -> bmiHeader.biSize        =  sizeof ( BITMAPINFOHEADER );
  pBmi -> bmiHeader.biWidth       =  imgWidth;
  pBmi -> bmiHeader.biHeight      = -( INT )imgHeight;
  pBmi -> bmiHeader.biPlanes      =  1;
  pBmi -> bmiHeader.biBitCount    =  8;
  pBmi -> bmiHeader.biCompression =  BI_RGB;

  if (  gDev -> IsPaletteDevice ()  ) {
  
   _alloc_colors (
    pData, imgWidth, imgHeight, PIXEL8, pBmi -> bmiColors, gDev
   );

   hOldPal = SelectPalette ( hDC, ( HPALETTE )(  gDev -> HPalette ()  ), FALSE );
   RealizePalette ( hDC );
  
  }  // end if

  retVal = CreateDIBitmap (
            hDC, ( PBITMAPINFOHEADER )pBmi, CBM_INIT, pData, pBmi, DIB_RGB_COLORS
		   );

  if (  gDev -> IsPaletteDevice ()  )

   SelectPalette ( hDC, hOldPal, FALSE );

 }  // end __try

 __finally {

  if ( pData     != NULL ) FREE( pData     );
  if ( rasterPtr != NULL ) FREE( rasterPtr );
  if ( pBmi      != NULL ) FREE( pBmi      ); 
  if ( Suffix    != NULL ) FREE( Suffix    );
  if ( Prefix    != NULL ) FREE( Prefix    );
  if ( OutCode   != NULL ) FREE( OutCode   );
 
 }  // end __finally

 return retVal;

}  // end loadGIF

typedef struct _screen_descr {

				char gifID[ 6 ];
				WORD scrnWidth;
				WORD scrnHeight;
				BYTE scrnFlag;

               } SCREEN_DESCR;

typedef struct _image_descr {

				WORD imgX;
				WORD imgY;
				WORD imgWidth;
				WORD imgHeight;
				BYTE imgFlag;

               } IMAGE_DESCR;

static int __fastcall _lzw_encode ( PBYTE, int, int, int );

static HANDLE hOut;

static int writeGIF (
            HANDLE hFile, HBITMAP hBmp, Handle( WNT_GraphicDevice )& gDev
           ) {
           
 int         i, retVal = I_ERROR;
 BITMAP      bmp;
 PBITMAPINFO pBih;
 LONG        bytesPerLine, nColors;
 WORD        bCount;
 DWORD       imageSize;
 BYTE        byte, color[ 3 ];
 PBYTE       pBits;
 WORD        word;
 HPALETTE    hOldPal;
 DWORD       dwSize, dwBytesWritten;
 
 SCREEN_DESCR sd;
 IMAGE_DESCR  id;

 Standard_Integer devWidth, devHeight;

 __try {
 
  if (  !GetObject ( hBmp, sizeof ( BITMAP ), &bmp )  ) __leave;

  if ( bmp.bmBitsPixel <= 8 ) {

   bCount        = 8;
   bytesPerLine  = bmp.bmWidth;

  } else {

   bCount        = 24;
   bytesPerLine  = bmp.bmWidth * sizeof ( LONG );

  }  // end else

  bytesPerLine += PAD( bytesPerLine );
  nColors       = bmp.bmBitsPixel <= 8 ? 256 : 0;

  pBih = ( PBITMAPINFO )MALLOC(
                         sizeof ( BITMAPINFO ) + sizeof ( RGBQUAD ) * 256
						);

  if ( pBih == NULL ) __leave;

  imageSize = bytesPerLine * bmp.bmHeight;

  pBits = ( LPBYTE )MALLOC( imageSize );

  if ( pBits == NULL ) __leave;

  pBih -> bmiHeader.biSize        =  sizeof ( BITMAPINFOHEADER );
  pBih -> bmiHeader.biWidth	      =  bmp.bmWidth;
  pBih -> bmiHeader.biHeight      = -bmp.bmHeight;
  pBih -> bmiHeader.biPlanes      =  1;
  pBih -> bmiHeader.biBitCount    =  bCount;
  pBih -> bmiHeader.biCompression =  BI_RGB;

  if (  gDev -> IsPaletteDevice ()  ) {
  
   hOldPal = SelectPalette ( hDC, ( HPALETTE )(  gDev -> HPalette ()  ), FALSE );
   RealizePalette ( hDC );
  
  }  // end if

  i = GetDIBits ( hDC, hBmp, 0, bmp.bmHeight, pBits, pBih, DIB_RGB_COLORS );

  if (  gDev -> IsPaletteDevice ()  )

   SelectPalette ( hDC, hOldPal, FALSE );

  if ( i == 0 ) __leave;

  gDev -> DisplaySize ( devWidth, devHeight );

  CopyMemory ( sd.gifID, "GIF87a", 6 );
  sd.scrnWidth  = devWidth;
  sd.scrnHeight	= devHeight;
  sd.scrnFlag   = 0x80 | (  ( 7 << 4 ) & 0x70  ) | 0x07;

  id.imgX      = 0;
  id.imgY      = 0;
  id.imgWidth  = ( WORD )bmp.bmWidth;
  id.imgHeight = ( WORD )bmp.bmHeight;
  id.imgFlag   = 0x07;

  dwSize = 11;

  if (  !WriteFile ( hFile, &sd, dwSize, &dwBytesWritten, NULL )  ) __leave;
  if ( dwBytesWritten != dwSize ) __leave;

  word = 0;

  if (  !WriteFile ( hFile, &word, 2, &dwBytesWritten, NULL )  ) __leave;
  if ( dwBytesWritten != 2 ) __leave;

  if ( bCount == 24 ) {

   BOOL  retVal;
   PBYTE pBits8 = ( PBYTE )MALLOC( bmp.bmWidth * bmp.bmHeight );

   if ( pBits8 != NULL )

    retVal = _convert24to8 (
              pBih -> bmiColors, pBits, pBits8,
              bmp.bmWidth, bmp.bmHeight
             );

   else __leave;

   if ( !retVal ) {

    FREE( pBits8 );
    __leave;

   }  // end if

   FREE( pBits );
   pBits = pBits8;

  }  // end if

  for ( i = 0; i < 256; ++i ) {

   color[ 0 ] = pBih -> bmiColors[ i ].rgbRed;
   color[ 1 ] = pBih -> bmiColors[ i ].rgbGreen;
   color[ 2 ] = pBih -> bmiColors[ i ].rgbBlue;
  
   if (  !WriteFile (
           hFile, color, 3, &dwBytesWritten, NULL
          )
   ) __leave;

   if ( dwBytesWritten != 3 ) __leave;
  
  }  // end for

  byte = IMAGESEP;

  if (  !WriteFile ( hFile, &byte, 1, &dwBytesWritten, NULL )  ) __leave;
  if ( dwBytesWritten != 1 ) __leave;

  dwSize = 9;

  if (  !WriteFile ( hFile, &id, dwSize, &dwBytesWritten, NULL )  ) __leave;
  if ( dwBytesWritten != dwSize ) __leave;

  hOut          = hFile;
  bytesPerLine  = bmp.bmWidth;

  retVal = _lzw_encode ( pBits, bmp.bmWidth, bmp.bmHeight, bytesPerLine );
 
 }  // end __try

 __finally {
 
  if ( pBits != NULL ) FREE( pBits );
  if ( pBih  != NULL ) FREE( pBih  );
 
 }  // end __finally

 return retVal;           
           
}  // end writeGIF

static void __fastcall _add_pixel ( UINT idx ) {

 if ( y < imgHeight )

  *( pData + y * bytesPerLine + x ) = ( BYTE )idx;

 if ( ++x == imgWidth ) {
 
  x = 0;
  
  if ( !isInterlace )
  
   ++y; 

  else {
  
   switch ( pass ) {
   
   	case 0:

	 y += 8;

	 if ( y >= imgHeight ) ++pass, y = 4;

	break;

	case 1:

	 y += 8;

	 if ( y >= imgHeight ) ++pass, y = 2;

	break;

	case 2:

	 y += 4;

	 if ( y >= imgHeight ) ++pass, y = 1;

	break;

	case 3:

	 y += 2;
   
   }  // end switch
  
  }  // end else
 
 }  // end if

}  // end _add_pixel

#define NBITS     12
#define TBL_SIZE  5021
#define MAX_CODE  (  ( 1 << NBITS ) - 1  )
#define BUFF_SIZE 255
#define UNUSED    -1

typedef struct _lzw_dict {

				int code;
				int prnt;
				BYTE byte;

               } LZWDict;

static LZWDict* dict;
static PBYTE	OutBuff;

static int startBits, codeBits, nextCode, bumpCode, rack, mask, putIdx,
           ClearCode, EOFCode, FreeCode;

static void            _init_dict  ( void );
static int  __fastcall _find_child ( int, int );
static BOOL __fastcall _put_bits   ( ULONG, UINT );
static BOOL            _flush_bits ( void );

static int __fastcall _lzw_encode ( PBYTE pData, int width, int height, int inc ) {

 int   i, x, y, retVal = I_ERROR;
 BYTE  byte;
 PBYTE pLine;
 int   strCode, chr;
 DWORD dwBytesWritten;

 __try {
 
  OutBuff = NULL;

  dict = ( LZWDict* )MALLOC(  sizeof ( LZWDict ) * TBL_SIZE  );

  if ( dict == NULL ) __leave;

  OutBuff = ( PBYTE )MALLOC( BUFF_SIZE );

  if ( OutBuff == NULL ) __leave;

  x     = y = 0;
  pLine = pData;

  OutBuff[ 0 ] = 0;
  putIdx       = 1;
  mask         = 0x01;
  rack         = 0;
  startBits    = 8;
  ClearCode    = 1 << startBits;
  EOFCode      = ClearCode + 1;
  FreeCode     = EOFCode + 1;

  _init_dict ();

  byte = startBits;

  if (  !WriteFile ( hOut, &byte, 1, &dwBytesWritten, NULL )  ) __leave;
  if ( dwBytesWritten != 1 ) __leave;

  strCode = pLine[ x++ ];

  if (   !_put_bits (  ( ULONG )ClearCode, codeBits  )   ) __leave;

  while ( y < height ) {
  
   chr = pLine[ x++ ];
   
   i = _find_child ( strCode, chr );

   if ( dict[ i ].code != UNUSED )

    strCode = dict[ i ].code;

   else {
   
    dict[ i ].code = nextCode++;
	dict[ i ].prnt = strCode;
	dict[ i ].byte = chr;

	if (   !_put_bits (  ( ULONG )strCode, codeBits  )   ) __leave;

	strCode = chr;

	if ( nextCode > MAX_CODE ) {
	
	 if (   !_put_bits (  ( ULONG )ClearCode, codeBits  )   ) __leave;

	 _init_dict ();
	
	} else if ( nextCode > bumpCode ) {
	
	 ++codeBits;
	 bumpCode <<= 1;
	
	}  // end if
   
   }  // end else

   if ( x == width ) {
   
   	x = 0;
	++y;
	pLine += inc;
   
   }  // end if
  
  }  // end while

  if (  !_put_bits (  ( ULONG )strCode, codeBits )  ) __leave;
  if (  !_put_bits (  ( ULONG )EOFCode, codeBits )  ) __leave;
  if (  !_flush_bits ()                             ) __leave;

  retVal = I_SUCCESS;
 
 }  // end __try

 __finally {
 
  if ( OutBuff != NULL ) FREE( OutBuff );
  if ( dict    != NULL ) FREE( dict    ); 
 
 }  // end __finally

 return retVal;

}  // end _lzw_encode

static void _init_dict ( void ) {

 FillMemory (  dict, sizeof ( LZWDict ) * TBL_SIZE, UNUSED  );

 nextCode = FreeCode;
 codeBits = startBits + 1;
 bumpCode = 1 << codeBits;

}  // end _init_dict

static int __fastcall _find_child ( int prntCode, int chr ) {

 int idx, offset;

 idx = (  chr << ( NBITS - 8 )  ) ^ prntCode;

 offset = idx ? TBL_SIZE - idx : 1;

 while ( TRUE ) {
 
  if ( dict[ idx ].code == UNUSED ||
       dict[ idx ].prnt == prntCode && dict[ idx ].byte == ( BYTE )chr
  )

   return idx;

  idx = ( idx >= offset ) ? idx - offset : idx + TBL_SIZE - offset;
 
 }  // end while

}  // end _find_child

static BOOL __fastcall _put_bits ( ULONG code, UINT nBits ) {

 BOOL  retVal = TRUE;
 ULONG msk;
 DWORD dwBytesWritten;

 msk = 1UL;

 while (  msk != ( ULONG )( 1 << nBits )  ) {
 
  if ( msk & code )

   rack |= mask;

  mask <<= 1;

  if (  ( mask & 0xFF ) == 0  ) {
  
   OutBuff[ putIdx++ ] = rack;
   ++OutBuff[ 0 ];

   if ( putIdx == BUFF_SIZE ) {
   
    if (  !WriteFile ( hOut, OutBuff, BUFF_SIZE, &dwBytesWritten, NULL )  ) {
    
     retVal = FALSE;

	 break;
    
    }  // end if

    if ( dwBytesWritten != BUFF_SIZE ) {
    
     retVal = FALSE;

	 break;
    
    }  // end if
   
   	putIdx = 1;
	OutBuff[ 0 ] = 0;

   }  // end if

   rack = 0;
   mask = 0x01;
  
  }  // end if

  msk <<= 1;
 
 }  // end while

 return retVal;

}  // end _put_bits

static BOOL _flush_bits ( void ) {

 BOOL  retVal = TRUE;
 BYTE  byte;
 DWORD dwBytesWritten;

 if ( mask != 0x01 ) {
 
  OutBuff[ putIdx++ ] = rack;
  ++OutBuff[ 0 ];
 
 }  // end if

 if ( putIdx != 1 ) {
 
  if (  !WriteFile ( hOut, OutBuff, putIdx, &dwBytesWritten, NULL )  )
    
   retVal = FALSE;

  if (  retVal && dwBytesWritten != ( DWORD )putIdx  )
    
   retVal = FALSE;
 
 }  // end if

 if ( retVal ) {
 
  byte = 0;

  if (  !WriteFile ( hOut, &byte, 1, &dwBytesWritten, NULL )  )
    
   retVal = FALSE;

  if (  retVal && dwBytesWritten != 1 )
    
   retVal = FALSE;
 
 }  // end if

 return retVal;

}  // end _flush_bits
//***//
//*************************************************************************//
//***//
static void __fastcall _alloc_colors (
                        PVOID data, int width, int height, int size, LPRGBQUAD colors,
                        Handle( WNT_GraphicDevice )& gDev
                       ) {

 int              i, j, k, bytes_per_line;
 Standard_Integer r, g, b;
 PBYTE            pLine;

 if ( height < 0 ) height = -height;
            
 switch ( size ) {

  case PIXEL4: {
  
   PBYTE pixels;
   int   l, idx, nColors;

   pixels = ( PBYTE )MALLOC( 0x10 );

   if ( pixels != NULL ) {

    pLine = ( PBYTE )data;

	bytes_per_line  = width >> 1;
	bytes_per_line += PAD( bytes_per_line );

	nColors = gDev -> NumColors ();

	for ( i = k = 0; i < height; ++i ) {
	
	 for ( j = l = 0; j < width; ++j ) {
	 
	  idx = pLine[ l ] & 0x0F;

	  if ( !pixels[ idx ] ) {
retry_4:
	   r = ( Standard_Integer )( colors[ idx ].rgbRed   );
	   g = ( Standard_Integer )( colors[ idx ].rgbGreen );
	   b = ( Standard_Integer )( colors[ idx ].rgbBlue  );

	   gDev -> SetColor (  ( r << 16 ) | ( g << 8 ) | b  );

	   pixels[ idx ] = TRUE;

	   if ( ++k > nColors )

	    goto end_4;
	  
	  } else {
	  
	   idx = ( pLine[ l++ ] >> 4 ) & 0x0F;

	   if ( !pixels[ idx ] )

	    goto retry_4;
	  
	  }  // end else
	 
	 }  // end for ( j . . . )

	 pLine += bytes_per_line;

	}  // end for ( i . . . )
end_4:
   	FREE( pixels );

   }  // end if
  
  }  // PIXEL4
 
  break;

  case PIXEL8: {
  
   int   idx, nColors;
   PBYTE pixels;

   pixels = ( PBYTE )MALLOC( 0x100 );

   if ( pixels != NULL ) {

    pLine = ( PBYTE )data;

	bytes_per_line = width + PAD( width );

	nColors = gDev -> NumColors ();

	for ( i = k = 0; i < height; ++i ) {
	
	 for ( j = 0; j < width; ++j ) {
	 
	  idx = pLine[ j ];

      if ( pixels[ idx ] ) continue;

	  r = ( Standard_Integer )( colors[ idx ].rgbRed   );
	  g = ( Standard_Integer )( colors[ idx ].rgbGreen );
	  b = ( Standard_Integer )( colors[ idx ].rgbBlue  );

	  gDev -> SetColor (  ( r << 16 ) | ( g << 8 ) | b  );

	  pixels[ idx ] = TRUE;

      if ( ++k > nColors ) goto end_8;
	 
	 }  // end for ( j . . . )

	 pLine += bytes_per_line;
	
	}  // end for ( i . . . )
end_8:
   	FREE( pixels );

   }  // end if
  
  }  // PIXEL8

  break;

  case PIXEL16: {

   PWORD pixels, hPixels, pData;
   WORD  pix, hPix, mask = 0xFF, rmask = 0xFFFF, mult;
   DWORD dataSize;

   pixels  = ( PWORD )MALLOC(  0x100 * sizeof ( WORD )  );
   hPixels = ( PWORD )MALLOC(  0x100 * sizeof ( WORD )  );

   if ( pixels != NULL && hPixels != NULL ) {

    FillMemory (  ( PVOID )pixels,  0x100 * sizeof ( WORD ), ~0  );
    FillMemory (  ( PVOID )hPixels, 0x100 * sizeof ( WORD ), ~0  );

    pData = ( PWORD )data;

	bytes_per_line  = width * sizeof ( WORD );
	bytes_per_line += PAD( bytes_per_line );
	dataSize        = bytes_per_line * height;

	mult  = ( WORD )(  dataSize / sizeof ( WORD ) / RAND_MAX  );

	if ( mult == 0 ) {

	 mult  = 1;
	 rmask = ( WORD )(  dataSize / sizeof ( WORD ) - 1  );

	}  // end if

    for ( i = j = 0, k = gDev -> NumColors ();
          i < ( int )(  dataSize / sizeof ( WORD )  );
          ++i
    ) {

     pix  = pData[ (  rand () * mult  ) & rmask ];
	 hPix = (  ( pix >> 8 ) ^ pix  ) & mask;

	 if (  pixels[ hPix ] == ~0 || hPixels[ hPix ] != pix  ) {
		 
	  gDev -> SetColor (
	           (  ( pix & 0x1F   ) << 3  ) |
	           (  ( pix & 0x3E0  ) << 6  ) |
	           (  ( pix & 0x7C00 ) << 9  )
	          ); 

	  if ( ++j > k ) break;

	   hPixels[ hPix ] = pixels[ hPix ] = pix;

	 }  // end if
		 
    }  // end for

	FREE( hPixels );
	FREE( pixels  );

   }  // end if

  }  // PIXEL16
  
  break;

  case PIXEL24: {
  
   PLONG    pixels, hPixels;
   PTRIPLET	pData;
   LONG     pix, hPix, mask = 0x0FFF, rmask = 0xFFFFFFFF, mult;
   DWORD    dataSize;

   pixels  = ( PLONG )MALLOC(  0x1000 * sizeof ( LONG )  );
   hPixels = ( PLONG )MALLOC(  0x1000 * sizeof ( LONG )  );

   if ( pixels != NULL && hPixels != NULL ) {

    FillMemory (  ( PVOID )pixels,  0x1000 * sizeof ( LONG ), ~0  );
    FillMemory (  ( PVOID )hPixels, 0x1000 * sizeof ( LONG ), ~0  );

	pData = ( PTRIPLET )data;

	bytes_per_line  = width * sizeof ( TRIPLET );
	bytes_per_line += PAD( bytes_per_line );
	dataSize        = bytes_per_line * height;

	mult  = dataSize / sizeof ( TRIPLET ) / RAND_MAX;

	if ( mult == 0 ) {

	 mult  = 1;
	 rmask = dataSize / sizeof ( TRIPLET ) - 1;

	}  // end if

    for ( i = j = 0, k = gDev -> NumColors ();
          i < ( int )(  dataSize / sizeof ( TRIPLET )  );
          ++i
    ) {

	 pix = (  *( PLONG )( pData[ (  rand () * mult  ) & rmask ].pixel )  ) & 0x00FFFFFF;
	 hPix = (  ( pix >> 12 ) ^ pix  ) & mask;

	 if (  pixels[ hPix ] == ~0 || hPixels[ hPix ] != pix  ) {
		 
	  gDev -> SetColor ( pix );

	  if ( ++j > k ) break;

	  hPixels[ hPix ] = pixels[ hPix ] = pix;

	 }  // end if
		 
    }  // end for

	FREE( hPixels );
	FREE( pixels  );

   }  // end if
  
  }  // PIXEL24

  break;

  case PIXEL32: {

   PLONG pixels, hPixels, pData;
   LONG  pix, hPix, mask = 0x0FFF, rmask = 0xFFFFFFFF, mult;
   DWORD dataSize;

   pixels  = ( PLONG )MALLOC(  0x1000 * sizeof ( LONG )  );
   hPixels = ( PLONG )MALLOC(  0x1000 * sizeof ( LONG )  );

   if ( pixels != NULL && hPixels != NULL ) {

    FillMemory (  ( PVOID )pixels,  0x1000 * sizeof ( LONG ), ~0  );
    FillMemory (  ( PVOID )hPixels, 0x1000 * sizeof ( LONG ), ~0  );

	pData = ( PLONG )data;

	bytes_per_line  = width * sizeof ( LONG );
	bytes_per_line += PAD( bytes_per_line );
	dataSize        = bytes_per_line * height;

	mult  = dataSize / sizeof ( LONG ) / RAND_MAX;

	if ( mult == 0 ) {

	 mult  = 1;
	 rmask = dataSize / sizeof ( LONG ) - 1;

	}  // end if

    for ( i = j = 0, k = gDev -> NumColors ();
          i < ( int )(  dataSize / sizeof ( LONG )  );
          ++i
    ) {

	 pix = pData[ (  rand () * mult  ) & rmask ];
	 hPix = (  ( pix >> 12 ) ^ pix  ) & mask;

	 if (  pixels[ hPix ] == ~0 || hPixels[ hPix ] != pix  ) {
		 
	  gDev -> SetColor ( pix );

	  if ( ++j > k ) break;

	  hPixels[ hPix ] = pixels[ hPix ] = pix;

	 }  // end if
		 
    }  // end for

	FREE( hPixels );
	FREE( pixels  );

   }  // end if

  }  // PIXEL32

 }  // end switch
                       
}  // end _alloc_colors

_init :: _init () {

 TCHAR cimgType[ 17 ];

 WNT_osVer.dwOSVersionInfoSize = sizeof ( OSVERSIONINFO );

 GetVersionEx ( &WNT_osVer );

 if ( hHeap == NULL ) {
 
  SYSTEM_INFO si;

  GetSystemInfo ( &si );

  hHeap = HeapCreate ( HEAP_GENERATE_EXCEPTIONS, si.dwPageSize, 0 );
 
 }  // end if

 if ( WNT_osVer.dwPlatformId == VER_PLATFORM_WIN32_NT ) {
#ifndef UNICODE 
  LPSTR    lpNTproc[] = { "OpenWindowStationA", "SetProcessWindowStation",
                          "OpenDesktopA"      , "SetThreadDesktop"       ,
                          "CloseDesktop"      , "CloseWindowStation"     
                        };
#else
  LPSTR    lpNTproc[] = { "OpenWindowStationW", "SetProcessWindowStation",
                          "OpenDesktopW"      , "SetThreadDesktop"       ,
                          "CloseDesktop"      , "CloseWindowStation"     
                        };
#endif  // UNICODE
  FARPROC* fpNTproc[] = { ( FARPROC* )&NTOpenWindowStation, ( FARPROC* )&NTSetProcessWindowStation,
                          ( FARPROC* )&NTOpenDesktop,       ( FARPROC* )&NTSetThreadDesktop,
                          ( FARPROC* )&NTCloseDesktop,      ( FARPROC* )&NTCloseWindowStation
                        };
  HMODULE  hUser32    = GetModuleHandle (  TEXT( "USER32" )  );

  for (   int i = 0; i < (  sizeof ( lpNTproc ) / sizeof ( lpNTproc[ 0 ] )  ); ++i   )

   *fpNTproc[ i ] = GetProcAddress ( hUser32, lpNTproc[ i ] );
 
 }  // end if

 ZeroMemory (  cimgType, sizeof ( cimgType )  );

 if (   GetEnvironmentVariable (
         TEXT( "CSF_DefaultImageFormat" ), cimgType, sizeof ( imgType )
        ) == 0
 ) lstrcpy (  cimgType, TEXT( "GIF" )  );

 imgType = _image_type ( cimgType, TRUE );

}  // end constructor

_init :: ~_init () {

 if ( hHeap != NULL ) {
 
  HeapDestroy ( hHeap );
  hHeap = NULL;
 
 }  // end if

}  // end destructor

static WNT_TypeOfImage __fastcall _image_type ( LPTSTR ext, BOOL fInit ) {

 WNT_TypeOfImage retVal;

 if (   !lstrcmpi (  ext, TEXT( "BMP" )  )   )

  retVal = WNT_TOI_BMP;

 else if (   !lstrcmpi (  ext, TEXT( "XWD" )  )   )

  retVal = WNT_TOI_XWD;

 else if ( fInit )

  retVal = WNT_TOI_GIF;

 else {

  retVal = imgType;

  if (   lstrcmpi (  ext, TEXT( "GIF" )  )   )

   switch ( retVal ) {
   
    case WNT_TOI_BMP:

     lstrcpy (  ext, TEXT( "bmp" )  );

    break;

    case WNT_TOI_XWD:

     lstrcpy (  ext, TEXT( "xwd" )  );

    break;

    default:

     lstrcpy (  ext, TEXT( "gif" )  );
   
   }  // end switch

 }  // end else

 return retVal;

}  // end _image_type 

static int __fastcall quick_check ( PBYTE, int, int, PBYTE, LPRGBQUAD );
static int __fastcall quick_quant ( PBYTE, int, int, PBYTE, LPRGBQUAD );
static int __fastcall ppm_quant   ( PBYTE, int, int, PBYTE, LPRGBQUAD );

static BOOL __fastcall _convert24to8 (
                        LPRGBQUAD cTable, PBYTE pData24, PBYTE pData8,
                        int w, int h
                       ) {

 BOOL retVal = FALSE;

 while ( 1 ) {

  if (  quick_check ( pData24, w, h, pData8, cTable )  ) {
okRet:
   retVal = TRUE;
   break;

  } else if (  ppm_quant ( pData24, w, h, pData8, cTable ) != -1  ) {

   for ( int i = 0; i < 256; ++i ) {

    BYTE b = cTable[ i ].rgbRed;

    cTable[ i ].rgbRed  = cTable[ i ].rgbBlue;
    cTable[ i ].rgbBlue = b;

   }  // end for

   goto okRet;

  }  // end if

  break;

 }  // end while

 return retVal;

}  // end _convert24to8
//*************************************************************************//
//* The following code based on code from the 'pbmplus' package written by //
//*  Jef Poskanzer                                                         //
//*************************************************************************//
//***//
#define MAXCOLORS 32767

#define PPM_GETR( p ) (  ( p ).r  )
#define PPM_GETG( p ) (  ( p ).g  )
#define PPM_GETB( p ) (  ( p ).b  )

#define PPM_ASSIGN( p, red, grn, blu ) \
 { ( p ).r = ( red ); ( p ).g = ( grn ); ( p ).b = ( blu ); }

#define PPM_EQUAL( p, q ) \
 (  ( p ).r == ( q ).r && ( p ).g == ( q ).g && ( p ).b == ( q ).b  )


#define PPM_DEPTH( newp, p, oldmaxval, newmaxval )                              \
 PPM_ASSIGN(                                                                    \
  ( newp ),                                                                     \
  (  ( int )PPM_GETR( p )  ) * (  ( int )newmaxval  ) / (  ( int )oldmaxval  ), \
  (  ( int )PPM_GETG( p )  ) * (  ( int )newmaxval  ) / (  ( int )oldmaxval  ), \
  (  ( int )PPM_GETB( p )  ) * (  ( int )newmaxval  ) / (  ( int )oldmaxval  )  \
 )


#define HASH_SIZE 6553

#define ppm_hashpixel( p )                  \
 (    (   (  ( int )PPM_GETR( p ) * 33023 + \
             ( int )PPM_GETG( p ) * 30013 + \
             ( int )PPM_GETB( p ) * 27011   \
          ) & 0x7fffffff                    \
      ) % HASH_SIZE                         \
 )

#define PPM_LUMIN( p ) \
         (  77 * PPM_GETR( p ) + 150 * PPM_GETG( p ) + 29 * PPM_GETB( p )  )

typedef struct { BYTE r, g, b; } pixel;

struct chist_item {
        pixel color;
        int   value;
       };

typedef struct chist_item* chist_vec;

typedef struct chist_list_item* chist_list;
typedef chist_list*             chash_table;

struct chist_list_item {
        struct chist_item ch;
        chist_list        next;
       };

struct box {
        int index;
        int colors;
        int sum;
       };

typedef struct box* box_vector;

static chist_vec   __fastcall ppm_computechist ( pixel**,   int, int, int, PINT );
static void        __fastcall ppm_freechist    ( chist_vec                      );
static chist_vec   __fastcall mediancut        ( chist_vec, int, int, int, int  );
static chash_table            ppm_allocchash   ( void                           );
static void        __fastcall ppm_freechash    ( chash_table                    );
static chash_table __fastcall ppm_computechash ( pixel**,   int, int, int, PINT );
static chist_vec   __fastcall ppm_chashtochist ( chash_table, int               );

static int redcompare   ( const void*, const void* );
static int greencompare ( const void*, const void* );
static int bluecompare  ( const void*, const void* );
static int sumcompare   ( const void*, const void* );

static int __fastcall ppm_quant (
                       PBYTE pic24, int cols, int rows, PBYTE pic8, LPRGBQUAD rgbmap
                      ) {


 pixel**     pixels;
 pixel*      pP;
 int         row;
 int         col, limitcol;
 BYTE        maxval, newmaxval;
 int         colors;
 int         index;
 chist_vec   chv, colormap;
 chash_table cht;
 int         i;
 PBYTE       picptr;
 LPRGBQUAD   pRGB;
 int         pad;

 index  = 0;
 maxval = 255;
 pad    = PAD( cols * 3 );

 pixels = ( pixel** )MALLOC(  rows * sizeof ( pixel* )  );
  
 if ( pixels == NULL ) return -1;

 for ( row = 0; row < rows; ++row ) {

  pixels[ row ] = ( pixel* )MALLOC(  cols * sizeof ( pixel )  );

  if ( pixels[ row ] == NULL ) {
freeMemory:
   while ( --row >= 0 ) FREE( pixels[ row ] );
      
   FREE( pixels );

   return -1;

  }  // end if

  for ( col = 0, pP = pixels[ row ]; col < cols; ++col, ++pP ) {

   pP -> r = *pic24++;
   pP -> g = *pic24++;
   pP -> b = *pic24++;
    
  }  // end for

  pic24 += pad;
  
 }  // end for

 for ( ;; ) {

  chv = ppm_computechist ( pixels, cols, rows, MAXCOLORS, &colors );
  
  if (  chv != ( chist_vec )0  ) break;
    
  newmaxval = maxval / 2;

  for ( row = 0; row < rows; ++row )

   for ( col = 0, pP = pixels[ row ]; col < cols; ++col, ++pP )

    PPM_DEPTH( *pP, *pP, maxval, newmaxval );
    
  maxval = newmaxval;
  
 }  // end for

 colormap = mediancut ( chv, colors, rows * cols, maxval, 256 );
  
 if (  colormap == ( chist_vec )NULL  ) {
freeMemory_1:
  ppm_freechist ( chv );
  row = rows;
  goto freeMemory;

 }  // end if

 ppm_freechist ( chv );

 cht = ppm_allocchash ();

 picptr = pic8;

 for ( row = 0;  row < rows;  ++row ) {

  col      = 0;
  limitcol = cols;
  pP       = pixels[ row ];

  do {

   int        hash;
   chist_list chl;

   hash = ppm_hashpixel ( *pP );

   for ( chl = cht[ hash ];  chl;  chl = chl -> next )

    if (  PPM_EQUAL( chl -> ch.color, *pP )  ) {

     index = chl -> ch.value;
     break;

    }  // end if

   if ( !chl ) {

    int  i, r1, g1, b1, r2, g2, b2;
    long dist, newdist;

	r1 = PPM_GETR( *pP );
	g1 = PPM_GETG( *pP );
	b1 = PPM_GETB( *pP );
	dist = 2000000000;

	for ( i = 0; i < 256; ++i ) {

     r2 = PPM_GETR( colormap[ i ].color );
     g2 = PPM_GETG( colormap[ i ].color );
     b2 = PPM_GETB( colormap[ i ].color );

     newdist = ( r1 - r2 ) * ( r1 - r2 ) +
               ( g1 - g2 ) * ( g1 - g2 ) +
               ( b1 - b2 ) * ( b1 - b2 );

     if ( newdist < dist ) {

      index = i;
      dist  = newdist;

     }  // end if
	
    }  // end for

    hash = ppm_hashpixel( *pP );
	chl  = ( chist_list )MALLOC(  sizeof ( struct chist_list_item )  );

	if ( chl == NULL ) {

     ppm_freechash ( cht );
     goto freeMemory_1;

    }  // end if

	chl -> ch.color = *pP;
	chl -> ch.value = index;
	chl -> next     = cht[ hash ];
	cht[ hash ]     = chl;
      
   }  // end if

   *picptr++ = index;
   ++col;
   ++pP;
  
  } while ( col != limitcol );

 }  // end for

 for ( i = 0, pRGB = rgbmap; i < 256; ++i, ++pRGB ) {

  PPM_DEPTH( colormap[ i ].color, colormap[ i ].color, maxval, 255 );
    
  pRGB -> rgbRed   = PPM_GETR( colormap[ i ].color );
  pRGB -> rgbGreen = PPM_GETG( colormap[ i ].color );
  pRGB -> rgbBlue  = PPM_GETB( colormap[ i ].color );
  
 }  // end for

 for ( i = 0; i < rows; ++i ) FREE( pixels[ i ] );
  
 FREE( pixels );

 ppm_freechist ( colormap );
 ppm_freechash ( cht      );

 return 0;

}  // end ppm_quant

static void __fastcall ppm_freechist ( chist_vec chv ) {

 FREE(  ( LPVOID )chv  );

}  // end ppm_freechist

static chist_vec __fastcall mediancut (
                             chist_vec chv, int colors, int sum,
                             int maxval, int newcolors
                            ) {

 chist_vec  colormap;
 box_vector bv;
 int        bi, i;
 int        boxes;

 bv = ( box_vector )MALLOC(  sizeof( struct box        ) * newcolors  );

 if ( bv == NULL ) return ( chist_vec )NULL;

 colormap = ( chist_vec  )MALLOC(  sizeof( struct chist_item ) * newcolors  );

 if ( colormap == NULL ) {

  FREE( bv );
  return ( chist_vec )NULL;

 }  // end if

 for ( i = 0; i < newcolors; ++i ) PPM_ASSIGN( colormap[ i ].color, 0, 0, 0 );

 bv[ 0 ].index  = 0;
 bv[ 0 ].colors = colors;
 bv[ 0 ].sum    = sum;
 boxes          = 1;

 while ( boxes < newcolors ) {

  int indx, clrs;
  int sm;
  int minr, maxr, ming, maxg, minb, maxb, v;
  int halfsum, lowersum;

  for ( bi = 0; bv[ bi ].colors < 2 && bi < boxes; ++bi );

  if ( bi == boxes ) break;

  indx = bv[ bi ].index;
  clrs = bv[ bi ].colors;
  sm   = bv[ bi ].sum;

  minr = maxr = PPM_GETR( chv[ indx ].color );
  ming = maxg = PPM_GETG( chv[ indx ].color );
  minb = maxb = PPM_GETB( chv[ indx ].color );

  for ( i = 1; i < clrs; ++i ) {

   v = PPM_GETR( chv[ indx + i ].color );

   if ( v < minr ) minr = v;
   if ( v > maxr ) maxr = v;

   v = PPM_GETG( chv[ indx + i ].color );

   if ( v < ming ) ming = v;
   if ( v > maxg ) maxg = v;

   v = PPM_GETB( chv[ indx + i ].color );

   if ( v < minb ) minb = v;
   if ( v > maxb ) maxb = v;

  }  // end for

  {  // begin local block

   pixel p;
   int   rl, gl, bl;

   PPM_ASSIGN( p, maxr - minr, 0, 0 );      
   rl = PPM_LUMIN( p );

   PPM_ASSIGN( p, 0, maxg - ming, 0 );
   gl = PPM_LUMIN( p );

   PPM_ASSIGN( p, 0, 0, maxb - minb );
   bl = PPM_LUMIN( p );

   if ( rl >= gl && rl >= bl )

    qsort (
     ( char* )&chv[ indx ], ( size_t )clrs,
     sizeof ( struct chist_item ), redcompare
    );
      
   else if ( gl >= bl )

    qsort (
     ( char* )&chv[ indx ], ( size_t )clrs,
     sizeof ( struct chist_item ), greencompare
    );
      
   else 

    qsort (
     ( char* )&chv[ indx ], ( size_t )clrs,
     sizeof ( struct chist_item ), bluecompare
    );
    
  }  // end local block

  lowersum = chv[ indx ].value;
  halfsum  = sm / 2;

  for ( i = 1; i < clrs - 1; ++i) {

   if ( lowersum >= halfsum ) break;

   lowersum += chv[ indx + i ].value;

  }  // end for

  bv[ bi ].colors = i;
  bv[ bi ].sum    = lowersum;

  bv[ boxes   ].index  = indx + i;
  bv[ boxes   ].colors = clrs - i;
  bv[ boxes++ ].sum    = sm - lowersum;

  qsort (
   ( char* )bv, ( size_t )boxes, sizeof ( struct box ), sumcompare
  );
  
 }  // end while

 for ( bi = 0; bi < boxes; ++bi ) {

  int  indx = bv[ bi ].index;
  int  clrs = bv[ bi ].colors;
  long r = 0, g = 0, b = 0, sum = 0;

  for ( i = 0; i < clrs; ++i ) {

   r += PPM_GETR( chv[ indx + i ].color ) * chv[ indx + i ].value;
   g += PPM_GETG( chv[ indx + i ].color ) * chv[ indx + i ].value;
   b += PPM_GETB( chv[ indx + i ].color ) * chv[ indx + i ].value;
      
   sum += chv[ indx + i ].value;

  }  // end for ( i . . . )

  r = r / sum;  if ( r > maxval ) r = maxval;
  g = g / sum;  if ( g > maxval ) g = maxval;
  b = b / sum;  if ( b > maxval ) b = maxval;

  PPM_ASSIGN(  colormap[ bi ].color, ( BYTE )r, ( BYTE )g, ( BYTE )b  );
  
 }  // end for ( bi . . . )

 FREE( bv );

 return colormap;

}  // end mediancut

static int redcompare ( const void* p1, const void* p2 ) {

 return ( int )PPM_GETR(   (  ( chist_vec )p1  ) -> color   ) - 
        ( int )PPM_GETR(   (  ( chist_vec )p2  ) -> color   );

}  // end redcompare

static int greencompare ( const void* p1, const void* p2 ) {

 return ( int )PPM_GETG(   (  ( chist_vec )p1  ) -> color   ) - 
        ( int )PPM_GETG(   (  ( chist_vec )p2  ) -> color   );

}  // end greencompare

static int bluecompare ( const void* p1, const void* p2 ) {

 return ( int )PPM_GETB(   (  ( chist_vec )p1  ) -> color   ) - 
        ( int )PPM_GETB(   (  ( chist_vec )p2  ) -> color   );

}  // end bluecompare

static int sumcompare ( const void* p1, const void* p2 ) {

 return (  ( box_vector )p2  ) -> sum - (  ( box_vector )p1  ) -> sum;

}  // end sumcompare

static chash_table ppm_allocchash ( void ) {

 chash_table cht;

 cht = ( chash_table )MALLOC(  HASH_SIZE * sizeof ( chist_list )  );

 return cht;

}  // end ppm_allocchash

static chist_vec __fastcall ppm_computechist (
                             pixel** pixels, int cols, int rows, int maxcolors,
                             PINT colorsP
                            ) {

 chash_table cht;
 chist_vec chv;

 cht = ppm_computechash ( pixels, cols, rows, maxcolors, colorsP );
  
 if ( cht == NULL ) return ( chist_vec )NULL;

 chv = ppm_chashtochist ( cht, maxcolors );

 ppm_freechash ( cht );
  
 return chv;

}  // end ppm_computechist

static chash_table __fastcall ppm_computechash (
                               pixel** pixels, int cols, int rows, int maxcolors,
                               PINT colorsP
                              ) {

 chash_table     cht;
 register pixel* pP;
 chist_list      chl;
 int             col, row, hash;

 cht      = ppm_allocchash ();
 *colorsP = 0;

 for ( row = 0; row < rows; ++row )

  for ( col = 0, pP = pixels[ row ];  col < cols;  ++col, ++pP ) {

   hash = ppm_hashpixel ( *pP );

   for ( chl = cht[ hash ]; chl != ( chist_list )0; chl = chl -> next )

    if (  PPM_EQUAL( chl -> ch.color, *pP )  ) break;
      
   if (  chl != ( chist_list)0  )

    ++( chl->ch.value );
      
   else {

	if (  ( *colorsP )++ > maxcolors  ) {

     ppm_freechash ( cht );

     return ( chash_table )NULL;

    }  // end if
	
    chl = ( chist_list )MALLOC(  sizeof( struct chist_list_item )  );

    if ( chl == NULL ) return ( chash_table )NULL;
	
    chl -> ch.color = *pP;
    chl -> ch.value = 1;
    chl -> next     = cht[ hash ];
    cht[ hash ]     = chl;
      
  }  // end else
    
 }  // end for
  
 return cht;

}  // end ppm_computechash

static chist_vec __fastcall ppm_chashtochist ( chash_table cht, int maxcolors ) {

 chist_vec  chv;
 chist_list chl;
 int        i, j;

 chv = ( chist_vec )MALLOC(  maxcolors * sizeof ( struct chist_item )  );

 if ( chv == NULL) return chv;

 j = 0;

 for ( i = 0; i < HASH_SIZE; ++i )

  for ( chl = cht[ i ];  chl != ( chist_list )0;  chl = chl -> next ) {

   chv[ j ] = chl -> ch;
   ++j;
    
  }  // end for

  return chv;

}  // end ppm_chashtochist

static void __fastcall ppm_freechash ( chash_table cht ) {

 int        i;
 chist_list chl, chlnext;

 for ( i = 0; i < HASH_SIZE; ++i )

  for ( chl = cht[ i ];  chl != ( chist_list )0; chl = chlnext ) {

   chlnext = chl -> next;
   FREE( chl );
    
  }  // end for

 FREE( cht );

}  // end ppm_freechash

static int __fastcall quick_check (
                       PBYTE pic24, int w, int h, PBYTE pic8, LPRGBQUAD rgbmap
                      ) {

 unsigned long colors[ 256 ], col;
 int           i, j, nc, low, high, mid, pad;
 PBYTE         p, pix;

 nc  = 0;
 mid = 0;
 pad = PAD( w * 3 );

 for ( i = 0, p = pic24; i < h; ++i ) {

  for ( j = 0; j < w; ++j ) {

   col  = (   (  ( unsigned long )*p++  ) << 16   );  
   col += (   (  ( unsigned long )*p++  ) <<  8   );
   col += *p++;

   low = 0;  high = nc - 1;

   while ( low <= high ) {

    mid = ( low + high ) / 2;

    if ( col < colors[ mid ] )

     high = mid - 1;

    else if ( col > colors[ mid ] )

     low  = mid + 1;
      
    else break;
    
   }  // end while

   if ( high < low ) {

    if ( nc >= 256 ) return FALSE;

    CopyMemory (
     ( char* )&colors[ low + 1 ], ( char* )&colors[ low ],
     ( nc - low ) * sizeof ( unsigned long )
    );

    colors[ low ] = col;
    ++nc;
    
   }  // end if

  }  // end for ( j . . . )

  p += pad;

 }  // end for ( i . . . )

 for ( i = 0, p = pic24, pix = pic8; i < h; ++i ) {

  for ( j = 0; j < w; ++j ) {

   col  = (   (  ( unsigned long )*p++  ) << 16   );  
   col += (   (  ( unsigned long )*p++  ) <<  8   );
   col += *p++;

   low = 0;  high = nc - 1;

   while ( low <= high ) {

    mid = ( low + high ) / 2;

    if ( col < colors[ mid ] )

     high = mid - 1;
      
    else if ( col > colors[ mid ] )

     low  = mid + 1;

    else break;
    
   }  // end while

   *pix++ = mid;

  }  // end for ( j . . . )

  p += pad;

 }  // end for ( i . . . )

 for ( i = 0; i < nc; ++i, ++rgbmap ) {

  rgbmap -> rgbRed   = ( BYTE )( colors[ i ] >>  0 ) & 0xFF;  
  rgbmap -> rgbGreen = ( BYTE )( colors[ i ] >>  8 ) & 0xFF;
  rgbmap -> rgbBlue  = ( BYTE )( colors[ i ] >> 16 ) & 0xFF;
  
 }  // end for

 return nc;

}  // end quick_check

#define RMASK  0xE0
#define RSHIFT    0
#define GMASK  0xE0
#define GSHIFT    3
#define BMASK  0xC0
#define BSHIFT    6
#define RANGE( a, b, c ) { if ( a < b ) a = b;  if ( a > c ) a = c; }

static int __fastcall quick_quant (
                       PBYTE p24, int w, int h, PBYTE p8, LPRGBQUAD rgbmap
                      ) {

 PBYTE pp;
 int   r1, g1, b1;
 PINT  thisline, nextline, thisptr, nextptr, tmpptr;
 int   i, j, val, pwide3;
 int   imax, jmax;
 int   pad;

 pad = PAD( w * 3 );

 pp     = p8;
 pwide3 = w * 3;
 imax   = h - 1;
 jmax   = w - 1;

 for ( i = 0; i < 256; ++i ) {

  rgbmap[ i ].rgbRed   = (   (  ( i << RSHIFT ) & RMASK  ) * 255 + RMASK / 2   ) / RMASK;
  rgbmap[ i ].rgbGreen = (   (  ( i << GSHIFT ) & GMASK  ) * 255 + GMASK / 2   ) / GMASK;
  rgbmap[ i ].rgbBlue  = (   (  ( i << BSHIFT ) & BMASK  ) * 255 + BMASK / 2   ) / BMASK;
  
 }  // end for
  
 thisline = ( PINT )MALLOC(  pwide3 * sizeof ( int )  );

 if ( thisline == NULL ) return 1;

 nextline = ( PINT )MALLOC(  pwide3 * sizeof ( int )  );

 if ( nextline == NULL ) {

  FREE( thisline );
  return 1;

 }  // end if

 for ( j = pwide3, tmpptr = nextline; j; --j ) *tmpptr++ = ( int )*p24++;

 p24 += pad;
  
 for ( i = 0; i < h; ++i ) {

  tmpptr   = thisline;
  thisline = nextline;
  nextline = tmpptr;
    
  if ( i != imax ) {

   for ( j = pwide3, tmpptr = nextline; j; --j ) *tmpptr++ = ( int )*p24++;

   p24 += pad;

  }  // end if
    
  for ( j = 0, thisptr = thisline, nextptr = nextline; j < w; ++j, ++pp ) {

   r1 = *thisptr++;
   RANGE( r1, 0, 255 );

   g1 = *thisptr++;
   RANGE(g1,0,255);

   b1 = *thisptr++;
   RANGE(b1,0,255);  
      
   val = (   (  ( r1 & RMASK ) >> RSHIFT  ) |
             (  ( g1 & GMASK ) >> GSHIFT  ) | 
	         (  ( b1 & BMASK ) >> BSHIFT  )   );
   *pp = val;
      
   r1 -= rgbmap[ val ].rgbRed;
   g1 -= rgbmap[ val ].rgbGreen;
   b1 -= rgbmap[ val ].rgbBlue;
      
   if ( j != jmax ) {

    thisptr[ 0 ] += ( r1 * 7 ) / 16;
    thisptr[ 1 ] += ( g1 * 7 ) / 16;
    thisptr[ 2 ] += ( b1 * 7 ) / 16;
      
   }  // end if
      
   if ( i != imax ) {

    nextptr[ 0 ] += ( r1 * 5 ) / 16;
    nextptr[ 1 ] += ( g1 * 5 ) / 16;
    nextptr[ 2 ] += ( b1 * 5 ) / 16;

    if ( j > 0 ) {

     nextptr[ -3 ] += ( r1 * 3 ) / 16;
     nextptr[ -2 ] += ( g1 * 3 ) / 16;
     nextptr[ -1 ] += ( b1 * 3 ) / 16;
	
    }  // end if

    if ( j != jmax ) {

     nextptr[ 3 ] += ( r1 ) / 16;
     nextptr[ 4 ] += ( g1 ) / 16;
     nextptr[ 5 ] += ( b1 ) / 16;
	
    }  // end if

	nextptr += 3;

   }  // end if

  }  // end for ( j . . . )
  
 }  // end for ( i . . . )
  
 FREE( thisline );
 FREE( nextline );
  
 return 0;

}  // end quick_quant
//***//
//*************************************************************************//
