图像处理VC源码1.0-DibApi

/********************************************************************************
 *  DIBAPI.H
 *
 *  Header file for Device-Independent Bitmap (DIB) API.  Provides
 *  function prototypes and constants for DIB functions
 ********************************************************************************/

#ifndef __DIBAPI_H_
#define __DIBAPI_H_
//

/* Handle to a DIB */
#define HDIB    HANDLE

// Dib Header Marker - used in writing DIBs to files
#define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B')

/* DIB constants */
#define PALVERSION   0x300

/* DIB copy constants */
#define PW_WINDOW   1
#define PW_CLIENT   2

/* DIB Macros*/
// WIDTHBYTES performs DWORD-aligning of DIB scanlines.  The "bits"
// parameter is the bit count for the scanline (biWidth * biBitCount),
// and this macro returns the number of DWORD-aligned bytes needed 
// to hold those bits.
#define WIDTHBYTES(bits)    (((bits) + 31) / 32 * 4)
#define IS_WIN30_DIB(lpbi)  ((*(LPDWORD)(lpbi)) == sizeof(BITMAPINFOHEADER))
#define RECTWIDTH(lpRect)   ((lpRect)->right - (lpRect)->left)
#define RECTHEIGHT(lpRect)  ((lpRect)->bottom - (lpRect)->top)
#define WaitCursorBegin() HCURSOR hcURSOR = SetCursor(LoadCursor(NULL, IDC_WAIT))
#define WaitCursorEnd()  SetCursor(hcURSOR)
 
/* function prototypes */
 // DIB initialization
HDIB CreateDIB(DWORD, DWORD, WORD);
HDIB CreateDefaultDIB(DWORD dwWidth, DWORD dwHeight);
void DestroyDIB(HDIB);
HDIB LoadDIB (LPTSTR);
BOOL SaveDIB (HDIB, LPTSTR);
HDIB ReadDIBFile(HANDLE);
 // DIB attributes
DWORD BytesPerLine(LPBYTE lpDIB);
DWORD BytesPerLine(HDIB hDIB);
DWORD DIBlockSize(HDIB hDIB);
DWORD DIBlockSize(LPBYTE lpDIB);
DWORD DIBHeight (LPBYTE lpDIB);
DWORD DIBHeight (HDIB hDIB);
DWORD DIBWidth (LPBYTE lpDIB);
DWORD DIBWidth (HDIB hDIB);
WORD DIBNumColors (LPBYTE lpDIB);
WORD DIBNumColors (HDIB hDIB);
WORD DIBBitCount (LPBYTE lpDIB);
WORD DIBBitCount (HDIB hDIB);
LPBYTE FindDIBBits (LPBYTE lpDIB);
WORD PaletteSize (LPBYTE lpDIB);
WORD PaletteSize (HDIB hDIB);
 // DIB display
BOOL PaintBitmap(HDC, LPRECT, HBITMAP, LPRECT, HPALETTE, DWORD);
BOOL PaintDIB(HDC, LPRECT, HDIB, LPRECT, HPALETTE, DWORD);
 // DIB operations
HBITMAP DIBToDIBSection(LPBYTE lpDIB);
HBITMAP DIBToDIBSection(HDIB hDIB);
HDIB DIBSectionToDIB(HBITMAP hBitmap);
HDIB ConvertDIBFormat(LPBYTE lpSrcDIB, UINT nWidth, UINT nHeight, UINT nbpp, BOOL bStretch, HPALETTE hPalSrc);
HDIB ConvertDIBFormat(HDIB hDIB, UINT nWidth, UINT nHeight, UINT nbpp, BOOL bStretch, HPALETTE hPalSrc);
HDIB ConvertDIBFormat(LPBYTE lpSrcDIB, UINT nbpp, HPALETTE hPalSrc);
HDIB ConvertDIBFormat(HDIB hDIB, UINT nbpp, HPALETTE hPalSrc);
HDIB BitmapToDIB (HBITMAP, HPALETTE);
HDIB BitmapToDIB (HBITMAP, HPALETTE, WORD);
HDIB ChangeBitmapFormat (HBITMAP, WORD, DWORD, HPALETTE);
HBITMAP DIBToBitmap (HDIB hDIB, HPALETTE hPal);
HDIB ChangeDIBFormat (HDIB, WORD, DWORD);
BOOL CopyColorTable( LPBITMAPINFO lpTarget, LPBITMAPINFO lpSource, HPALETTE hPalSrc );
 // DIB palette
HPALETTE CreateDIBPalette(LPBYTE lpDIB);
HPALETTE CreateDIBPalette(HDIB hDIB);
BOOL DisplayPalette(HDC hDC, LPRECT lpRect, HPALETTE hPal);
HPALETTE CopyPalette(HPALETTE hPalSrc);
HPALETTE GetSystemPalette(void);
int PalEntriesOnDevice (HDC hDC);
HPALETTE CreateIdentifyPalette(HPALETTE hPalSrc);
BOOL MapDIBColorsToPalette(HDIB hDIB, HPALETTE hPalette);
 // DIB capture
HBITMAP CopyScreenToBitmap (LPRECT);
HBITMAP CopyWindowToBitmap (HWND, WORD);
HBITMAP CopyClientRectToBitmap(HWND hWnd, LPRECT lpRect);
HDIB CopyScreenToDIB (LPRECT);
HDIB CopyWindowToDIB (HWND, WORD);
HDIB CopyClientRectToDIB(HWND hWnd, LPRECT lpRect);
 // Color quantization
HPALETTE CreateOctreePalette(HDIB hDIB, UINT nMaxColors, UINT nColorBits);
HPALETTE CreateOctreePalette(LPBYTE lpDIB, UINT nMaxColors, UINT nColorBits);
HANDLE CopyHandle(HANDLE h);

//
#endif //__DIBAPI_H_ 

==================================================================================

//**********************************************************************
//
//  AIBAPI.CPP
//
//  Source file for Device-Independent Bitmap (DIB) API.
//
//**********************************************************************
 
#define     STRICT      // enable strict type checking
 
#include "stdafx.h"
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <io.h>
#include <direct.h>
#include <stdlib.h>
#include <assert.h>
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include "dibapi.h"

 
/*************************************************************************
 *
 * CreateDIB()
 *
 * Parameters:
 *
 * DWORD dwWidth    - Width for new bitmap, in pixels
 * DWORD dwHeight   - Height for new bitmap 
 * WORD  wBitCount  - Bit Count for new DIB (1, 4, 8, or 24)
 *
 * Return Value:
 *
 * HDIB             - Handle to new DIB
 *
 * Description:
 *
 * This function allocates memory for and initializes a new DIB by
 * filling in the BITMAPINFOHEADER, allocating memory for the color
 * table, and allocating memory for the bitmap bits.  As with all
 * HDIBs, the header, colortable and bits are all in one contiguous
 * memory block.  This function is similar to the CreateBitmap() 
 * Windows API.
 *
 * The colortable and bitmap bits are left uninitialized (zeroed) in the
 * returned HDIB.
 *
 *
 ************************************************************************/
HDIB CreateDIB(DWORD dwWidth, DWORD dwHeight, WORD wBitCount)
{
    BITMAPINFOHEADER    bi;             // bitmap header
    LPBITMAPINFOHEADER  lpbi;           // pointer to BITMAPINFOHEADER
    DWORD               dwLen;          // size of memory block
    HDIB                hDIB;
    DWORD               dwBytesPerLine; // Number of bytes per scanline
 
 
    // Make sure bits per pixel is valid
 
    if (wBitCount <= 1)
        wBitCount = 1;
    else if (wBitCount <= 4)
        wBitCount = 4;
    else if (wBitCount <= 8)
        wBitCount = 8;
    else if (wBitCount <= 24)
        wBitCount = 24;
    else
        wBitCount = 4;  // set default value to 4 if parameter is bogus
 
    // initialize BITMAPINFOHEADER
 
    bi.biSize = sizeof(BITMAPINFOHEADER);
    bi.biWidth = dwWidth;         // fill in width from parameter
    bi.biHeight = dwHeight;       // fill in height from parameter
    bi.biPlanes = 1;              // must be 1
    bi.biBitCount = wBitCount;    // from parameter
    bi.biCompression = BI_RGB;    
    bi.biSizeImage = 0;           // 0's here mean "default"
    bi.biXPelsPerMeter = 0;
    bi.biYPelsPerMeter = 0;
    bi.biClrUsed = 0;
    bi.biClrImportant = 0;
 
    // calculate size of memory block required to store the DIB.  This
    // block should be big enough to hold the BITMAPINFOHEADER, the color
    // table, and the bits
 
    dwBytesPerLine = WIDTHBYTES(wBitCount * dwWidth);
    dwLen = bi.biSize + PaletteSize((LPBYTE)&bi) + (dwBytesPerLine * dwHeight);
 
    // alloc memory block to store our bitmap
 
    hDIB = GlobalAlloc(GHND, dwLen);
 
    // major bummer if we couldn't get memory block
 
    if (!hDIB)
        return NULL;
 
    // lock memory and get pointer to it
 
    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
 
    // use our bitmap info structure to fill in first part of
    // our DIB with the BITMAPINFOHEADER
 
    *lpbi = bi;
 
    // Since we don't know what the colortable and bits should contain,
    // just leave these blank.  Unlock the DIB and return the HDIB.
 
    GlobalUnlock(hDIB);
 
    //return handle to the DIB
 
    return hDIB;
}
 
/*************************************************************************
 *
 * CreateDefaultDIB()
 *
 * Parameters:
 *
 * DWORD dwWidth    - Width for new bitmap, in pixels
 * DWORD dwHeight   - Height for new bitmap 
  *
 * Return Value:
 *
 * HDIB             - Handle to new DIB
 *
 * Description:
 *
 * This function allocates memory for and initializes a new DIB by
 * filling in the BITMAPINFOHEADER, allocating memory for the color
 * table, and allocating memory for the bitmap bits.  As with all
 * HDIBs, the header, colortable and bits are all in one contiguous
 * memory block.  This function is similar to the CreateBitmap() 
 * Windows API.
 *
 * The colortable is initialized with system palette, but bitmap bits
 * are left uninitialized (zeroed) in the returned HDIB.
 *
 *
 ************************************************************************/
HDIB CreateDefaultDIB(DWORD dwWidth, DWORD dwHeight)
{
 // Get DC
    HDC hDC = GetDC(NULL);
    if (!hDC)
        return NULL;

 // DC bts/pixel
 int nDeviceBitsPixel = GetDeviceCaps(hDC, BITSPIXEL);

 // create DIB according to DC
 HDIB hDIB = CreateDIB(dwWidth, dwHeight, nDeviceBitsPixel);

 // DIB buffer
 LPBITMAPINFO lpbmi = (LPBITMAPINFO)GlobalLock(hDIB);
    LPBYTE lpDIBBits = FindDIBBits((LPBYTE)lpbmi);
    DWORD dwBitsSize = lpbmi->bmiHeader.biHeight * BytesPerLine((LPBYTE)&(lpbmi->bmiHeader));

 // set DIB color to White
 for (DWORD l=0; l<dwBitsSize; ++l)
  lpDIBBits[l] = 0xff;

 // if no palette, return DIB handle
 if (nDeviceBitsPixel > 8)
 {
  GlobalUnlock(hDIB);
     ReleaseDC(NULL, hDC);
  return hDIB;
 }

 // if there is palette, set system palette to DIB

 // colors in system palette
    int nColors = PalEntriesOnDevice(hDC);   // Number of palette entries
 
    // Copy the current system palette into our logical palette
 PALETTEENTRY pe[256];
    GetSystemPaletteEntries(hDC, 0, nColors, pe);

 // set color table
 for (int i=0; i<nColors; ++i)
 {
  lpbmi->bmiColors[i].rgbRed = pe[i].peRed;
  lpbmi->bmiColors[i].rgbGreen = pe[i].peGreen;
  lpbmi->bmiColors[i].rgbBlue = pe[i].peBlue;
  lpbmi->bmiColors[i].rgbReserved = 0;
 }

    // clean up
 GlobalUnlock(hDIB);
    ReleaseDC(NULL, hDC);

 return hDIB;
}
/*************************************************************************
 *
 * DestroyDIB ()
 *
 * Purpose:  Frees memory associated with a DIB
 *
 * Returns:  none
 *
 *************************************************************************/
void DestroyDIB(HDIB hDib)
{
    GlobalFree(hDib);
}
 
/*************************************************************************
 *
 * Function:  ReadDIBFile (int)
 *
 *  Purpose:  Reads in the specified DIB file into a global chunk of
 *            memory.
 *
 *  Returns:  A handle to a dib (hDIB) if successful.
 *            NULL if an error occurs.
 *
 * Comments:  BITMAPFILEHEADER is stripped off of the DIB.  Everything
 *            from the end of the BITMAPFILEHEADER structure on is
 *            returned in the global memory handle.
 *
 *
 * NOTE: The DIB API were not written to handle OS/2 DIBs, so this
 * function will reject any file that is not a Windows DIB.
 *
 *************************************************************************/
HANDLE ReadDIBFile(HANDLE hFile)
{
    BITMAPFILEHEADER    bmfHeader;
    DWORD               dwBitsSize;
    UINT                nNumColors;   // Number of colors in table
    HANDLE              hDIB;        
    HANDLE              hDIBtmp;      // Used for GlobalRealloc() //MPB
    LPBITMAPINFOHEADER  lpbi;
    DWORD               offBits;
    DWORD               dwRead;
 
    // get length of DIB in bytes for use when reading
 
    dwBitsSize = GetFileSize(hFile, NULL);
 
    // Allocate memory for header & color table. We'll enlarge this
    // memory as needed.
 
    hDIB = GlobalAlloc(GMEM_MOVEABLE, (DWORD)(sizeof(BITMAPINFOHEADER) +
            256 * sizeof(RGBQUAD)));
 
    if (!hDIB)
        return NULL;
 
    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
 
    if (!lpbi) 
    {
        GlobalFree(hDIB);
        return NULL;
    }
 
    // read the BITMAPFILEHEADER from our file
 
    if (!ReadFile(hFile, (LPBYTE)&bmfHeader, sizeof (BITMAPFILEHEADER),
            &dwRead, NULL))
        goto ErrExit;
 
    if (sizeof (BITMAPFILEHEADER) != dwRead)
        goto ErrExit;
 
    if (bmfHeader.bfType != 0x4d42)  // 'BM'
        goto ErrExit;
 
    // read the BITMAPINFOHEADER
 
    if (!ReadFile(hFile, (LPBYTE)lpbi, sizeof(BITMAPINFOHEADER), &dwRead,
            NULL))
        goto ErrExit;
 
    if (sizeof(BITMAPINFOHEADER) != dwRead)
        goto ErrExit;
 
    // Check to see that it's a Windows DIB -- an OS/2 DIB would cause
    // strange problems with the rest of the DIB API since the fields
    // in the header are different and the color table entries are
    // smaller.
    //
    // If it's not a Windows DIB (e.g. if biSize is wrong), return NULL.
 
    if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
        goto ErrExit;
 
    // Now determine the size of the color table and read it.  Since the
    // bitmap bits are offset in the file by bfOffBits, we need to do some
    // special processing here to make sure the bits directly follow
    // the color table (because that's the format we are susposed to pass
    // back)
 
    if (!(nNumColors = (UINT)lpbi->biClrUsed))
    {
        // no color table for 24-bit, default size otherwise
 
        if (lpbi->biBitCount != 24)
            nNumColors = 1 << lpbi->biBitCount; // standard size table
    }
 
    // fill in some default values if they are zero
 
    if (lpbi->biClrUsed == 0)
        lpbi->biClrUsed = nNumColors;
 
    if (lpbi->biSizeImage == 0)
    {
        lpbi->biSizeImage = ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) +
                31) & ~31) >> 3) * lpbi->biHeight;
    }
 
    // get a proper-sized buffer for header, color table and bits
 
    GlobalUnlock(hDIB);
    hDIBtmp = GlobalReAlloc(hDIB, lpbi->biSize + nNumColors *
            sizeof(RGBQUAD) + lpbi->biSizeImage, 0);
 
    if (!hDIBtmp) // can't resize buffer for loading
        goto ErrExitNoUnlock; //MPB
    else
        hDIB = hDIBtmp;
 
    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
 
    // read the color table
 
    ReadFile (hFile, (LPBYTE)(lpbi) + lpbi->biSize,
            nNumColors * sizeof(RGBQUAD), &dwRead, NULL);
 
    // offset to the bits from start of DIB header
 
    offBits = lpbi->biSize + nNumColors * sizeof(RGBQUAD);
 
    // If the bfOffBits field is non-zero, then the bits might *not* be
    // directly following the color table in the file.  Use the value in
    // bfOffBits to seek the bits.
 
    if (bmfHeader.bfOffBits != 0L)
        SetFilePointer(hFile, bmfHeader.bfOffBits, NULL, FILE_BEGIN);
 
    if (ReadFile(hFile, (LPBYTE)lpbi + offBits, lpbi->biSizeImage, &dwRead,
            NULL))
        goto OKExit;
 
ErrExit:
    GlobalUnlock(hDIB);    
 
ErrExitNoUnlock:    
    GlobalFree(hDIB);
    return NULL;
 
OKExit:
    GlobalUnlock(hDIB);
    return hDIB;
}

/*************************************************************************
 *
 * LoadDIB()
 *
 * Loads the specified DIB from a file, allocates memory for it,
 * and reads the disk file into the memory.
 *
 *
 * Parameters:
 *
 * LPCTSTR lpFileName - specifies the file to load a DIB from
 *
 * Returns: A handle to a DIB, or NULL if unsuccessful.
 *
 * NOTE: The DIB API were not written to handle OS/2 DIBs; This
 * function will reject any file that is not a Windows DIB.
 *
 *************************************************************************/
HDIB LoadDIB(LPCTSTR lpFileName)
{
    HDIB        hDIB;
    HANDLE      hFile;
 
    // Set the cursor to a hourglass, in case the loading operation
    // takes more than a sec, the user will know what's going on.
 
    SetCursor(LoadCursor(NULL, IDC_WAIT));
 
    if ((hFile = CreateFile(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
            NULL)) != INVALID_HANDLE_VALUE)
    {
        hDIB = ReadDIBFile(hFile);
        CloseHandle(hFile);
        SetCursor(LoadCursor(NULL, IDC_ARROW));
        return hDIB;
    }
    else
    {
        SetCursor(LoadCursor(NULL, IDC_ARROW));
        return NULL;
    }
}
 
 
/*************************************************************************
 *
 * SaveDIB()
 *
 * Saves the specified DIB into the specified file name on disk.  No
 * error checking is done, so if the file already exists, it will be
 * written over.
 *
 * Parameters:
 *
 * HDIB hDib - Handle to the dib to save
 *
 * LPCTSTR lpFileName - pointer to full pathname to save DIB under
 *
 * Return value: TRUE if successful
 *     FALSE if failure
 *
 *************************************************************************/
BOOL SaveDIB(HDIB hDib, LPCTSTR lpFileName)
{
    BITMAPFILEHEADER    bmfHdr;     // Header for Bitmap file
    LPBITMAPINFOHEADER  lpBI;       // Pointer to DIB info structure
    HANDLE              fh;         // file handle for opened file
    DWORD               dwDIBSize;
    DWORD               dwWritten;
 
    if (!hDib)
        return FALSE;
 
    fh = CreateFile(lpFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
 
    if (fh == INVALID_HANDLE_VALUE)
        return FALSE;
 
    // Get a pointer to the DIB memory, the first of which contains
    // a BITMAPINFO structure
 
    lpBI = (LPBITMAPINFOHEADER)GlobalLock(hDib);
    if (!lpBI)
    {
        CloseHandle(fh);
        return FALSE;
    }
 
    // Check to see if we're dealing with an OS/2 DIB.  If so, don't
    // save it because our functions aren't written to deal with these
    // DIBs.
 
    if (lpBI->biSize != sizeof(BITMAPINFOHEADER))
    {
        GlobalUnlock(hDib);
        CloseHandle(fh);
        return FALSE;
    }
 
    // Fill in the fields of the file header
 
    // Fill in file type (first 2 bytes must be "BM" for a bitmap)
 
    bmfHdr.bfType = DIB_HEADER_MARKER;  // "BM"
 
    // Calculating the size of the DIB is a bit tricky (if we want to
    // do it right).  The easiest way to do this is to call GlobalSize()
    // on our global handle, but since the size of our global memory may have
    // been padded a few bytes, we may end up writing out a few too
    // many bytes to the file (which may cause problems with some apps,
    // like HC 3.0).
    //
    // So, instead let's calculate the size manually.
    //
    // To do this, find size of header plus size of color table.  Since the
    // first DWORD in both BITMAPINFOHEADER and BITMAPCOREHEADER conains
    // the size of the structure, let's use this.
 
    // Partial Calculation
 
    dwDIBSize = *(LPDWORD)lpBI + PaletteSize((LPBYTE)lpBI);  
 
    // Now calculate the size of the image
 
    // It's an RLE bitmap, we can't calculate size, so trust the biSizeImage
    // field
 
    if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4))
        dwDIBSize += lpBI->biSizeImage;
    else
    {
        DWORD dwBmBitsSize;  // Size of Bitmap Bits only
 
        // It's not RLE, so size is Width (DWORD aligned) * Height
 
        dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) *
                lpBI->biHeight;
 
        dwDIBSize += dwBmBitsSize;
 
        // Now, since we have calculated the correct size, why don't we
        // fill in the biSizeImage field (this will fix any .BMP files which 
        // have this field incorrect).
 
        lpBI->biSizeImage = dwBmBitsSize;
    }
 
 
    // Calculate the file size by adding the DIB size to sizeof(BITMAPFILEHEADER)
                   
    bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);
    bmfHdr.bfReserved1 = 0;
    bmfHdr.bfReserved2 = 0;
 
    // Now, calculate the offset the actual bitmap bits will be in
    // the file -- It's the Bitmap file header plus the DIB header,
    // plus the size of the color table.
    
    bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize +
            PaletteSize((LPBYTE)lpBI);
 
    // Write the file header
 
    WriteFile(fh, (LPBYTE)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
 
    // Write the DIB header and the bits -- use local version of
    // MyWrite, so we can write more than 32767 bytes of data
    
    WriteFile(fh, (LPBYTE)lpBI, dwDIBSize, &dwWritten, NULL);
 
    GlobalUnlock(hDib);
    CloseHandle(fh);
 
    if (dwWritten == 0)
        return FALSE; // oops, something happened in the write
    else
        return TRUE; // Success code
}
 
/*************************************************************************
 *
 * FindDIBBits()
 *
 * Parameter:
 *
 * LPBYTE lpDIB      - pointer to packed-DIB memory block
 *
 * Return Value:
 *
 * LPBYTE            - pointer to the DIB bits
 *
 * Description:
 *
 * This function calculates the address of the DIB's bits and returns a
 * pointer to the DIB bits.
 *
 ************************************************************************/
LPBYTE FindDIBBits(LPBYTE lpDIB)
{
   return (lpDIB + *(LPDWORD)lpDIB + PaletteSize(lpDIB));
}
 
/*************************************************************************
 *
 * DIBWidth()
 *
 * Parameter:
 *
 * LPBYTE lpDIB      - pointer to packed-DIB memory block
 *
 * Return Value:
 *
 * DWORD            - width of the DIB
 *
 * Description:
 *
 * This function gets the width of the DIB from the BITMAPINFOHEADER
 * width field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER
 * width field if it is an OS/2-style DIB.
 *
 ************************************************************************/
DWORD DIBWidth(LPBYTE lpDIB)
{
    LPBITMAPINFOHEADER   lpbmi;  // pointer to a Win 3.0-style DIB
    LPBITMAPCOREHEADER   lpbmc;  // pointer to an OS/2-style DIB
 
    // point to the header (whether Win 3.0 and OS/2)
 
    lpbmi = (LPBITMAPINFOHEADER)lpDIB;
    lpbmc = (LPBITMAPCOREHEADER)lpDIB;
 
    // return the DIB width if it is a Win 3.0 DIB
 
    if (lpbmi->biSize == sizeof(BITMAPINFOHEADER))
        return lpbmi->biWidth;
    else  // it is an OS/2 DIB, so return its width
        return (DWORD)lpbmc->bcWidth;
}
 
DWORD DIBWidth(HDIB hDIB)
{
 LPBYTE lpDIB = (LPBYTE)GlobalLock(hDIB);
 DWORD dw = DIBWidth(lpDIB);
 GlobalUnlock(hDIB);
 return dw;
}
 
/*************************************************************************
 *
 * DIBHeight()
 *
 * Parameter:
 *
 * LPBYTE lpDIB      - pointer to packed-DIB memory block
 *
 * Return Value:
 *
 * DWORD            - height of the DIB
 *
 * Description:
 *
 * This function gets the height of the DIB from the BITMAPINFOHEADER
 * height field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER
 * height field if it is an OS/2-style DIB.
 *
 ************************************************************************/
DWORD DIBHeight(LPBYTE lpDIB)
{
   LPBITMAPINFOHEADER   lpbmi;  // pointer to a Win 3.0-style DIB
   LPBITMAPCOREHEADER   lpbmc;  // pointer to an OS/2-style DIB
 
   // point to the header (whether OS/2 or Win 3.0
 
   lpbmi = (LPBITMAPINFOHEADER)lpDIB;
   lpbmc = (LPBITMAPCOREHEADER)lpDIB;
 
    // return the DIB height if it is a Win 3.0 DIB
    if (lpbmi->biSize == sizeof(BITMAPINFOHEADER))
        return lpbmi->biHeight;
    else  // it is an OS/2 DIB, so return its height
        return (DWORD)lpbmc->bcHeight;
}
 
DWORD DIBHeight(HDIB hDIB)
{
 LPBYTE lpDIB = (LPBYTE)GlobalLock(hDIB);
 DWORD dw = DIBHeight(lpDIB);
 GlobalUnlock(hDIB);
 return dw;
}
 
/*************************************************************************
 *
 * PaletteSize()
 *
 * Parameter:
 *
 * LPBYTE lpDIB      - pointer to packed-DIB memory block
 *
 * Return Value:
 *
 * WORD             - size of the color palette of the DIB
 *
 * Description:
 *
 * This function gets the size required to store the DIB's palette by
 * multiplying the number of colors by the size of an RGBQUAD (for a
 * Windows 3.0-style DIB) or by the size of an RGBTRIPLE (for an OS/2-
 * style DIB).
 *
 ************************************************************************/
WORD PaletteSize(LPBYTE lpDIB)
{
    // calculate the size required by the palette
    if (IS_WIN30_DIB (lpDIB))
        return (DIBNumColors(lpDIB) * sizeof(RGBQUAD));
    else
        return (DIBNumColors(lpDIB) * sizeof(RGBTRIPLE));
}
 
WORD PaletteSize(HDIB hDIB)
{
 LPBYTE lpDIB = (LPBYTE)GlobalLock(hDIB);
 WORD wSize = PaletteSize(lpDIB);
 GlobalUnlock(hDIB);
 return wSize;
}
 
/*************************************************************************
 *
 * DIBNumColors()
 *
 * Parameter:
 *
 * LPBYTE lpDIB      - pointer to packed-DIB memory block
 *
 * Return Value:
 *
 * WORD             - number of colors in the color table
 *
 * Description:
 *
 * This function calculates the number of colors in the DIB's color table
 * by finding the bits per pixel for the DIB (whether Win3.0 or OS/2-style
 * DIB). If bits per pixel is 1: colors=2, if 4: colors=16, if 8: colors=256,
 * if 24, no colors in color table.
 *
 ************************************************************************/
WORD DIBNumColors(LPBYTE lpDIB)
{
    WORD wBitCount;  // DIB bit count
 
    // If this is a Windows-style DIB, the number of colors in the
    // color table can be less than the number of bits per pixel
    // allows for (i.e. lpbi->biClrUsed can be set to some value).
    // If this is the case, return the appropriate value.
    
 
    if (IS_WIN30_DIB(lpDIB))
    {
        DWORD dwClrUsed;
 
        dwClrUsed = ((LPBITMAPINFOHEADER)lpDIB)->biClrUsed;
        if (dwClrUsed)
 
        return (WORD)dwClrUsed;
    }
 
    // Calculate the number of colors in the color table based on
    // the number of bits per pixel for the DIB.
    
    if (IS_WIN30_DIB(lpDIB))
        wBitCount = ((LPBITMAPINFOHEADER)lpDIB)->biBitCount;
    else
        wBitCount = ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount;
 
    // return number of colors based on bits per pixel
 
    switch (wBitCount)
    {
        case 1:
            return 2;
 
        case 4:
            return 16;
 
        case 8:
            return 256;
 
        default:
            return 0;
    }
}

WORD DIBNumColors(HDIB hDIB)
{
 LPBYTE lpDIB = (LPBYTE)GlobalLock(hDIB);
 WORD wSize = DIBNumColors(lpDIB);
 GlobalUnlock(hDIB);
 return wSize;
}

WORD DIBBitCount(LPBYTE lpDIB)
{
    if (IS_WIN30_DIB(lpDIB))
        return ((LPBITMAPINFOHEADER)lpDIB)->biBitCount;
    else
        return ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount;
}

WORD DIBBitCount(HDIB hDIB)
{
 LPBYTE lpDIB = (LPBYTE)GlobalLock(hDIB);
 WORD wSize = DIBBitCount(lpDIB);
 GlobalUnlock(hDIB);
 return wSize;
}
 
/****************************************************************************
*
*     FUNCTION: BytesPerLine
*
*     PURPOSE:  Calculates the number of bytes in one scan line.
*
*     PARAMS:   LPBYTE lpDIB - pointer to the BITMAPINFOHEADER
                              that begins the CF_DIB block
*
*     RETURNS:  DWORD - number of bytes in one scan line (DWORD aligned)
*
/****************************************************************************/
DWORD BytesPerLine(LPBYTE lpDIB)
{
    return WIDTHBYTES(((LPBITMAPINFOHEADER)lpDIB)->biWidth * ((LPBITMAPINFOHEADER)lpDIB)->biPlanes * ((LPBITMAPINFOHEADER)lpDIB)->biBitCount);
}

DWORD BytesPerLine(HDIB hDIB)
{
 LPBYTE lpDIB = (LPBYTE)GlobalLock(hDIB);
 DWORD dw = BytesPerLine(lpDIB);
 GlobalUnlock(hDIB);
 return dw;
}

/****************************************************************************
*
*     FUNCTION: DIBlockSize
*
*     PURPOSE:  Calculates the number of bytes in one scan line.
*
*     PARAMS:   LPBYTE lpDIB - pointer to the BITMAPINFOHEADER
                              that begins the CF_DIB block
*
*     RETURNS:  DWORD - DIB block size
*
/****************************************************************************/
DWORD DIBlockSize(LPBYTE lpDIB)
{
 if (((LPBITMAPINFOHEADER)lpDIB)->biSizeImage == 0)
  ((LPBITMAPINFOHEADER)lpDIB)->biSizeImage = BytesPerLine(lpDIB) * ((LPBITMAPINFOHEADER)lpDIB)->biHeight;
 return ((LPBITMAPINFOHEADER)lpDIB)->biSize + PaletteSize(lpDIB) + ((LPBITMAPINFOHEADER)lpDIB)->biSizeImage;
}

DWORD DIBlockSize(HDIB hDIB)
{
 LPBYTE lpDIB = (LPBYTE)GlobalLock(hDIB);
 DWORD dw = DIBlockSize(lpDIB);
 GlobalUnlock(hDIB);
 return dw;
}
 
/*************************************************************************
 *
 * CreateDIBPalette()
 *
 * Parameter:
 *
 * LPBYTE lpbi       - specifies the DIB
 *
 * Return Value:
 *
 * HPALETTE         - specifies the palette
 *
 * Description:
 *
 * This function creates a palette from a DIB by allocating memory for the
 * logical palette, reading and storing the colors from the DIB's color table
 * into the logical palette, creating a palette from this logical palette,
 * and then returning the palette's handle. This allows the DIB to be
 * displayed using the best possible colors (important for DIBs with 256 or
 * more colors).
 *
 ************************************************************************/
HPALETTE CreateDIBPalette(LPBYTE lpbi)
{
    LPLOGPALETTE        lpPal;          // pointer to a logical palette
    HANDLE              hLogPal;        // handle to a logical palette
    HPALETTE            hPal = NULL;    // handle to a palette
    int                 i, wNumColors;  // loop index, number of colors in color table
    LPBITMAPINFO        lpbmi;          // pointer to BITMAPINFO structure (Win3.0)
    LPBITMAPCOREINFO    lpbmc;          // pointer to BITMAPCOREINFO structure (OS/2)
    BOOL                bWinStyleDIB;   // Win3.0 DIB?
 
    // if handle to DIB is invalid, return NULL
 
    if (! lpbi)
        return NULL;
 
    // get pointer to BITMAPINFO (Win 3.0)
 
    lpbmi = (LPBITMAPINFO)lpbi;
 
    // get pointer to BITMAPCOREINFO (OS/2 1.x)
 
    lpbmc = (LPBITMAPCOREINFO)lpbi;
 
    // get the number of colors in the DIB 
 
    wNumColors = DIBNumColors(lpbi);
 
    // is this a Win 3.0 DIB?
 
    bWinStyleDIB = IS_WIN30_DIB(lpbi);
    if (wNumColors)
    {
        // allocate memory block for logical palette
 
        hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) +
                sizeof(PALETTEENTRY) * wNumColors);
 
        // if not enough memory, clean up and return NULL
 
        if (!hLogPal)
            return NULL;
 
        // lock memory block and get pointer to it
 
        lpPal = (LPLOGPALETTE)GlobalLock(hLogPal);
 
        // set version and number of palette entries
 
        lpPal->palVersion = PALVERSION;
        lpPal->palNumEntries = wNumColors;
 
        // store RGB triples (if Win 3.0 DIB) or RGB quads (if OS/2 DIB)
        // into palette
        
        for (i = 0; i < wNumColors; i++)
        {
            if (bWinStyleDIB)
            {
                lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed;
                lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen;
                lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue;
                lpPal->palPalEntry[i].peFlags = 0;
            }
            else
            {
                lpPal->palPalEntry[i].peRed = lpbmc->bmciColors[i].rgbtRed;
                lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen;
                lpPal->palPalEntry[i].peBlue = lpbmc->bmciColors[i].rgbtBlue;
                lpPal->palPalEntry[i].peFlags = 0;
            }
        }
 
        // create the palette and get handle to it
 
        hPal = CreatePalette(lpPal);
 
        // if error getting handle to palette, clean up and return NULL
 
        if (!hPal)
        {
            GlobalUnlock(hLogPal);
            GlobalFree(hLogPal);
            return NULL;
        }
    }
 
    // return handle to DIB's palette
    return hPal;
}
 
/*************************************************************************
 *
 * CreateDIBPalette()
 *
 * Parameter:
 *
 * HDIB hDIB        - specifies the DIB
 *
 * Return Value:
 *
 * HPALETTE         - specifies the palette
 *
 * Description:
 *
 * This function creates a palette from a DIB by allocating memory for the
 * logical palette, reading and storing the colors from the DIB's color table
 * into the logical palette, creating a palette from this logical palette,
 * and then returning the palette's handle. This allows the DIB to be
 * displayed using the best possible colors (important for DIBs with 256 or
 * more colors).
 *
 ************************************************************************/
HPALETTE CreateDIBPalette(HDIB hDIB)
{
    HPALETTE            hPal = NULL;    // handle to a palette
    LPBYTE               lpbi;           // pointer to packed-DIB
 
    // if handle to DIB is invalid, return NULL
 
    if (!hDIB)
        return NULL;
 
    // lock DIB memory block and get a pointer to it
 
    lpbi = (LPBYTE)GlobalLock(hDIB);
 
 hPal = CreateDIBPalette(lpbi);

 // Unlock hDIB
    GlobalUnlock(hDIB);
 
    // return handle to DIB's palette
    return hPal;
}
 
/*************************************************************************
 *
 * DIBToBitmap()
 *
 * Parameters:
 *
 * HDIB hDIB        - specifies the DIB to convert
 *
 * HPALETTE hPal    - specifies the palette to use with the bitmap
 *
 * Return Value:
 *
 * HBITMAP          - identifies the device-dependent bitmap
 *
 * Description:
 *
 * This function creates a bitmap from a DIB using the specified palette.
 * If no palette is specified, default is used.
 *
 * NOTE:
 *
 * The bitmap returned from this funciton is always a bitmap compatible
 * with the screen (e.g. same bits/pixel and color planes) rather than
 * a bitmap with the same attributes as the DIB.  This behavior is by
 * design, and occurs because this function calls CreateDIBitmap to
 * do its work, and CreateDIBitmap always creates a bitmap compatible
 * with the hDC parameter passed in (because it in turn calls
 * CreateCompatibleBitmap).
 *
 * So for instance, if your DIB is a monochrome DIB and you call this
 * function, you will not get back a monochrome HBITMAP -- you will
 * get an HBITMAP compatible with the screen DC, but with only 2
 * colors used in the bitmap.
 *
 * If your application requires a monochrome HBITMAP returned for a
 * monochrome DIB, use the function SetDIBits().
 *
 * Also, the DIBpassed in to the function is not destroyed on exit. This
 * must be done later, once it is no longer needed.
 *
 ************************************************************************/
HBITMAP DIBToBitmap(HDIB hDIB, HPALETTE hPal)
{
    LPBYTE       lpDIBHdr, lpDIBBits;  // pointer to DIB header, pointer to DIB bits
    HBITMAP     hBitmap;            // handle to device-dependent bitmap
    HDC         hDC;                    // handle to DC
    HPALETTE    hOldPal = NULL;    // handle to a palette
 
    // if invalid handle, return NULL 
 
    if (!hDIB)
        return NULL;
 
    // lock memory block and get a pointer to it
 
    lpDIBHdr = (LPBYTE)GlobalLock(hDIB);
 
    // get a pointer to the DIB bits
 
    lpDIBBits = FindDIBBits(lpDIBHdr);
 
    // get a DC 
 
    hDC = GetDC(NULL);
    if (!hDC)
    {
        // clean up and return NULL
        GlobalUnlock(hDIB);
        return NULL;
    }
 
    // select and realize palette
 
    if (hPal)
 {
        hOldPal = SelectPalette(hDC, hPal, FALSE);
     RealizePalette(hDC);
 }
 
    // create bitmap from DIB info and bits
    hBitmap = CreateDIBitmap(hDC,
       (LPBITMAPINFOHEADER)lpDIBHdr,
       CBM_INIT,
       lpDIBBits,
       (LPBITMAPINFO)lpDIBHdr,
       DIB_RGB_COLORS);
 
    // restore previous palette
    if (hOldPal)
        SelectPalette(hDC, hOldPal, FALSE);
 
    // clean up
    ReleaseDC(NULL, hDC);
    GlobalUnlock(hDIB);
 
    // return handle to the bitmap
    return hBitmap;
}
 
 
/*************************************************************************
 *
 * BitmapToDIB()
 *
 * Parameters:
 *
 * HBITMAP hBitmap  - specifies the bitmap to convert
 *
 * HPALETTE hPal    - specifies the palette to use with the bitmap
 *
 * Return Value:
 *
 * HDIB             - identifies the device-dependent bitmap
 *
 * Description:
 *
 * This function creates a DIB from a bitmap using the specified palette.
 *
 ************************************************************************/
HDIB BitmapToDIB(HBITMAP hBitmap, HPALETTE hPal)
{
    BITMAP              bm;         // bitmap structure
    BITMAPINFOHEADER    bi;         // bitmap header
    LPBITMAPINFOHEADER  lpbi;       // pointer to BITMAPINFOHEADER
    DWORD               dwLen;      // size of memory block
    HANDLE              hDIB, h;    // handle to DIB, temp handle
    HDC                 hDC;        // handle to DC
    WORD                biBits;     // bits per pixel
 
    // check if bitmap handle is valid
 
    if (!hBitmap)
        return NULL;
 
    // fill in BITMAP structure, return NULL if it didn't work
 
    if (!GetObject(hBitmap, sizeof(bm), (LPBYTE)&bm))
        return NULL;
 
    // if no palette is specified, use default palette
 
    if (hPal == NULL)
        hPal = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
 
    // calculate bits per pixel
 
    biBits = bm.bmPlanes * bm.bmBitsPixel;
 
    // make sure bits per pixel is valid
 
    if (biBits <= 1)
        biBits = 1;
    else if (biBits <= 4)
        biBits = 4;
    else if (biBits <= 8)
        biBits = 8;
    else // if greater than 8-bit, force to 24-bit
        biBits = 24;
 
    // initialize BITMAPINFOHEADER
 
    bi.biSize = sizeof(BITMAPINFOHEADER);
    bi.biWidth = bm.bmWidth;
    bi.biHeight = bm.bmHeight;
    bi.biPlanes = 1;
    bi.biBitCount = biBits;
    bi.biCompression = BI_RGB;
    bi.biSizeImage = 0;
    bi.biXPelsPerMeter = 0;
    bi.biYPelsPerMeter = 0;
    bi.biClrUsed = 0;
    bi.biClrImportant = 0;
 
    // calculate size of memory block required to store BITMAPINFO
 
    dwLen = bi.biSize + PaletteSize((LPBYTE)&bi);
 
    // get a DC
 
    hDC = GetDC(NULL);
 
    // select and realize our palette
 
    hPal = SelectPalette(hDC, hPal, FALSE);
    RealizePalette(hDC);
 
    // alloc memory block to store our bitmap
 
    hDIB = GlobalAlloc(GHND, dwLen);
 
    // if we couldn't get memory block
 
    if (!hDIB)
    {
      // clean up and return NULL
 
      SelectPalette(hDC, hPal, TRUE);
      RealizePalette(hDC);
      ReleaseDC(NULL, hDC);
      return NULL;
    }
 
    // lock memory and get pointer to it
 
    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
 
    /// use our bitmap info. to fill BITMAPINFOHEADER
 
    *lpbi = bi;
 
    // call GetDIBits with a NULL lpBits param, so it will calculate the
    // biSizeImage field for us    
 
    GetDIBits(hDC, hBitmap, 0, (UINT)bi.biHeight, NULL, (LPBITMAPINFO)lpbi,
        DIB_RGB_COLORS);
 
    // get the info. returned by GetDIBits and unlock memory block
 
    bi = *lpbi;
    GlobalUnlock(hDIB);
 
    // if the driver did not fill in the biSizeImage field, make one up 
    if (bi.biSizeImage == 0)
        bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * biBits) * bm.bmHeight;
 
    // realloc the buffer big enough to hold all the bits
 
    dwLen = bi.biSize + PaletteSize((LPBYTE)&bi) + bi.biSizeImage;
 
    if (h = GlobalReAlloc(hDIB, dwLen, 0))
        hDIB = h;
    else
    {
        // clean up and return NULL
 
        GlobalFree(hDIB);
        hDIB = NULL;
        SelectPalette(hDC, hPal, TRUE);
        RealizePalette(hDC);
        ReleaseDC(NULL, hDC);
        return NULL;
    }
 
    // lock memory block and get pointer to it */
 
    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
 
    // call GetDIBits with a NON-NULL lpBits param, and actualy get the
    // bits this time
 
    if (GetDIBits(hDC, hBitmap, 0, (UINT)bi.biHeight, (LPBYTE)lpbi +
            (WORD)lpbi->biSize + PaletteSize((LPBYTE)lpbi), (LPBITMAPINFO)lpbi,
            DIB_RGB_COLORS) == 0)
    {
        // clean up and return NULL
 
        GlobalUnlock(hDIB);
        hDIB = NULL;
        SelectPalette(hDC, hPal, TRUE);
        RealizePalette(hDC);
        ReleaseDC(NULL, hDC);
        return NULL;
    }
 
    bi = *lpbi;
 
    // clean up 
    GlobalUnlock(hDIB);
    SelectPalette(hDC, hPal, TRUE);
    RealizePalette(hDC);
    ReleaseDC(NULL, hDC);
 
    // return handle to the DIB
    return hDIB;
}
 
/*************************************************************************
 *
 * BitmapToDIB()
 *
 * Parameters:
 *
 * HBITMAP hBitmap  - specifies the bitmap to convert
 *
 * HPALETTE hPal    - specifies the palette to use with the bitmap
 *
 * WORD wBitCount   - specifies the DIB colorbits
 *
 * Return Value:
 *
 * HDIB             - identifies the device-dependent bitmap
 *
 * Description:
 *
 * This function creates a DIB from a bitmap using the specified palette.
 *
 ************************************************************************/
HDIB BitmapToDIB(HBITMAP hBitmap, HPALETTE hPalette, WORD wBitCount)
{
 HDIB hNewDib;

 if (! hBitmap)
        return NULL;

 // get bitmap info
 BITMAP  bm;         // bitmap structure
 GetObject(hBitmap, sizeof(bm), (LPBYTE)&bm);
 int biBits = bm.bmPlanes * bm.bmBitsPixel;
 // make sure bits per pixel is valid
 if (biBits <= 1)
  biBits = 1;
 else if (biBits <= 4)
  biBits = 4;
 else if (biBits <= 8)
  biBits = 8;
 else // if greater than 8-bit, force to 24-bit
  biBits = 24;

 // get DIB handle from current bitmap
 HDIB hDib = BitmapToDIB(hBitmap, hPalette);
 if (! hDib)
        return NULL;

 if (wBitCount == biBits)
  hNewDib = hDib;
 else
 {
     // DIB bits/pixel is not the same as device
  // convert dib format to accordingly
  hNewDib = ConvertDIBFormat(hDib, wBitCount, hPalette);
  // cleanup hDib
  GlobalFree(hDib);
 }

 return hNewDib;
}


/*************************************************************************
 *
 * ChangeBitmapFormat()
 *
 * Parameter:
 *
 * HBITMAP          - handle to a bitmap
 *
 * WORD             - desired bits per pixel
 *
 * DWORD            - desired compression format
 *
 * HPALETTE         - handle to palette
 *
 * Return Value:
 *
 * HDIB             - handle to the new DIB if successful, else NULL
 *
 * Description:
 *
 * This function will convert a bitmap to the specified bits per pixel
 * and compression format. The bitmap and it's palette will remain
 * after calling this function.
 *
 ************************************************************************/
HDIB ChangeBitmapFormat (HBITMAP hbm, WORD biBits, DWORD biCompression, HPALETTE hpal)
{
    BITMAP               bm;
    BITMAPINFOHEADER     bi;
    LPBITMAPINFOHEADER   lpbi;
    DWORD                dwLen;
    HANDLE               hdib;
    HANDLE               h;
    HDC                  hdc;

    if (!hbm)
        return NULL;

    if (hpal == NULL)
        hpal = (HPALETTE)GetStockObject(DEFAULT_PALETTE);

    GetObject(hbm,sizeof(bm),(LPBYTE)&bm);

    if (biBits == 0)
 {
        biBits =  bm.bmPlanes * bm.bmBitsPixel;

  // make sure bits per pixel is valid
     if (biBits <= 1)
      biBits = 1;
     else if (biBits <= 4)
      biBits = 4;
     else if (biBits <= 8)
      biBits = 8;
  else // if greater than 8-bit, force to 24-bit
   biBits = 24;
 }

    bi.biSize               = sizeof(BITMAPINFOHEADER);
    bi.biWidth              = bm.bmWidth;
    bi.biHeight             = bm.bmHeight;
    bi.biPlanes             = 1;
    bi.biBitCount           = biBits;
    bi.biCompression        = biCompression;
    bi.biSizeImage          = 0;
    bi.biXPelsPerMeter      = 0;
    bi.biYPelsPerMeter      = 0;
    bi.biClrUsed            = 0;
    bi.biClrImportant       = 0;

    dwLen  = bi.biSize + PaletteSize((LPBYTE)&bi);

    hdc = GetDC(NULL);
    HPALETTE hpalT = SelectPalette(hdc,hpal,FALSE);
    RealizePalette(hdc);

    hdib = GlobalAlloc(GHND,dwLen);

    if (!hdib)
 {
        SelectPalette(hdc,hpalT,FALSE);
        ReleaseDC(NULL,hdc);
        return NULL;
    }

    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib);

    *lpbi = bi;

    /*  call GetDIBits with a NULL lpBits param, so it will calculate the
     *  biSizeImage field for us
     */
    GetDIBits(hdc, hbm, 0L, (DWORD)bi.biHeight,
        (LPBYTE)NULL, (LPBITMAPINFO)lpbi, (DWORD)DIB_RGB_COLORS);

    bi = *lpbi;
    GlobalUnlock(hdib);

    /* If the driver did not fill in the biSizeImage field, make one up */
    if (bi.biSizeImage == 0)
 {
        bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * biBits) * bm.bmHeight;

        if (biCompression != BI_RGB)
            bi.biSizeImage = (bi.biSizeImage * 3) / 2;
    }

    /*  realloc the buffer big enough to hold all the bits */
    dwLen = bi.biSize + PaletteSize((LPBYTE)&bi) + bi.biSizeImage;
    if (h = GlobalReAlloc(hdib,dwLen,0))
        hdib = h;
    else
 {
        GlobalFree(hdib);
        hdib = NULL;

        SelectPalette(hdc,hpalT,FALSE);
        ReleaseDC(NULL,hdc);
        return hdib;
    }

    /*  call GetDIBits with a NON-NULL lpBits param, and actualy get the
     *  bits this time
     */
    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hdib);

    if (! GetDIBits(hdc,
                    hbm,
                    0L,
                    (DWORD)bi.biHeight,
                    (LPBYTE)lpbi + (WORD)lpbi->biSize + PaletteSize((LPBYTE)lpbi),
                    (LPBITMAPINFO)lpbi,
     (DWORD)DIB_RGB_COLORS))
 {
         GlobalUnlock(hdib);
         hdib = NULL;
         SelectPalette(hdc,hpalT,FALSE);
         ReleaseDC(NULL,hdc);
         return NULL;
    }
    bi = *lpbi;
  
 GlobalUnlock(hdib);
    SelectPalette(hdc,hpalT,FALSE);
    ReleaseDC(NULL,hdc);
    return hdib;
}


/*************************************************************************
 *
 * ChangeDIBFormat()
 *
 * Parameter:
 *
 * HDIB             - handle to packed-DIB in memory
 *
 * WORD             - desired bits per pixel
 *
 * DWORD            - desired compression format
 *
 * Return Value:
 *
 * HDIB             - handle to the new DIB if successful, else NULL
 *
 * Description:
 *
 * This function will convert the bits per pixel and/or the compression
 * format of the specified DIB. Note: If the conversion was unsuccessful,
 * we return NULL. The original DIB is left alone. Don't use code like the
 * following:
 *
 *    hMyDIB = ChangeDIBFormat(hMyDIB, 8, BI_RLE4);
 *
 * The conversion will fail, but hMyDIB will now be NULL and the original
 * DIB will now hang around in memory. We could have returned the old
 * DIB, but we wanted to allow the programmer to check whether this
 * conversion succeeded or failed.
 *
 ************************************************************************/
HDIB ChangeDIBFormat(HDIB hDIB, WORD wBitCount, DWORD dwCompression)
{
    HBITMAP            hBitmap;         // Handle to bitmap
    HDIB               hNewDIB = NULL;  // Handle to new DIB
    HPALETTE           hPal;   // Handle to palette

    // Check for a valid DIB handle
 
    if (!hDIB)
        return NULL;
 
    // Save the old DIB's palette
 
    hPal = CreateDIBPalette(hDIB);
    if (hPal == NULL)
        hPal = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
 
    // Convert old DIB to a bitmap
 
    hBitmap = DIBToBitmap(hDIB, hPal);
    if (!hBitmap)
    {
        DeleteObject(hPal);
        return NULL;
    }

 // Change bitmap format

 hNewDIB = ChangeBitmapFormat(hBitmap, wBitCount, dwCompression, hPal);
 
    // Clean up and return
 
    DeleteObject(hBitmap);
    DeleteObject(hPal);
 
    return hNewDIB;
}
 

/****************************************************************************
*
*     FUNCTION: ConvertDIBFormat
*
*     PURPOSE:  Creates a new DIB of the requested format, copies the source
*               image to the new DIB.
*
*     PARAMS:   LPBITMAPINFO lpSrcDIB - the source CF_DIB
*               UINT         nWidth   - width for new DIB
*               UINT         nHeight  - height for new DIB
*               UINT         nbpp     - bpp for new DIB
*               BOOL         bStretch - TRUE to stretch source to dest
*                                       FALSE to take upper left of image
*    HPALETTE  hPalSrc  - Palette used to set new DIB
*    DWORD   dwSize   - return the size of new DIB pointer
*
*     RETURNS:  HDIB - Handle of CF_DIB memory block with new image
*               NULL on failure
*
/****************************************************************************/
HDIB ConvertDIBFormat(LPBYTE lpDIB, UINT nWidth, UINT nHeight, UINT nbpp, BOOL bStretch, HPALETTE hPalSrc)
{
 LPBITMAPINFO lpSrcDIB =  (LPBITMAPINFO)lpDIB;
    LPBITMAPINFO lpbmi = NULL;
    LPBYTE       lpSourceBits, lpTargetBits, lpResult;
    HDC    hDC = NULL, hSourceDC, hTargetDC;
    HBITMAP      hSourceBitmap, hTargetBitmap, hOldTargetBitmap, hOldSourceBitmap;
    DWORD        dwSourceBitsSize, dwTargetBitsSize, dwTargetHeaderSize, dwColorNum;
 HDIB   hDib;
 
    // Allocate and fill out a BITMAPINFO struct for the new DIB
    if (nbpp <= 8)
  dwColorNum = 1 << nbpp;
 else
  dwColorNum = 0;
    dwTargetHeaderSize = sizeof( BITMAPINFO ) + ( dwColorNum * sizeof( RGBQUAD ) );
    lpbmi = (LPBITMAPINFO)malloc( dwTargetHeaderSize );
    lpbmi->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
    lpbmi->bmiHeader.biWidth = nWidth;
    lpbmi->bmiHeader.biHeight = nHeight;
    lpbmi->bmiHeader.biPlanes = 1;
    lpbmi->bmiHeader.biBitCount = nbpp;
    lpbmi->bmiHeader.biCompression = BI_RGB;
    lpbmi->bmiHeader.biSizeImage = 0;
    lpbmi->bmiHeader.biXPelsPerMeter = 0;
    lpbmi->bmiHeader.biYPelsPerMeter = 0;
    lpbmi->bmiHeader.biClrUsed = 0;
    lpbmi->bmiHeader.biClrImportant = 0;
    // Fill in the color table
    if( ! CopyColorTable( lpbmi, (LPBITMAPINFO)lpSrcDIB, hPalSrc ) )
    {
        free( lpbmi );
        return NULL;
    }
 
    // Gonna use DIBSections and BitBlt() to do the conversion, so make 'em
 hDC = GetDC( NULL );
    hTargetBitmap = CreateDIBSection( hDC, lpbmi, DIB_RGB_COLORS, (VOID **)&lpTargetBits, NULL, 0 );
    hSourceBitmap = CreateDIBSection( hDC, lpSrcDIB, DIB_RGB_COLORS, (VOID **)&lpSourceBits, NULL, 0 );
    hSourceDC = CreateCompatibleDC( hDC );
    hTargetDC = CreateCompatibleDC( hDC );
 
    // Flip the bits on the source DIBSection to match the source DIB
    dwSourceBitsSize = lpSrcDIB->bmiHeader.biHeight * BytesPerLine((LPBYTE)&(lpSrcDIB->bmiHeader));
    dwTargetBitsSize = lpbmi->bmiHeader.biHeight * BytesPerLine((LPBYTE)&(lpbmi->bmiHeader));
    memcpy( lpSourceBits, FindDIBBits((LPBYTE)lpSrcDIB), dwSourceBitsSize );
    lpbmi->bmiHeader.biSizeImage = dwTargetBitsSize;
 
    // Select DIBSections into DCs
    hOldSourceBitmap = (HBITMAP)SelectObject( hSourceDC, hSourceBitmap );
    hOldTargetBitmap = (HBITMAP)SelectObject( hTargetDC, hTargetBitmap );
 
    // Set the color tables for the DIBSections
    if( lpSrcDIB->bmiHeader.biBitCount <= 8 )
        SetDIBColorTable( hSourceDC, 0, 1 << lpSrcDIB->bmiHeader.biBitCount, lpSrcDIB->bmiColors );
    if( lpbmi->bmiHeader.biBitCount <= 8 )
        SetDIBColorTable( hTargetDC, 0, 1 << lpbmi->bmiHeader.biBitCount, lpbmi->bmiColors );
 
    // If we are asking for a straight copy, do it
    if( (lpSrcDIB->bmiHeader.biWidth==lpbmi->bmiHeader.biWidth) && (lpSrcDIB->bmiHeader.biHeight==lpbmi->bmiHeader.biHeight) )
    {
        BitBlt( hTargetDC, 0, 0, lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight, hSourceDC, 0, 0, SRCCOPY );
    }
    else
    {
        // else, should we stretch it?
        if( bStretch )
        {
            SetStretchBltMode( hTargetDC, COLORONCOLOR );
            StretchBlt( hTargetDC, 0, 0, lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight, hSourceDC, 0, 0, lpSrcDIB->bmiHeader.biWidth, lpSrcDIB->bmiHeader.biHeight, SRCCOPY );
        }
        else
        {
            // or just take the upper left corner of the source
            BitBlt( hTargetDC, 0, 0, lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight, hSourceDC, 0, 0, SRCCOPY );
        }
    }
 
    // Clean up and delete the DCs
    SelectObject( hSourceDC, hOldSourceBitmap );
    SelectObject( hTargetDC, hOldTargetBitmap );
    DeleteDC( hSourceDC );
    DeleteDC( hTargetDC );
    ReleaseDC( NULL, hDC );
 
    // Flush the GDI batch, so we can play with the bits
    GdiFlush();
 
    // Allocate enough memory for the new CF_DIB, and copy bits
    hDib = GlobalAlloc(GHND, dwTargetHeaderSize + dwTargetBitsSize );
    lpResult = (LPBYTE)GlobalLock(hDib);
    memcpy( lpResult, lpbmi, dwTargetHeaderSize );
    memcpy( FindDIBBits( (LPBYTE)lpResult ), lpTargetBits, dwTargetBitsSize );
 
    // final cleanup
    DeleteObject( hTargetBitmap );
    DeleteObject( hSourceBitmap );
 free( lpbmi );
    GlobalUnlock(hDib);
 
    return hDib;
}
/* End ConvertDIBFormat() 1***************************************************/

/****************************************************************************
*
*     FUNCTION: ConvertDIBFormat
*
*     PURPOSE:  Creates a new DIB of the requested format, copies the source
*               image to the new DIB.
*
*     PARAMS:   HDIB   hDIB     - the source CF_DIB
*               UINT         nWidth   - width for new DIB
*               UINT         nHeight  - height for new DIB
*               UINT         nbpp     - bpp for new DIB
*               BOOL         bStretch - TRUE to stretch source to dest
*                                       FALSE to take upper left of image
*    HPALETTE  hPalSrc  - Palette used to set new DIB
*
*     RETURNS:  HDIB - new CF_DIB handle
*
/****************************************************************************/
HDIB ConvertDIBFormat(HDIB hDIB, UINT nWidth, UINT nHeight, UINT nbpp, BOOL bStretch, HPALETTE hPalSrc)
{
    LPBITMAPINFO lpbmi = NULL;
    LPBYTE       lpSourceBits, lpTargetBits, lpResult;
    HDC    hDC = NULL, hSourceDC, hTargetDC;
    HBITMAP      hSourceBitmap, hTargetBitmap, hOldTargetBitmap, hOldSourceBitmap;
    DWORD        dwSourceBitsSize, dwTargetBitsSize, dwTargetHeaderSize, dwColorNum;
 HDIB   hNewDIB;
 DWORD   dwSize;

 // Get DIB pointer
 if (! hDIB)
  return NULL;
 LPBITMAPINFO lpSrcDIB = (LPBITMAPINFO)GlobalLock(hDIB);
 if (! lpSrcDIB)
  return NULL;

    // Allocate and fill out a BITMAPINFO struct for the new DIB
    if (nbpp <= 8)
  dwColorNum = 1 << nbpp;
 else
  dwColorNum = 0;
    dwTargetHeaderSize = sizeof( BITMAPINFO ) + ( dwColorNum * sizeof( RGBQUAD ) );
    lpbmi = (LPBITMAPINFO)malloc( dwTargetHeaderSize );
    lpbmi->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
    lpbmi->bmiHeader.biWidth = nWidth;
    lpbmi->bmiHeader.biHeight = nHeight;
    lpbmi->bmiHeader.biPlanes = 1;
    lpbmi->bmiHeader.biBitCount = nbpp;
    lpbmi->bmiHeader.biCompression = BI_RGB;
    lpbmi->bmiHeader.biSizeImage = 0;
    lpbmi->bmiHeader.biXPelsPerMeter = 0;
    lpbmi->bmiHeader.biYPelsPerMeter = 0;
    lpbmi->bmiHeader.biClrUsed = 0;
    lpbmi->bmiHeader.biClrImportant = 0;
    // Fill in the color table
    if( ! CopyColorTable( lpbmi, (LPBITMAPINFO)lpSrcDIB, hPalSrc ) )
    {
        free( lpbmi );
        return NULL;
    }
 
    // Gonna use DIBSections and BitBlt() to do the conversion, so make 'em
 hDC = GetDC( NULL );
    hTargetBitmap = CreateDIBSection( hDC, lpbmi, DIB_RGB_COLORS, (VOID **)&lpTargetBits, NULL, 0 );
    hSourceBitmap = CreateDIBSection( hDC, lpSrcDIB, DIB_RGB_COLORS, (VOID **)&lpSourceBits, NULL, 0 );
    hSourceDC = CreateCompatibleDC( hDC );
    hTargetDC = CreateCompatibleDC( hDC );
 
    // Flip the bits on the source DIBSection to match the source DIB
    dwSourceBitsSize = lpSrcDIB->bmiHeader.biHeight * BytesPerLine((LPBYTE)&(lpSrcDIB->bmiHeader));
    dwTargetBitsSize = lpbmi->bmiHeader.biHeight * BytesPerLine((LPBYTE)&(lpbmi->bmiHeader));
    memcpy( lpSourceBits, FindDIBBits((LPBYTE)lpSrcDIB), dwSourceBitsSize );
    lpbmi->bmiHeader.biSizeImage = dwTargetBitsSize;
 
    // Select DIBSections into DCs
    hOldSourceBitmap = (HBITMAP)SelectObject( hSourceDC, hSourceBitmap );
    hOldTargetBitmap = (HBITMAP)SelectObject( hTargetDC, hTargetBitmap );
 
    // Set the color tables for the DIBSections
    if( lpSrcDIB->bmiHeader.biBitCount <= 8 )
        SetDIBColorTable( hSourceDC, 0, 1 << lpSrcDIB->bmiHeader.biBitCount, lpSrcDIB->bmiColors );
    if( lpbmi->bmiHeader.biBitCount <= 8 )
        SetDIBColorTable( hTargetDC, 0, 1 << lpbmi->bmiHeader.biBitCount, lpbmi->bmiColors );
 
    // If we are asking for a straight copy, do it
    if( (lpSrcDIB->bmiHeader.biWidth==lpbmi->bmiHeader.biWidth) && (lpSrcDIB->bmiHeader.biHeight==lpbmi->bmiHeader.biHeight) )
    {
        BitBlt( hTargetDC, 0, 0, lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight, hSourceDC, 0, 0, SRCCOPY );
    }
    else
    {
        // else, should we stretch it?
        if( bStretch )
        {
            SetStretchBltMode( hTargetDC, COLORONCOLOR );
            StretchBlt( hTargetDC, 0, 0, lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight, hSourceDC, 0, 0, lpSrcDIB->bmiHeader.biWidth, lpSrcDIB->bmiHeader.biHeight, SRCCOPY );
        }
        else
        {
            // or just take the upper left corner of the source
            BitBlt( hTargetDC, 0, 0, lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight, hSourceDC, 0, 0, SRCCOPY );
        }
    }
 
    // Clean up and delete the DCs
    SelectObject( hSourceDC, hOldSourceBitmap );
    SelectObject( hTargetDC, hOldTargetBitmap );
    DeleteDC( hSourceDC );
    DeleteDC( hTargetDC );
    ReleaseDC( NULL, hDC );
 
    // Flush the GDI batch, so we can play with the bits
    GdiFlush();
 
    // Allocate enough memory for the new CF_DIB, and copy bits
 dwSize = dwTargetHeaderSize + dwTargetBitsSize;
 hNewDIB = GlobalAlloc(GHND, dwSize);
    lpResult = (LPBYTE)GlobalLock(hNewDIB);//malloc( dwTargetHeaderSize + dwTargetBitsSize );
    memcpy( lpResult, lpbmi, dwTargetHeaderSize );
    memcpy( FindDIBBits( (LPBYTE)lpResult ), lpTargetBits, dwTargetBitsSize );
 
    // final cleanup
    DeleteObject( hTargetBitmap );
    DeleteObject( hSourceBitmap );
    free( lpbmi );
 GlobalUnlock(hDIB);
 GlobalUnlock(hNewDIB);
 
    return hNewDIB;
}
/* End ConvertDIBFormat() 2***************************************************/

/****************************************************************************
*
*     FUNCTION: ConvertDIBFormat
*
*     PURPOSE:  Creates a new DIB of the requested format, copies the source
*               image to the new DIB.
*
*     PARAMS:   LPBYTE   lpDIB    - the source CF_DIB
*               UINT         nbpp     - bpp for new DIB
*    HPALETTE  hPalSrc  - Palette used to set new DIB
*
*     RETURNS:  HDIB - new CF_DIB handle
*
/****************************************************************************/
HDIB ConvertDIBFormat(LPBYTE lpDIB, UINT nbpp, HPALETTE hPalSrc)
{
 LPBITMAPINFO lpSrcDIB = (LPBITMAPINFO)lpDIB;
    LPBITMAPINFO lpbmi = NULL;
    LPBYTE       lpSourceBits, lpTargetBits, lpResult;
    HDC    hDC = NULL, hSourceDC, hTargetDC;
    HBITMAP      hSourceBitmap, hTargetBitmap, hOldTargetBitmap, hOldSourceBitmap;
    DWORD        dwSourceBitsSize, dwTargetBitsSize, dwTargetHeaderSize, dwColorNum;
 HDIB   hNewDIB;
 DWORD   dwSize;
 int    nWidth, nHeight;

 nWidth = lpSrcDIB->bmiHeader.biWidth;
 nHeight = lpSrcDIB->bmiHeader.biHeight;

    // Allocate and fill out a BITMAPINFO struct for the new DIB
    if (nbpp <= 8)
  dwColorNum = 1 << nbpp;
 else
  dwColorNum = 0;
    dwTargetHeaderSize = sizeof( BITMAPINFO ) + ( dwColorNum * sizeof( RGBQUAD ) );
    lpbmi = (LPBITMAPINFO)malloc( dwTargetHeaderSize );
    lpbmi->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
    lpbmi->bmiHeader.biWidth = nWidth;
    lpbmi->bmiHeader.biHeight = nHeight;
    lpbmi->bmiHeader.biPlanes = 1;
    lpbmi->bmiHeader.biBitCount = nbpp;
    lpbmi->bmiHeader.biCompression = BI_RGB;
    lpbmi->bmiHeader.biSizeImage = 0;
    lpbmi->bmiHeader.biXPelsPerMeter = 0;
    lpbmi->bmiHeader.biYPelsPerMeter = 0;
    lpbmi->bmiHeader.biClrUsed = 0;
    lpbmi->bmiHeader.biClrImportant = 0;
    // Fill in the color table
    if( ! CopyColorTable( lpbmi, (LPBITMAPINFO)lpSrcDIB, hPalSrc ) )
    {
        free( lpbmi );
        return NULL;
    }
 
    // Gonna use DIBSections and BitBlt() to do the conversion, so make 'em
 hDC = GetDC( NULL );
    hTargetBitmap = CreateDIBSection( hDC, lpbmi, DIB_RGB_COLORS, (VOID **)&lpTargetBits, NULL, 0 );
    hSourceBitmap = CreateDIBSection( hDC, lpSrcDIB, DIB_RGB_COLORS, (VOID **)&lpSourceBits, NULL, 0 );
    hSourceDC = CreateCompatibleDC( hDC );
    hTargetDC = CreateCompatibleDC( hDC );
 
    // Flip the bits on the source DIBSection to match the source DIB
    dwSourceBitsSize = lpSrcDIB->bmiHeader.biHeight * BytesPerLine((LPBYTE)&(lpSrcDIB->bmiHeader));
    dwTargetBitsSize = lpbmi->bmiHeader.biHeight * BytesPerLine((LPBYTE)&(lpbmi->bmiHeader));
    memcpy( lpSourceBits, FindDIBBits((LPBYTE)lpSrcDIB), dwSourceBitsSize );
    lpbmi->bmiHeader.biSizeImage = dwTargetBitsSize;
 
    // Select DIBSections into DCs
    hOldSourceBitmap = (HBITMAP)SelectObject( hSourceDC, hSourceBitmap );
    hOldTargetBitmap = (HBITMAP)SelectObject( hTargetDC, hTargetBitmap );
 
    // Set the color tables for the DIBSections
    if( lpSrcDIB->bmiHeader.biBitCount <= 8 )
        SetDIBColorTable( hSourceDC, 0, 1 << lpSrcDIB->bmiHeader.biBitCount, lpSrcDIB->bmiColors );
    if( lpbmi->bmiHeader.biBitCount <= 8 )
        SetDIBColorTable( hTargetDC, 0, 1 << lpbmi->bmiHeader.biBitCount, lpbmi->bmiColors );
 
    // We are asking for a straight copy, do it
    BitBlt( hTargetDC, 0, 0, lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight, hSourceDC, 0, 0, SRCCOPY );
 
    // Clean up and delete the DCs
    SelectObject( hSourceDC, hOldSourceBitmap );
    SelectObject( hTargetDC, hOldTargetBitmap );
    DeleteDC( hSourceDC );
    DeleteDC( hTargetDC );
    ReleaseDC( NULL, hDC );
 
    // Flush the GDI batch, so we can play with the bits
    GdiFlush();
 
    // Allocate enough memory for the new CF_DIB, and copy bits
 dwSize = dwTargetHeaderSize + dwTargetBitsSize;
 hNewDIB = GlobalAlloc(GHND, dwSize);
    lpResult = (LPBYTE)GlobalLock(hNewDIB);//malloc( dwTargetHeaderSize + dwTargetBitsSize );
    memcpy( lpResult, lpbmi, dwTargetHeaderSize );
    memcpy( FindDIBBits( (LPBYTE)lpResult ), lpTargetBits, dwTargetBitsSize );
 
    // final cleanup
    DeleteObject( hTargetBitmap );
    DeleteObject( hSourceBitmap );
    free( lpbmi );
 GlobalUnlock(hNewDIB);
 
    return hNewDIB;
}
/* End ConvertDIBFormat() 3***************************************************/

/****************************************************************************
*
*     FUNCTION: ConvertDIBFormat
*
*     PURPOSE:  Creates a new DIB of the requested format, copies the source
*               image to the new DIB.
*
*     PARAMS:   HDIB   hDIB     - the source CF_DIB
*               UINT         nbpp     - bpp for new DIB
*    HPALETTE  hPalSrc  - Palette used to set new DIB
*
*     RETURNS:  HDIB - new CF_DIB handle
*
/****************************************************************************/
HDIB ConvertDIBFormat(HDIB hDIB, UINT nbpp, HPALETTE hPalSrc)
{
    LPBITMAPINFO lpbmi = NULL;
    LPBYTE       lpSourceBits, lpTargetBits, lpResult;
    HDC    hDC = NULL, hSourceDC, hTargetDC;
    HBITMAP      hSourceBitmap, hTargetBitmap, hOldTargetBitmap, hOldSourceBitmap;
    DWORD        dwSourceBitsSize, dwTargetBitsSize, dwTargetHeaderSize, dwColorNum;
 HANDLE   hNewDIB;
 DWORD   dwSize;
 int    nWidth, nHeight;

 // Get DIB pointer
 if (! hDIB)
  return NULL;
 LPBITMAPINFO lpSrcDIB = (LPBITMAPINFO)GlobalLock(hDIB);
 if (! lpSrcDIB)
  return NULL;
 nWidth = lpSrcDIB->bmiHeader.biWidth;
 nHeight = lpSrcDIB->bmiHeader.biHeight;

    // Allocate and fill out a BITMAPINFO struct for the new DIB
    if (nbpp <= 8)
  dwColorNum = 1 << nbpp;
 else
  dwColorNum = 0;
    dwTargetHeaderSize = sizeof( BITMAPINFO ) + ( dwColorNum * sizeof( RGBQUAD ) );
    lpbmi = (LPBITMAPINFO)malloc( dwTargetHeaderSize );
    lpbmi->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
    lpbmi->bmiHeader.biWidth = nWidth;
    lpbmi->bmiHeader.biHeight = nHeight;
    lpbmi->bmiHeader.biPlanes = 1;
    lpbmi->bmiHeader.biBitCount = nbpp;
    lpbmi->bmiHeader.biCompression = BI_RGB;
    lpbmi->bmiHeader.biSizeImage = 0;
    lpbmi->bmiHeader.biXPelsPerMeter = 0;
    lpbmi->bmiHeader.biYPelsPerMeter = 0;
    lpbmi->bmiHeader.biClrUsed = 0;
    lpbmi->bmiHeader.biClrImportant = 0;
    // Fill in the color table
    if( ! CopyColorTable( lpbmi, (LPBITMAPINFO)lpSrcDIB, hPalSrc ) )
    {
        free( lpbmi );
        return NULL;
    }
 
    // Gonna use DIBSections and BitBlt() to do the conversion, so make 'em
 hDC = GetDC( NULL );
    hTargetBitmap = CreateDIBSection( hDC, lpbmi, DIB_RGB_COLORS, (VOID **)&lpTargetBits, NULL, 0 );
    hSourceBitmap = CreateDIBSection( hDC, lpSrcDIB, DIB_RGB_COLORS, (VOID **)&lpSourceBits, NULL, 0 );
    hSourceDC = CreateCompatibleDC( hDC );
    hTargetDC = CreateCompatibleDC( hDC );
 
    // Flip the bits on the source DIBSection to match the source DIB
    dwSourceBitsSize = lpSrcDIB->bmiHeader.biHeight * BytesPerLine((LPBYTE)&(lpSrcDIB->bmiHeader));
    dwTargetBitsSize = lpbmi->bmiHeader.biHeight * BytesPerLine((LPBYTE)&(lpbmi->bmiHeader));
    memcpy( lpSourceBits, FindDIBBits((LPBYTE)lpSrcDIB), dwSourceBitsSize );
    lpbmi->bmiHeader.biSizeImage = dwTargetBitsSize;
 
    // Select DIBSections into DCs
    hOldSourceBitmap = (HBITMAP)SelectObject( hSourceDC, hSourceBitmap );
    hOldTargetBitmap = (HBITMAP)SelectObject( hTargetDC, hTargetBitmap );
 
    // Set the color tables for the DIBSections
    if( lpSrcDIB->bmiHeader.biBitCount <= 8 )
        SetDIBColorTable( hSourceDC, 0, 1 << lpSrcDIB->bmiHeader.biBitCount, lpSrcDIB->bmiColors );
    if( lpbmi->bmiHeader.biBitCount <= 8 )
        SetDIBColorTable( hTargetDC, 0, 1 << lpbmi->bmiHeader.biBitCount, lpbmi->bmiColors );
 
    // We are asking for a straight copy, do it
    BitBlt( hTargetDC, 0, 0, lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight, hSourceDC, 0, 0, SRCCOPY );
 
    // Clean up and delete the DCs
    SelectObject( hSourceDC, hOldSourceBitmap );
    SelectObject( hTargetDC, hOldTargetBitmap );
    DeleteDC( hSourceDC );
    DeleteDC( hTargetDC );
    ReleaseDC( NULL, hDC );
 
    // Flush the GDI batch, so we can play with the bits
    GdiFlush();
 
    // Allocate enough memory for the new CF_DIB, and copy bits
 dwSize = dwTargetHeaderSize + dwTargetBitsSize;
 hNewDIB = GlobalAlloc(GHND, dwSize);
    lpResult = (LPBYTE)GlobalLock(hNewDIB);//malloc( dwTargetHeaderSize + dwTargetBitsSize );
    memcpy( lpResult, lpbmi, dwTargetHeaderSize );
    memcpy( FindDIBBits( (LPBYTE)lpResult ), lpTargetBits, dwTargetBitsSize );
 
    // final cleanup
    DeleteObject( hTargetBitmap );
    DeleteObject( hSourceBitmap );
    free( lpbmi );
 GlobalUnlock(hDIB);
 GlobalUnlock(hNewDIB);
 
    return hNewDIB;
}
/* End ConvertDIBFormat() 4***************************************************/
 
/****************************************************************************
*
*     FUNCTION: CopyColorTable
*
*     PURPOSE:  Copies the color table from one CF_DIB to another.
*
*     PARAMS:   LPBITMAPINFO lpTarget - pointer to target DIB
*               LPBITMAPINFO lpSource - pointer to source DIB
*
*     RETURNS:  BOOL - TRUE for success, FALSE for failure
*
/****************************************************************************/
BOOL CopyColorTable( LPBITMAPINFO lpTarget, LPBITMAPINFO lpSource, HPALETTE hPalSrc )
{
    // What we do depends on the target's color depth
    switch( lpTarget->bmiHeader.biBitCount )
    {
        // 8bpp - need 256 entry color table
        case 8:
   if (hPalSrc)
   { // Palette is provided, use it
    PALETTEENTRY    pe[256];
    UINT            i;

    GetPaletteEntries( hPalSrc, 0, 256, pe );
    for(i=0;i<256;i++)
    {
     lpTarget->bmiColors[i].rgbRed = pe[i].peRed;
     lpTarget->bmiColors[i].rgbGreen = pe[i].peGreen;
     lpTarget->bmiColors[i].rgbBlue = pe[i].peBlue;
     lpTarget->bmiColors[i].rgbReserved = 0;
    }
   }
   else
   { // no palette povided
    if( lpSource->bmiHeader.biBitCount == 8 )
    { // Source is 8bpp too, copy color table
     memcpy( lpTarget->bmiColors, lpSource->bmiColors, 256*sizeof(RGBQUAD) );
    }
    else
    { // Source is != 8bpp, use Octree algorithm to create palette
     HPALETTE        hPal;
     HDC            hDC = GetDC( NULL );
     PALETTEENTRY    pe[256];
     UINT            i;
 
     hPal = CreateOctreePalette((LPBYTE)lpSource, 236, 8);
     if (! hPal)  // use halftone palette                
      hPal = CreateHalftonePalette( hDC );
     ReleaseDC( NULL, hDC );

     GetPaletteEntries( hPal, 0, 256, pe );
     DeleteObject( hPal );
     for(i=0;i<256;i++)
     {
      lpTarget->bmiColors[i].rgbRed = pe[i].peRed;
      lpTarget->bmiColors[i].rgbGreen = pe[i].peGreen;
      lpTarget->bmiColors[i].rgbBlue = pe[i].peBlue;
      lpTarget->bmiColors[i].rgbReserved = pe[i].peFlags;
     }
    }
   }
   break; // end 8bpp
 
        // 4bpp - need 16 entry color table
        case 4:
   if (hPalSrc)
   { // Palette is provided, use it
    PALETTEENTRY    pe[16];
    UINT            i;

    GetPaletteEntries( hPalSrc, 0, 16, pe );
    for(i=0;i<16;i++)
    {
     lpTarget->bmiColors[i].rgbRed = pe[i].peRed;
     lpTarget->bmiColors[i].rgbGreen = pe[i].peGreen;
     lpTarget->bmiColors[i].rgbBlue = pe[i].peBlue;
     lpTarget->bmiColors[i].rgbReserved = 0;
    }
   }
   else
   { // No palette is provided
    if( lpSource->bmiHeader.biBitCount == 4 )
    { // Source is 4bpp too, copy color table
     memcpy( lpTarget->bmiColors, lpSource->bmiColors, 16*sizeof(RGBQUAD) );
    }
    else
    { // Source is != 4bpp, use system palette
     HPALETTE        hPal;
     PALETTEENTRY    pe[256];
     UINT            i;
 
     hPal = (HPALETTE)GetStockObject( DEFAULT_PALETTE );
     GetPaletteEntries( hPal, 0, 16, pe );
     for(i=0;i<16;i++)
     {
      lpTarget->bmiColors[i].rgbRed = pe[i].peRed;
      lpTarget->bmiColors[i].rgbGreen = pe[i].peGreen;
      lpTarget->bmiColors[i].rgbBlue = pe[i].peBlue;
      lpTarget->bmiColors[i].rgbReserved = pe[i].peFlags;
     }
                }
   }
   break; // end 4bpp
 
        // 1bpp - need 2 entry mono color table
        case 1:
            lpTarget->bmiColors[0].rgbRed = 0;
            lpTarget->bmiColors[0].rgbGreen = 0;
            lpTarget->bmiColors[0].rgbBlue = 0;
            lpTarget->bmiColors[0].rgbReserved = 0;
            lpTarget->bmiColors[1].rgbRed = 255;
            lpTarget->bmiColors[1].rgbGreen = 255;
            lpTarget->bmiColors[1].rgbBlue = 255;
            lpTarget->bmiColors[1].rgbReserved = 0;
   break; // end 1bpp
 
        // no color table for the > 8bpp modes
        case 32:
        case 24:
        case 16:
        default:
         break;
    }
    return TRUE;
}
/* End CopyColorTable() *****************************************************/

/****************************************************************************
*
*     FUNCTION: DIBToDIBSection
*
*     PURPOSE:  Create DIBSECTION from DIB
*
*     PARAMS:   LPBYTE lpDIB - pointer to DIB data buffer
*
*     RETURNS:  HBITMAP - handle of DIBSECTION, or NULL for failure
*
/****************************************************************************/
HBITMAP DIBToDIBSection(LPBYTE lpDIB)
{
    LPBYTE       lpSourceBits;
    HDC    hDC = NULL, hSourceDC;
    HBITMAP      hSourceBitmap, hOldSourceBitmap;
    DWORD        dwSourceBitsSize;

 LPBITMAPINFO lpSrcDIB = (LPBITMAPINFO)lpDIB;
 if (! lpSrcDIB)
  return NULL;

    // Gonna use DIBSections and BitBlt() to do the conversion, so make 'em
 hDC = GetDC( NULL );
    hSourceBitmap = CreateDIBSection( hDC, lpSrcDIB, DIB_RGB_COLORS, (VOID **)&lpSourceBits, NULL, 0 );
    hSourceDC = CreateCompatibleDC( hDC );
 
    // Flip the bits on the source DIBSection to match the source DIB
    dwSourceBitsSize = lpSrcDIB->bmiHeader.biHeight * BytesPerLine((LPBYTE)&(lpSrcDIB->bmiHeader));
    memcpy( lpSourceBits, FindDIBBits((LPBYTE)lpSrcDIB), dwSourceBitsSize );
 
    // Select DIBSections into DCs
    hOldSourceBitmap = (HBITMAP)SelectObject( hSourceDC, hSourceBitmap );
 
    // Set the color tables for the DIBSections
    if( lpSrcDIB->bmiHeader.biBitCount <= 8 )
        SetDIBColorTable( hSourceDC, 0, 1 << lpSrcDIB->bmiHeader.biBitCount, lpSrcDIB->bmiColors );

    // Clean up and delete the DCs
    SelectObject( hSourceDC, hOldSourceBitmap );
    DeleteDC( hSourceDC );
    ReleaseDC( NULL, hDC );
 
    // Flush the GDI batch, so we can play with the bits
    GdiFlush();
 
    return hSourceBitmap;
}

// Create DIBSECTION from DIB
HBITMAP DIBToDIBSection(HDIB hDIB)
{
    HBITMAP      hSourceBitmap;

 // Get DIB pointer
 if (! hDIB)
  return NULL;
 LPBYTE lpSrcDIB = (LPBYTE)GlobalLock(hDIB);
 if (! lpSrcDIB)
  return NULL;

 hSourceBitmap = DIBToDIBSection(lpSrcDIB);

    // final cleanup
 GlobalUnlock(hDIB);
 
    return hSourceBitmap;
}

/****************************************************************************
*
*     FUNCTION: DIBSectionToDIB
*
*     PURPOSE:  Create DIB from DIBSECTION
*
*     PARAMS:   HBITMAP - handle of DIBSECTION, or NULL for failure
*
*     RETURNS:  HBITMAP hBitmap - DIB handle
*
/****************************************************************************/
HDIB DIBSectionToDIB(HBITMAP hBitmap)
{
    HDC    hDC = NULL, hSourceDC;
 HBITMAP   hOldSourceBitmap;
 HANDLE   hNewDIB;
    LPBITMAPINFO lpbmi = NULL;
 DWORD   dwSize;
 DIBSECTION   ds;
    DWORD   dwColorNum;

 // get DIB info
 GetObject(hBitmap, sizeof(DIBSECTION), &ds);
    dwColorNum = ds.dsBmih.biClrUsed;
    if (dwColorNum == 0 && ds.dsBmih.biBitCount <= 8)
  dwColorNum = 1 << ds.dsBmih.biBitCount;

    // Allocate and fill out a BITMAPINFO struct for the new DIB
 dwSize = sizeof(BITMAPINFOHEADER) + (dwColorNum * sizeof(RGBQUAD)) + ds.dsBmih.biSizeImage;
 hNewDIB = GlobalAlloc(GHND, dwSize);
 if (! hNewDIB)
  return NULL;
 lpbmi = (LPBITMAPINFO)GlobalLock(hNewDIB);
 if (! lpbmi)
  return NULL;
    lpbmi->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
    lpbmi->bmiHeader.biWidth = ds.dsBm.bmWidth;
    lpbmi->bmiHeader.biHeight = ds.dsBm.bmHeight;
    lpbmi->bmiHeader.biPlanes = 1;
    lpbmi->bmiHeader.biBitCount = ds.dsBmih.biBitCount;
    lpbmi->bmiHeader.biCompression = ds.dsBmih.biCompression;
    lpbmi->bmiHeader.biSizeImage = ds.dsBmih.biSizeImage;
    lpbmi->bmiHeader.biXPelsPerMeter = ds.dsBmih.biXPelsPerMeter;
    lpbmi->bmiHeader.biYPelsPerMeter = ds.dsBmih.biYPelsPerMeter;
    lpbmi->bmiHeader.biClrUsed = ds.dsBmih.biClrUsed;
    lpbmi->bmiHeader.biClrImportant = ds.dsBmih.biClrImportant;

 // get DC for operation
 hDC = GetDC( NULL );
 
 // get DIB bits
    if (! GetDIBits(hDC,
                    hBitmap,
                    0L,
                    (DWORD)ds.dsBm.bmHeight,
                    (LPBYTE)lpbmi + (WORD)lpbmi->bmiHeader.biSize + (dwColorNum*sizeof(RGBQUAD)),
                    (LPBITMAPINFO)lpbmi,
     (DWORD)DIB_RGB_COLORS))
 {
         GlobalUnlock(hNewDIB);
         ReleaseDC(NULL,hDC);
         return NULL;
    }

 // memory DC
    hSourceDC = CreateCompatibleDC( hDC );
    // Select DIBSections into DCs
    hOldSourceBitmap = (HBITMAP)SelectObject( hSourceDC, hBitmap );
 
    // Fill in the color table from DIBSection
    if( lpbmi->bmiHeader.biBitCount <= 8 )
        GetDIBColorTable( hSourceDC, 0, 1 << lpbmi->bmiHeader.biBitCount, lpbmi->bmiColors );
 
    // Clean up and delete the DCs
    SelectObject( hSourceDC, hOldSourceBitmap );
    DeleteDC( hSourceDC );
    ReleaseDC( NULL, hDC );
 GlobalUnlock(hNewDIB);
 
    return hNewDIB;
}


/*************************************************************************
 *
 * CopyScreenToBitmap()
 *
 * Parameter:
 *
 * LPRECT lpRect    - specifies the window
 *
 * Return Value:
 *
 * HDIB             - identifies the device-dependent bitmap
 *
 * Description:
 *
 * This function copies the specified part of the screen to a device-
 * dependent bitmap.
 *
 *
 ************************************************************************/
HBITMAP CopyScreenToBitmap(LPRECT lpRect)
{
    HDC         hScrDC, hMemDC;         // screen DC and memory DC
    HBITMAP     hBitmap, hOldBitmap;    // handles to deice-dependent bitmaps
    int         nX, nY, nX2, nY2;       // coordinates of rectangle to grab
    int         nWidth, nHeight;        // DIB width and height
    int         xScrn, yScrn;           // screen resolution
 
    // check for an empty rectangle
 
    if (IsRectEmpty(lpRect))
      return NULL;
 
    // create a DC for the screen and create
    // a memory DC compatible to screen DC
    
    hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);
    hMemDC = CreateCompatibleDC(hScrDC);
 
    // get points of rectangle to grab
 
    nX = lpRect->left;
    nY = lpRect->top;
    nX2 = lpRect->right;
    nY2 = lpRect->bottom;
 
    // get screen resolution
 
    xScrn = GetDeviceCaps(hScrDC, HORZRES);
    yScrn = GetDeviceCaps(hScrDC, VERTRES);
 
    //make sure bitmap rectangle is visible
 
    if (nX < 0)
        nX = 0;
    if (nY < 0)
        nY = 0;
    if (nX2 > xScrn)
        nX2 = xScrn;
    if (nY2 > yScrn)
        nY2 = yScrn;
 
    nWidth = nX2 - nX;
    nHeight = nY2 - nY;
 
    // create a bitmap compatible with the screen DC
    hBitmap = CreateCompatibleBitmap(hScrDC, nWidth, nHeight);
 
    // select new bitmap into memory DC
    hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);
 
    // bitblt screen DC to memory DC
    BitBlt(hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, SRCCOPY);
 
    // select old bitmap back into memory DC and get handle to
    // bitmap of the screen
    
    hBitmap = (HBITMAP)SelectObject(hMemDC, hOldBitmap);
 
    // clean up
 
    DeleteDC(hScrDC);
    DeleteDC(hMemDC);
 
    // return handle to the bitmap
 
    return hBitmap;
}

/*************************************************************************
 *
 * CopyWindowToBitmap()
 *
 * Parameters:
 *
 * HWND hWnd        - specifies the window
 *
 * WORD fPrintArea  - specifies the window area to copy into the device-
 *                    dependent bitmap
 *
 * Return Value:
 *
 * HDIB         - identifies the device-dependent bitmap
 *
 * Description:
 *
 * This function copies the specified part(s) of the window to a device-
 * dependent bitmap.
 *
 *
 ************************************************************************/
HBITMAP CopyWindowToBitmap(HWND hWnd, WORD fPrintArea)
{
    HBITMAP     hBitmap = NULL;  // handle to device-dependent bitmap
 
    // check for a valid window handle
 
    if (!hWnd)
        return NULL;
 
    switch (fPrintArea)
    {
        case PW_WINDOW: // copy entire window
        {
            RECT    rectWnd;
 
            // get the window rectangle
 
            GetWindowRect(hWnd, &rectWnd);
 
            // get the bitmap of that window by calling
            // CopyScreenToBitmap and passing it the window rect
       
            hBitmap = CopyScreenToBitmap(&rectWnd);
            break;
        }
        
 
        case PW_CLIENT: // copy client area
        {
            RECT rectClient;
            POINT pt1, pt2;
 
            // get client dimensions
 
            GetClientRect(hWnd, &rectClient);
 
            // convert client coords to screen coords
 
            pt1.x = rectClient.left;
            pt1.y = rectClient.top;
            pt2.x = rectClient.right;
            pt2.y = rectClient.bottom;
            ClientToScreen(hWnd, &pt1);
            ClientToScreen(hWnd, &pt2);
            rectClient.left = pt1.x;
            rectClient.top = pt1.y;
            rectClient.right = pt2.x;
            rectClient.bottom = pt2.y;
 
            // get the bitmap of the client area by calling
            // CopyScreenToBitmap and passing it the client rect
            
            hBitmap = CopyScreenToBitmap(&rectClient);
            break;
        }
    
        default:    // invalid print area
            return NULL;
    }
 
    // return handle to the bitmap
 
   return hBitmap;
}
 
 
/*************************************************************************
 *
 * CopyClientRectToBitmap()
 *
 * Parameters:
 *
 * HWND hWnd        - specifies the window
 *
 * LPRECT lpRect    - specifies the client area rect to copy into the device-
 *                    independent bitmap
 *
 * Return Value:
 *
 * HDIB             - identifies the device-independent bitmap
 *
 * Description:
 *
 * This function copies the specified part(s) of the window client to a
 * device-independent bitmap.
 *
 ************************************************************************/
HBITMAP CopyClientRectToBitmap(HWND hWnd, LPRECT lpRect)
{
   HBITMAP     hBitmap = NULL;  // handle to DIB
 
   // check for a valid window handle
 
    if (!hWnd)
        return NULL;
 
    POINT   pt1, pt2;

    // convert client coords to screen coords

    pt1.x = lpRect->left;
    pt1.y = lpRect->top;
    pt2.x = lpRect->right;
    pt2.y = lpRect->bottom;
    ClientToScreen(hWnd, &pt1);
    ClientToScreen(hWnd, &pt2);
    lpRect->left = pt1.x;
    lpRect->top = pt1.y;
    lpRect->right = pt2.x;
    lpRect->bottom = pt2.y;

    // get the DIB of the client area by calling
    // CopyScreenToDIB and passing it the client rect

    hBitmap = CopyScreenToBitmap(lpRect);
 
 // restore lpRect

    pt1.x = lpRect->left;
    pt1.y = lpRect->top;
    pt2.x = lpRect->right;
    pt2.y = lpRect->bottom;
    ScreenToClient(hWnd, &pt1);
    ScreenToClient(hWnd, &pt2);
    lpRect->left = pt1.x;
    lpRect->top = pt1.y;
    lpRect->right = pt2.x;
    lpRect->bottom = pt2.y;

 // return the handle to the DIB
 
   return hBitmap;
}
 
/*************************************************************************
 *
 * CopyScreenToDIB()
 *
 * Parameter:
 *
 * LPRECT lpRect    - specifies the window
 *
 * Return Value:
 *
 * HDIB             - identifies the device-independent bitmap
 *
 * Description:
 *
 * This function copies the specified part of the screen to a device-
 * independent bitmap.
 *
 ************************************************************************/
HDIB CopyScreenToDIB(LPRECT lpRect)
{
    HBITMAP     hBitmap;        // handle to device-dependent bitmap
    HPALETTE    hPalette;       // handle to palette
    HDIB        hDIB = NULL;    // handle to DIB
 
    // get the device-dependent bitmap in lpRect by calling
    //  CopyScreenToBitmap and passing it the rectangle to grab
 
    hBitmap = CopyScreenToBitmap(lpRect);
 
    // check for a valid bitmap handle
 
    if (!hBitmap)
      return NULL;
 
    // get the current palette
 
    hPalette = GetSystemPalette();
 
    // convert the bitmap to a DIB
 
    hDIB = BitmapToDIB(hBitmap, hPalette);
 
    // clean up 
 
    DeleteObject(hPalette);
    DeleteObject(hBitmap);
 
    // return handle to the packed-DIB
    return hDIB;
}
 
/*************************************************************************
 *
 * CopyWindowToDIB()
 *
 * Parameters:
 *
 * HWND hWnd        - specifies the window
 *
 * WORD fPrintArea  - specifies the window area to copy into the device-
 *                    independent bitmap
 *
 * Return Value:
 *
 * HDIB             - identifies the device-independent bitmap
 *
 * Description:
 *
 * This function copies the specified part(s) of the window to a device-
 * independent bitmap.
 *
 ************************************************************************/
HDIB CopyWindowToDIB(HWND hWnd, WORD fPrintArea)
{
   HDIB     hDIB = NULL;  // handle to DIB
 
   // check for a valid window handle
 
    if (!hWnd)
        return NULL;
 
    switch (fPrintArea)
    {
        case PW_WINDOW: // copy entire window
        {
            RECT    rectWnd;
 
            // get the window rectangle
 
            GetWindowRect(hWnd, &rectWnd);
 
            // get the DIB of the window by calling
            // CopyScreenToDIB and passing it the window rect
            
            hDIB = CopyScreenToDIB(&rectWnd);
            break;
        }
      
        case PW_CLIENT: // copy client area
        {
            RECT    rectClient;
            POINT   pt1, pt2;
 
            // get the client area dimensions
 
            GetClientRect(hWnd, &rectClient);
 
            // convert client coords to screen coords
 
            pt1.x = rectClient.left;
            pt1.y = rectClient.top;
            pt2.x = rectClient.right;
            pt2.y = rectClient.bottom;
            ClientToScreen(hWnd, &pt1);
            ClientToScreen(hWnd, &pt2);
            rectClient.left = pt1.x;
            rectClient.top = pt1.y;
            rectClient.right = pt2.x;
            rectClient.bottom = pt2.y;
 
            // get the DIB of the client area by calling
            // CopyScreenToDIB and passing it the client rect
 
            hDIB = CopyScreenToDIB(&rectClient);
            break;
        }
      
        default:    // invalid print area
            return NULL;
    }
 
   // return the handle to the DIB
 
   return hDIB;
}
 
/*************************************************************************
 *
 * CopyClientRectToDIB()
 *
 * Parameters:
 *
 * HWND hWnd        - specifies the window
 *
 * LPRECT lpRect    - specifies the client area rect to copy into the device-
 *                    independent bitmap
 *
 * Return Value:
 *
 * HDIB             - identifies the device-independent bitmap
 *
 * Description:
 *
 * This function copies the specified part(s) of the window client to a
 * device-independent bitmap.
 *
 ************************************************************************/
HDIB CopyClientRectToDIB(HWND hWnd, LPRECT lpRect)
{
   HDIB     hDIB = NULL;  // handle to DIB
 
   // check for a valid window handle
 
    if (!hWnd)
        return NULL;
 
    POINT   pt1, pt2;

    // convert client coords to screen coords

    pt1.x = lpRect->left;
    pt1.y = lpRect->top;
    pt2.x = lpRect->right;
    pt2.y = lpRect->bottom;
    ClientToScreen(hWnd, &pt1);
    ClientToScreen(hWnd, &pt2);
    lpRect->left = pt1.x;
    lpRect->top = pt1.y;
    lpRect->right = pt2.x;
    lpRect->bottom = pt2.y;

    // get the DIB of the client area by calling
    // CopyScreenToDIB and passing it the client rect

    hDIB = CopyScreenToDIB(lpRect);
 
 // restore lpRect

    pt1.x = lpRect->left;
    pt1.y = lpRect->top;
    pt2.x = lpRect->right;
    pt2.y = lpRect->bottom;
    ScreenToClient(hWnd, &pt1);
    ScreenToClient(hWnd, &pt2);
    lpRect->left = pt1.x;
    lpRect->top = pt1.y;
    lpRect->right = pt2.x;
    lpRect->bottom = pt2.y;

 // return the handle to the DIB
 
   return hDIB;
}

 
/*************************************************************************
 *
 * PaintDIB()
 *
 * Parameters:
 *
 * HDC hDC          - DC to do output to
 *
 * LPRECT lpDCRect  - rectangle on DC to do output to
 *
 * HDIB hDIB        - handle to global memory with a DIB spec
 *                    in it followed by the DIB bits
 *
 * LPRECT lpDIBRect - rectangle of DIB to output into lpDCRect
 *
 * HPALETTE hPal    - Palette used to diaplsy DIB, if is NULL,
 *       use DIB palette to display
 *
 * DWORD dwRop      - ROP mode to display DIB
 *
 * Return Value:
 *
 * BOOL             - TRUE if DIB was drawn, FALSE otherwise
 *
 * Description:
 *   Painting routine for a DIB.  Calls StretchDIBits() or
 *   SetDIBitsToDevice() to paint the DIB.  The DIB is
 *   output to the specified DC, at the coordinates given
 *   in lpDCRect.  The area of the DIB to be output is
 *   given by lpDIBRect.
 *
 * NOTE: This function always selects the palette as background. Before
 * calling this function, be sure your palette is selected to desired
 * priority (foreground or background).
 *
 *
 ************************************************************************/
BOOL PaintDIB(HDC hDC, LPRECT lpDCRect, HDIB hDIB, LPRECT lpDIBRect,
        HPALETTE hPal, DWORD dwRop)
{
    LPBYTE        lpDIBHdr;           // Pointer to BITMAPINFOHEADER
    LPBYTE        lpDIBBits;          // Pointer to DIB bits
    BOOL         bSuccess=FALSE;     // Success/fail flag
    HPALETTE     hOldPal=NULL;       // Previous palette
 
    // Check for valid DIB handle
 
    if (!hDIB)
        return FALSE;

    // Lock down the DIB, and get a pointer to the beginning of the bit
    // buffer
    
    lpDIBHdr  = (LPBYTE)GlobalLock(hDIB);
    lpDIBBits = FindDIBBits(lpDIBHdr);
 
 // if no palette provided, create one from DIB

    if (! hPal)
  hPal = CreateDIBPalette(lpDIBHdr);

    // Select and realize our palette as background
 
    if (hPal)
    {
        hOldPal = SelectPalette(hDC, hPal, TRUE);
        RealizePalette(hDC);
    }
 
    // Make sure to use the stretching mode best for color pictures
 
    SetStretchBltMode(hDC, COLORONCOLOR);
 
    // Call StretchDIBits() with dwRop
 
 bSuccess = StretchDIBits(hDC,
        lpDCRect->left,
        lpDCRect->top,
        RECTWIDTH(lpDCRect),
        RECTHEIGHT(lpDCRect),
        lpDIBRect->left,
                 (int)DIBHeight(lpDIBHdr) - lpDIBRect->top - RECTHEIGHT(lpDIBRect),
        RECTWIDTH(lpDIBRect),
        RECTHEIGHT(lpDIBRect),
        lpDIBBits,
        (LPBITMAPINFO)lpDIBHdr,
        DIB_RGB_COLORS,
        SRCCOPY);
 
    // Unlock the memory block
 
    GlobalUnlock(hDIB);
 
    // Reselect old palette
 
    if (hOldPal)
  SelectPalette(hDC, hOldPal, FALSE);
 
    // Return with success/fail flag
    return bSuccess;
}

/*************************************************************************
 *
 * PaintBitmap()
 *
 * Parameters:
 *
 * HDC hDC          - DC to do output to
 *
 * LPRECT lpDCRect  - rectangle on DC to do output to
 *
 * HBITMAP hDDB     - handle to device-dependent bitmap (DDB)
 *
 * LPRECT lpDDBRect - rectangle of DDB to output into lpDCRect
 *
 * HPALETTE hPalette - handle to the palette to use with hDDB
 *
 * Return Value:
 *
 * BOOL             - TRUE if bitmap was drawn, FLASE otherwise
 *
 * Description:
 *
 * Painting routine for a DDB.  Calls BitBlt() or
 * StretchBlt() to paint the DDB.  The DDB is
 * output to the specified DC, at the coordinates given
 * in lpDCRect.  The area of the DDB to be output is
 * given by lpDDBRect.  The specified palette is used.
 *
 * NOTE: This function always selects the palette as background. Before
 * calling this function, be sure your palette is selected to desired
 * priority (foreground or background).
 *
 ************************************************************************/
BOOL PaintBitmap(HDC hDC, LPRECT lpDCRect, HBITMAP hDDB,  LPRECT lpDDBRect, 
        HPALETTE hPal, DWORD dwRop)
{
    HDC         hMemDC;            // Handle to memory DC
    HBITMAP     hOldBitmap;        // Handle to previous bitmap
    HPALETTE    hOldPal1 = NULL;   // Handle to previous palette
    HPALETTE    hOldPal2 = NULL;   // Handle to previous palette
    BOOL        bSuccess = FALSE;  // Success/fail flag
 
    // Create a memory DC
 
    hMemDC = CreateCompatibleDC (hDC);
 
    // If this failed, return FALSE
 
    if (!hMemDC)
        return FALSE;
 
    // If we have a palette, select and realize it
 
    if (hPal)
    {
        hOldPal1 = SelectPalette(hMemDC, hPal, TRUE);
        hOldPal2 = SelectPalette(hDC, hPal, TRUE);
        RealizePalette(hDC);
    }
 
    // Select bitmap into the memory DC
 
    hOldBitmap = (HBITMAP)SelectObject (hMemDC, hDDB);
 
    // Make sure to use the stretching mode best for color pictures
 
    SetStretchBltMode (hDC, COLORONCOLOR);
 
    // Determine whether to call StretchBlt() or BitBlt()
    if ((RECTWIDTH(lpDCRect)  == RECTWIDTH(lpDDBRect)) &&
            (RECTHEIGHT(lpDCRect) == RECTHEIGHT(lpDDBRect)))
        bSuccess = BitBlt(hDC, lpDCRect->left, lpDCRect->top,
                lpDCRect->right - lpDCRect->left,
                lpDCRect->bottom - lpDCRect->top, hMemDC, lpDDBRect->left,
                lpDDBRect->top, dwRop);
    else
        bSuccess = StretchBlt(hDC, lpDCRect->left,  lpDCRect->top, 
                lpDCRect->right - lpDCRect->left,
                lpDCRect->bottom - lpDCRect->top, hMemDC, lpDDBRect->left, 
                lpDDBRect->top,  lpDDBRect->right - lpDDBRect->left,
                lpDDBRect->bottom - lpDDBRect->top, dwRop);
 
    // Clean up
 
    SelectObject(hMemDC, hOldBitmap);
 
    if (hOldPal1)
        SelectPalette (hMemDC, hOldPal1, FALSE);
 
    if (hOldPal2)
        SelectPalette (hDC, hOldPal2, FALSE);
 
    DeleteDC (hMemDC);
 
    // Return with success/fail flag
 
    return bSuccess;
}

/*************************************************************************
 *
 * DisplayPalette ()
 *
 * Parameter:
 *
 * HDC hDC          - handle of device context to display palette
 * LPRECT lpRect      - rect range to show palette
 * HPALETTE hPal     - handle of palette to display
 *
 * Return Value:
 *
 * BOOL            - TRUE, if success, else FALSE
 *
 * Description:
 *
 * This function displays palette on the specified rectangle in a device context
 *
 ************************************************************************/
BOOL DisplayPalette(HDC hDC, LPRECT lpRect, HPALETTE hPal)
{
 if (! hPal)
  return FALSE;

 int nEntries;
 PALETTEENTRY pe[256];
 nEntries = GetPaletteEntries(hPal, 0, 256, pe);
 int nSqr = (int)sqrt((double)nEntries);

 int nWidth = (lpRect->right-lpRect->left)/nSqr;
 int nHeight = (lpRect->bottom-lpRect->top)/nSqr;
 lpRect->right = lpRect->left + nWidth*nSqr;
 lpRect->bottom = lpRect->top + nHeight*nSqr;

 HPALETTE hOldPal = (HPALETTE)SelectPalette(hDC, hPal, FALSE);
 RealizePalette(hDC);

 HBRUSH hBrush, hOldBrush;
 int x, y;
 for (int i=0; i<nEntries; ++i)
 {
  x = i%nSqr;
  y = i/nSqr;
  hBrush = CreateSolidBrush(RGB(pe[i].peRed, pe[i].peGreen, pe[i].peBlue));
  hOldBrush = (HBRUSH)SelectObject(hDC, hBrush);
  Rectangle(hDC,
         lpRect->left + x*nWidth,
      lpRect->top + y*nHeight,
      lpRect->left + (x+1)*nWidth,
      lpRect->top + (y+1) *nHeight);
  SelectObject(hDC, hOldBrush);
  DeleteObject(hBrush);
 }
 
 SelectPalette(hDC, hOldPal, FALSE);

 return TRUE;
}

/*************************************************************************
 *
 * CopyPalette ()
 *
 * Parameter:
 *
 * HPALETTE hPalSrc    - source palette handle
 *
 * Return Value:
 *
 * HPALETTE          - destination palette handle
 *
 * Description:
 *
 * This function copys the source palette to a new palette handle
 *
 ************************************************************************/
HPALETTE CopyPalette(HPALETTE hPalSrc)
{
    PLOGPALETTE     plogPal;
    int             iNumEntries=0;
    HPALETTE        hPal;
 HANDLE   h;

 iNumEntries = GetPaletteEntries(hPalSrc, 0, iNumEntries, NULL);
    if (iNumEntries == 0)
        return (HPALETTE) NULL;

 h = GlobalAlloc(GHND, sizeof(DWORD) + sizeof(PALETTEENTRY)*iNumEntries);
 if (! h)
        return (HPALETTE) NULL;
 plogPal = (PLOGPALETTE)GlobalLock(h);
    if (! plogPal)
        return (HPALETTE) NULL;

    plogPal->palVersion = 0x300;
    plogPal->palNumEntries = (WORD) iNumEntries;
    GetPaletteEntries(hPalSrc, 0, iNumEntries, plogPal->palPalEntry);
    hPal = CreatePalette(plogPal);

    GlobalUnlock(h);
    GlobalFree(h);

    return hPal;
}
 
/*************************************************************************
 *
 * PalEntriesOnDevice()
 *
 * Parameter:
 *
 * HDC hDC          - device context
 *
 * Return Value:
 *
 * int              - number of palette entries on device
 *
 * Description:
 *
 * This function gets the number of palette entries on the specified device
 *
 ************************************************************************/
int PalEntriesOnDevice(HDC hDC)
{
    int nColors;  // number of colors
 
    // Find out the number of colors on this device.
    
    nColors = (1 << (GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES)));
 
    assert(nColors);
    return nColors;
}
 
 
/*************************************************************************
 *
 * GetSystemPalette()
 *
 * Parameters:
 *
 * None
 *
 * Return Value:
 *
 * HPALETTE         - handle to a copy of the current system palette
 *
 * Description:
 *
 * This function returns a handle to a palette which represents the system
 * palette.  The system RGB values are copied into our logical palette using
 * the GetSystemPaletteEntries function.  
 *
 ************************************************************************/
HPALETTE GetSystemPalette(void)
{
    HDC hDC;                // handle to a DC
    static HPALETTE hPal = NULL;   // handle to a palette
    HANDLE hLogPal;         // handle to a logical palette
    LPLOGPALETTE lpLogPal;  // pointer to a logical palette
    int nColors;            // number of colors
 
    // Find out how many palette entries we want.
 
    hDC = GetDC(NULL);
 
    if (!hDC)
        return NULL;
 
    nColors = PalEntriesOnDevice(hDC);   // Number of palette entries
 
    // Allocate room for the palette and lock it.
 
    hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) + nColors *
            sizeof(PALETTEENTRY));
 
    // if we didn't get a logical palette, return NULL
 
    if (!hLogPal)
        return NULL;
 
    // get a pointer to the logical palette
 
    lpLogPal = (LPLOGPALETTE)GlobalLock(hLogPal);
 
    // set some important fields
 
    lpLogPal->palVersion = PALVERSION;
    lpLogPal->palNumEntries = nColors;
 
    // Copy the current system palette into our logical palette
 
    GetSystemPaletteEntries(hDC, 0, nColors,
            (LPPALETTEENTRY)(lpLogPal->palPalEntry));
 
    // Go ahead and create the palette.  Once it's created,
    // we no longer need the LOGPALETTE, so free it.    
 
    hPal = CreatePalette(lpLogPal);
 
    // clean up
 
    GlobalUnlock(hLogPal);
    GlobalFree(hLogPal);
    ReleaseDC(NULL, hDC);
 
    return hPal;
}
 
/*************************************************************************
 *
 * CreateIdentifyPalette ()
 *
 * Parameter:
 *
 * HPALETTE hPalSrc    - source palette handle
 *
 * Return Value:
 *
 * HPALETTE          - destination identify palette handle
 *
 * Description:
 *
 * This function creates an identify palette from the source palette handle
 *
 ************************************************************************/
HPALETTE CreateIdentifyPalette(HPALETTE hPalSrc)
{
    BOOL bResult = FALSE;
    int i, iSysColors, iPalEntries;
    HPALETTE hPalette, hpalOld;

 if (! hPalSrc)
  return NULL;

 // create a new palette equal to input
 hPalette = CopyPalette(hPalSrc);

    // Get a screen DC to work with
    HDC hdcScreen = GetDC(NULL);
    ASSERT(hdcScreen);

    // Make sure we are on a palettized device
    if (!(GetDeviceCaps(hdcScreen, RASTERCAPS) & RC_PALETTE))
 {
        TRACE("Not a palettized device");
        goto abort;
    }

    // Get the number of system colors and the number of palette entries
    // Note that on a palletized device the number of colors is the
    // number of guaranteed colors.  I.e. the number of reserved system colors
    iSysColors = GetDeviceCaps(hdcScreen, NUMCOLORS);
    iPalEntries = GetDeviceCaps(hdcScreen, SIZEPALETTE);

    // if there are more than 256 colors we are wasting our time
    if (iSysColors > 256) goto abort;

    // Now we force the palette manager to reset its tables so that
    // the next palette to be realized will get its colors in the order they are
    // in the logical palette. This is done by changing the number of
    // reserved colors.
    SetSystemPaletteUse(hdcScreen, SYSPAL_NOSTATIC);
    SetSystemPaletteUse(hdcScreen, SYSPAL_STATIC);

    // Select our palette into the screen DC and realize it so that
    // its colors will be entered into the free slots in the physical palette
    hpalOld = ::SelectPalette(hdcScreen,
                              hPalette, // our hpal
                              FALSE);
    ::RealizePalette(hdcScreen);
    // Now replace the old palette (but don't realize it)
    ::SelectPalette(hdcScreen, hpalOld, FALSE);

    // The physical palette now has our colors set in place and its own
    // reserved colors at either end.  We can grab the lot now
    PALETTEENTRY pe[256];
    GetSystemPaletteEntries(hdcScreen,
                            0,
                            iPalEntries,
                            pe);

    // Set the PC_NOCOLLAPSE flag for each of our colors so that GDI
    // won't merge them together.  Be careful not to set PC_NOCOLLAPSE for the
    // sys color entries or we'll get multpile copies of these colors in
    // the palette when we realize it.
    for (i = 0; i < iSysColors/2; i++) {
        pe[i].peFlags = 0;
    }
    for (; i < iPalEntries-iSysColors/2; i++) {
        pe[i].peFlags = PC_NOCOLLAPSE;
    }
    for (; i < iPalEntries; i++) {
        pe[i].peFlags = 0;
    }

    // Resize the palette in case it was smaller
    ResizePalette(hPalette, iPalEntries);

    // Update the palette entries with what is now in the physical palette
    SetPaletteEntries(hPalette, 0, iPalEntries, pe);
    bResult = TRUE;

abort:
    ::ReleaseDC(NULL, hdcScreen);
    return bResult ? hPalette : NULL;
}

/*************************************************************************
 *
 * MapDIBColorsToPalette ()
 *
 * Parameter:
 *
 * HDIB hDIB      - DIB handle
 * HPALETTE hPalette    - given palette handle
 *
 * Return Value:
 *
 * HPALETTE          - destination identify palette handle
 *
 * Description:
 *
 * This function Map the colors in a DIB to a given palette.
 *
 ************************************************************************/
BOOL MapDIBColorsToPalette(HDIB hDIB, HPALETTE hPalette)
{
    if (! hDIB)
        return FALSE;
    if (! hPalette)
        return FALSE;

    LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
    if (! lpbi)
        return FALSE;
    LPRGBQUAD pctThis = (LPRGBQUAD)((LPBYTE)lpbi + lpbi->biSize);

    // build an index translation table to map this DIBs colors
    // to those of the reference DIB
    BYTE imap[256];
    for (int i = 0; i < 256; i++)
 {
        imap[i] = (BYTE)GetNearestPaletteIndex(hPalette,
         RGB(pctThis->rgbRed,
          pctThis->rgbGreen,
          pctThis->rgbBlue));
        pctThis++;
    }
    // now map the DIB bits
    LPBYTE pBits = (LPBYTE)lpbi + lpbi->biSize + PaletteSize((LPBYTE)lpbi);
    int iSize = WIDTHBYTES(lpbi->biBitCount*lpbi->biWidth) * lpbi->biHeight;
    while (iSize--)
 {
        *pBits = imap[*pBits];
        pBits++;
    }
    // Now reset the DIB color table so that its RGB values match
    // those in the palette
    PALETTEENTRY pe[256];
    GetPaletteEntries(hPalette, 0, 256, pe);
    pctThis = (LPRGBQUAD)((LPBYTE)lpbi + lpbi->biSize);
    for (i = 0; i < 256; i++)
 {
        pctThis->rgbRed = pe[i].peRed;   
        pctThis->rgbGreen = pe[i].peGreen;   
        pctThis->rgbBlue = pe[i].peBlue;
        pctThis++;   
    }
 
 GlobalUnlock(hDIB);
    return TRUE;
}

/*************************************************************************
 *
 * CopyHandle()
 *
 * Parameters:
 *
 * HANDLE h         - source handle
 *
 * Return Value:
 *
 * HANDLE           - duplicated handle
 *
 * Description:
 *
 * Copy memory handle to another
 ************************************************************************/
HANDLE CopyHandle(HANDLE h)
{
 if (h == NULL)
  return NULL;

 DWORD  dwLen = ::GlobalSize((HGLOBAL)h);
 HANDLE hCopy = ::GlobalAlloc(GHND, dwLen);
 if (hCopy == NULL)
  return NULL;

 void* lpCopy = ::GlobalLock((HGLOBAL) hCopy);
 void* lp     = ::GlobalLock((HGLOBAL) h);
 ::CopyMemory(lpCopy, lp, dwLen);
 ::GlobalUnlock(hCopy);
 ::GlobalUnlock(h);

 return hCopy;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值