常用用图像处理算法(二)

文件中引用文件及函数如下:

1)dibapi.h

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

#ifndef __DIBAPI1_H_
#define __DIBAPI1_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

/* Gray Method */
#define MEAN_GRAY   0
#define MAXIMUM_GRAY  1
#define WEIGHT_GRAY   2
#define OTHER_GRAY   3


/* 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 MYWIDTHBYTES(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)
#define BOUND(x, mn, mx) ((x) < (mn) ? (mn) : ((x) > (mx) ? (mx) : (x)))


// Structure use internally
typedef struct _NODE
{
 BOOL bIsLeaf;               // TRUE if node has no children
 UINT nPixelCount;           // Number of pixels represented by this leaf
 UINT nRedSum;               // Sum of red components
 UINT nGreenSum;             // Sum of green components
 UINT nBlueSum;              // Sum of blue components
 struct _NODE* pChild[8];    // Pointers to child nodes
 struct _NODE* pNext;        // Pointer to next reducible node
} NODE;

 
/* function prototypes */
 // DIB initialization
HANDLE LoadImgHandle(char* szImgFileName, char *strExt, int &nFileType) ;
BOOL SaveDIB (HDIB, LPCTSTR);
void DestroyDIB(HDIB hDib);

// DIB attributes
DWORD BytesPerLine(LPBYTE lpDIB);
DWORD DIBlockSize(LPBYTE lpDIB);
DWORD DIBHeight (LPBYTE lpDIB);
DWORD DIBWidth (LPBYTE lpDIB);
WORD DIBNumColors (LPBYTE lpDIB);
WORD DIBBitCount (LPBYTE lpDIB);
LPBYTE FindDIBBits (LPBYTE lpDIB);
WORD PaletteSize (LPBYTE lpDIB);

 // 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);
HPALETTE CreateOctreePalette(HDIB hDIB, UINT nMaxColors, UINT nColorBits);
HPALETTE CreateOctreePalette(LPBYTE lpDIB, UINT nMaxColors, UINT nColorBits);
HPALETTE BuildOctreePalette(HANDLE hImage, UINT nMaxColors, UINT nColorBits);
//Relative functions with CreateOctreePalette
void AddColor (NODE**, BYTE, BYTE, BYTE, UINT, UINT, UINT*, NODE**);
NODE* CreateNode (UINT, UINT, UINT*, NODE**);
void ReduceTree (UINT, UINT*, NODE**);
void DeleteTree (NODE**);
void GetPaletteColors (NODE*, PALETTEENTRY*, UINT*);
int GetRightShiftCount (DWORD);
int GetLeftShiftCount (DWORD);
//Relative functions with CreateOctreePalette

//DIB operations
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);
//
BOOL CopyColorTable( LPBITMAPINFO lpTarget, LPBITMAPINFO lpSource, HPALETTE hPalSrc );
HBITMAP DIBToDIBSection(LPBYTE lpDIB);
HBITMAP DIBToDIBSection(HDIB hDIB);
HBITMAP DIBToBitmap(HDIB hDIB, HPALETTE hPal) ;
HDIB ChangeDIBFormat(HDIB hDIB, WORD wBitCount, DWORD dwCompression) ;
HDIB ChangeBitmapFormat (HBITMAP hbm, WORD biBits, DWORD biCompression, HPALETTE hpal);
bool GrayEqualize(HDIB hDib);
bool GrayStretchDIB(int nMethod, HDIB hDib,BYTE bX1,BYTE bY1,BYTE bX2,BYTE  bY2);
bool EliminateDirtDIB(int nMethod, HDIB hDib, CRect rect);
bool EliminateDirtDIB(int nMethod, HDIB hDib, int nCircleX, int nCircleY, int nRadius);
void SaveTo8bit_BMP(const BYTE* pbInputMat, int Width, int Height, const char* szFileName, int nGrayLevel);
HDIB ChangeDIBSize(HDIB hDIB, int nWidth, int nHeight);

 

int PalEntriesOnDevice (HDC hDC);
HPALETTE CreateIdentifyPalette(HPALETTE hPalSrc);
BOOL MapDIBColorsToPalette(HDIB hDIB, HPALETTE hPalette);
LONG GetPixelOffsetValue(HDIB hDib,LONG y, LONG x);
HDIB CropDIB(HDIB hDIB, LPRECT lpRect);
HDIB ColorQuantizeDIB(HDIB hDIB, UINT nColorBits, UINT nMaxColors);
HPALETTE ConvertToGrayscale(HDIB hDib, int nMethod, double fRedWeight, double fGreenWeight, double fBlueWeight);
BOOL SaveBMPFile(LPCSTR lpFileName, BITMAPINFO *pBmpInfo, BYTE *pImageBuffer);
bool  GetGrayHist(const BYTE * pbImg, const int nImgWid, const int nImgHei, int *pnHist );
bool  GetCumulativeHist(const int *pnHist , int nLength, long *pnCuHist);
//

 

//////////////////////////////////////////////////////////
#endif //__DIBAPI_H_

2)dibapi.cpp

//**********************************************************************
//
//  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 <afxcoll.h>
#include <afxtempl.h>

#include "dibapi.h"


void DestroyDIB(HDIB hDib)
{
    GlobalFree(hDib);
}

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 = MYWIDTHBYTES((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.
    //bfOffBits specifies the offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to the bitmap bits. 
   
 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)
{
 ASSERT(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;
}
 
 
/*************************************************************************
 *
 * 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;
}
 
 
/*************************************************************************
 *
 * 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 DIBBitCount(LPBYTE lpDIB)
{
 if (IS_WIN30_DIB(lpDIB))
        return ((LPBITMAPINFOHEADER)lpDIB)->biBitCount;
    else
        return ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount;
}

 
 
/****************************************************************************
*
*     FUNCTION: BytesPerLine
*
*     PURPOSE:  Calculates the number of bytes in one scan line.
*
*    功能:计算DIB位图每条扫描线的字节数
*   
*     PARAMS:   LPBYTE lpDIB - pointer to the BITMAPINFOHEADER
                              that begins the CF_DIB block
*
*  参数:指向BITMAPINFOHEADER 结构的指针
*
*     RETURNS:  DWORD - number of bytes in one scan line (DWORD aligned)
*
\****************************************************************************/
DWORD BytesPerLine(LPBYTE lpDIB)
{
    return MYWIDTHBYTES(((LPBITMAPINFOHEADER)lpDIB)->biWidth * ((LPBITMAPINFOHEADER)lpDIB)->biPlanes * ((LPBITMAPINFOHEADER)lpDIB)->biBitCount);
}


/****************************************************************************
*
*     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;
}


 
/*************************************************************************
 *
 * 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 = WORD(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;
}
/*************************************************************************
 *
 * 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;

 SIZE_T  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;
}

LONG GetPixelOffsetValue(HDIB hDib,LONG y, LONG x)
{
 WaitCursorBegin();
 
 LPBYTE lpDIB,lpDIBBits;
 DWORD lHeight;
 lpDIB = (LPBYTE) GlobalLock( hDib );

 lpDIBBits = FindDIBBits( lpDIB );
 lHeight  = DIBHeight( lpDIB );
 LONG lLineBytes = BytesPerLine(lpDIB);

 GlobalUnlock( hDib );
 WaitCursorEnd();

 return *(lpDIBBits + (lHeight-y-1)*lLineBytes+x);
}

HDIB CropDIB(HDIB hDIB, LPRECT lpRect)
{
    LPBITMAPINFO lpbmi = NULL;
    LPBYTE       lpSourceBits, lpTargetBits, lpResult;
    HDC    hDC = NULL, hSourceDC, hTargetDC;
    HBITMAP      hSourceBitmap, hTargetBitmap, hOldTargetBitmap, hOldSourceBitmap;
    DWORD        dwSourceBitsSize, dwTargetBitsSize, dwTargetHeaderSize;
 int    nWidth, nHeight;
 HDIB   hNewDIB;
 DWORD   dwSize;

 WaitCursorBegin();

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

    // Allocate and fill out a BITMAPINFO struct for the new DIB
    dwTargetHeaderSize = sizeof( BITMAPINFOHEADER ) + PaletteSize(lpSrcDIB);
    lpbmi = (LPBITMAPINFO)malloc( dwTargetHeaderSize );
 memcpy(lpbmi, lpSrcDIB, dwTargetHeaderSize);
 nWidth = RECTWIDTH(lpRect);
 nHeight = RECTHEIGHT(lpRect);
    lpbmi->bmiHeader.biWidth = nWidth;
    lpbmi->bmiHeader.biHeight = nHeight;
 
    // 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 );
 
 // put old bitmap in new bitmap
    BitBlt(hTargetDC, 0, 0, nWidth, nHeight, hSourceDC, lpRect->left, lpRect->top, 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);
 WaitCursorEnd();
 
    return hNewDIB;
}


//对原来图像进行灰度化
BOOL SaveBMPFile(LPCSTR lpFileName, BITMAPINFO *pBmpInfo, BYTE *pImageBuffer)
{
 BOOL bRVal    = TRUE;
 DWORD dwBytesRead  = 0;
 DWORD dwSize   = 0;
 BITMAPFILEHEADER bfh = {0};
 int nTable    = 0;
 DWORD dwImageSize  = 0;

 if (pBmpInfo->bmiHeader.biBitCount > 8) {
  nTable = 0;
 }
 else{
  nTable = 256;
 }

 dwImageSize =  MYWIDTHBYTES(pBmpInfo->bmiHeader.biWidth * pBmpInfo->bmiHeader.biBitCount) *
  pBmpInfo->bmiHeader.biHeight;

 if (dwImageSize <= 0) {
  bRVal = FALSE;
 }
 else{
  bfh.bfType  = (WORD)'M' << 8 | 'B';
  bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + nTable * sizeof(RGBQUAD);
  bfh.bfSize  = bfh.bfOffBits + dwImageSize;   

  HANDLE hFile = ::CreateFile(lpFileName,
   GENERIC_WRITE ,
   0,
   NULL,
   CREATE_ALWAYS,
   FILE_ATTRIBUTE_NORMAL,
   NULL
   );
  if (hFile == INVALID_HANDLE_VALUE) {
   bRVal = FALSE;
  }
  else{
   dwSize = sizeof(BITMAPFILEHEADER);
   ::WriteFile(hFile, &bfh, dwSize, &dwBytesRead, NULL );

   dwSize = sizeof(BITMAPINFOHEADER) + nTable * sizeof(RGBQUAD);
   ::WriteFile(hFile, pBmpInfo, dwSize, &dwBytesRead, NULL );

   dwSize = dwImageSize;
   WriteFile(hFile, pImageBuffer, dwSize, &dwBytesRead, NULL );

   CloseHandle(hFile);
  }
 }

 return bRVal;
}

// Add 2007-05-09
HANDLE LoadImgHandle(char* szImgFileName, char *strExt, int &nFileType)
{

 typedef HANDLE (WINAPI * PGETDIBPROC)(HWND, char *, HANDLE);
 PGETDIBPROC lpFun;
 HANDLE hDib;

 HINSTANCE hConvertLib = LoadLibrary("Convert.dll");
 ASSERT(hConvertLib != NULL);

 if(strcmp(strExt,".bmp") == 0)
 {
  lpFun = (PGETDIBPROC)GetProcAddress(hConvertLib, "Bmp2HDIB");
  nFileType = 1;
 }
 else if(strcmp(strExt,".jpg") == 0)
 {
  lpFun = (PGETDIBPROC)GetProcAddress(hConvertLib, "Jpg2HDIB");
  nFileType = 2;
 }
 else if(strcmp(strExt,".tif") == 0)
 {
  lpFun = (PGETDIBPROC)GetProcAddress(hConvertLib, "Tiff2HDIB");
  nFileType = 3;
 }
 else
 {
  if(hConvertLib)
  {
   FreeLibrary(hConvertLib);
  }
  nFileType = -1;
  return NULL;
 }
 ASSERT(lpFun != NULL);


 freopen("nul", "w", stdout);

 hDib = (*lpFun) ( NULL, szImgFileName, NULL);

 freopen("con", "w", stdout);

 if(hConvertLib)
 {
  FreeLibrary(hConvertLib);
 }

 return hDib;
}

HPALETTE ConvertToGrayscale(HDIB hDib, int nMethod,
       double fRedWeight, double fGreenWeight, double fBlueWeight)
{
 if (hDib == NULL)
  return NULL;

 BITMAPINFO* lpbi = (BITMAPINFO *)GlobalLock(hDib);
 if (! lpbi)
  return NULL;

 WaitCursorBegin();

 // get color number
 WORD wNumColors = DIBNumColors((LPBYTE)lpbi);
 if (wNumColors == 0)  // There is no palette
 {
  GlobalUnlock(hDib);
  // reduce colors to 256
  HDIB hNewDib = ColorQuantizeDIB(hDib, 8, 256);
  LPBYTE lpDIB = (LPBYTE)GlobalLock(hNewDib);
  if (! lpDIB)
  {
   WaitCursorEnd();
   return NULL;
  }
  DWORD dwSize = DIBlockSize(lpDIB);
  hDib = GlobalReAlloc(hDib, dwSize, 0);
  lpbi = (BITMAPINFO *)GlobalLock(hDib);
  CopyMemory((LPBYTE)lpbi, (LPBYTE)lpDIB, dwSize);
  GlobalUnlock(hNewDib);
  GlobalFree(hNewDib);
 }

 wNumColors = DIBNumColors((LPBYTE)lpbi);
 BYTE GrayValue = 0;
 WORD i;
 switch (nMethod)
 {
 case MAXIMUM_GRAY:
  for (i=0; i<wNumColors; i++)
  {
   GrayValue = max(max(lpbi->bmiColors[i].rgbRed,
    lpbi->bmiColors[i].rgbGreen),
    lpbi->bmiColors[i].rgbBlue);
   lpbi->bmiColors[i].rgbRed   =
    lpbi->bmiColors[i].rgbGreen =
    lpbi->bmiColors[i].rgbBlue  = GrayValue;


  }
  break;
 case MEAN_GRAY:
  for (i=0; i<wNumColors; i++)
  {
   GrayValue = min(255,
    (lpbi->bmiColors[i].rgbRed +
    lpbi->bmiColors[i].rgbGreen +
    lpbi->bmiColors[i].rgbBlue)/3);
   lpbi->bmiColors[i].rgbRed   =
    lpbi->bmiColors[i].rgbGreen =
    lpbi->bmiColors[i].rgbBlue  = GrayValue;
  }
  break;
 case WEIGHT_GRAY:
  for (i=0; i<wNumColors; i++)
  {
   GrayValue = min(255,
    (BYTE)(lpbi->bmiColors[i].rgbRed*fRedWeight +
    lpbi->bmiColors[i].rgbGreen*fGreenWeight +
    lpbi->bmiColors[i].rgbBlue*fBlueWeight));
   lpbi->bmiColors[i].rgbRed   =
    lpbi->bmiColors[i].rgbGreen =
    lpbi->bmiColors[i].rgbBlue  = GrayValue;
  }
  break;
 case OTHER_GRAY: //该法旨在通过有选择的灰度化。
  for ( i = 0; i<wNumColors; i++)
  {
   BYTE b,g,r;
   r = lpbi->bmiColors[i].rgbRed;
   g = lpbi->bmiColors[i].rgbGreen;
   b = lpbi->bmiColors[i].rgbBlue;
   double h,s;
   h = 180.0/3.1415926*acos((2*r-g-b)/2.0/sqrt(pow(float(r-g),2)+(r-b)*(g-b)));
   s = 1 - 3.0/(r+g+b)*min((r,g),(r,b));
   if( b >(r+g))//为蓝色降低蓝色比例
    GrayValue = 0;
   else
    GrayValue = min(255,
    (BYTE)(lpbi->bmiColors[i].rgbRed*0.5 +
    lpbi->bmiColors[i].rgbGreen*0.4 +
    lpbi->bmiColors[i].rgbBlue*0.1));

   lpbi->bmiColors[i].rgbRed   =
    lpbi->bmiColors[i].rgbGreen =
    lpbi->bmiColors[i].rgbBlue  = GrayValue;
  }
  break;
 }
 GlobalUnlock(hDib);
 WaitCursorEnd();

 return CreateDIBPalette(hDib);
}
HDIB ColorQuantizeDIB(HDIB hDIB, UINT nColorBits, UINT nMaxColors)
{
 HPALETTE hPal = NULL;

 WaitCursorBegin();

 // color quantization palette
 LPBYTE lpDIB = (LPBYTE)GlobalLock(hDIB);

 hPal = CreateOctreePalette(lpDIB, nMaxColors, nColorBits);

 GlobalUnlock(hDIB);

 // convert DIB to new format
 HDIB hNewDIB = ConvertDIBFormat(hDIB, nColorBits, hPal);

 WaitCursorEnd();

 return hNewDIB;
}

/*************************************************************************
*
* 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;
}

HPALETTE CreateOctreePalette(HDIB hDIB, UINT nMaxColors, UINT nColorBits)
{
 HANDLE hImage;

 hImage = DIBToDIBSection(hDIB);
 if (! hImage)
  return NULL;
 return BuildOctreePalette(hImage, nMaxColors, nColorBits);
}

HPALETTE CreateOctreePalette(LPBYTE lpDIB, UINT nMaxColors, UINT nColorBits)
{
 HANDLE hImage;

 hImage = DIBToDIBSection(lpDIB);
 if (! hImage)
  return NULL;
 return BuildOctreePalette(hImage, nMaxColors, nColorBits);
}

HPALETTE BuildOctreePalette(HANDLE hImage, UINT nMaxColors, UINT nColorBits)
{
 DIBSECTION ds;
 int i, j, nPad;
 BYTE* pbBits;
 WORD* pwBits;
 DWORD* pdwBits;
 DWORD rmask, gmask, bmask;
 int rright, gright, bright;
 int rleft, gleft, bleft;
 BYTE r, g, b;
 WORD wColor;
 DWORD dwColor, dwSize;
 LOGPALETTE* plp;
 HPALETTE hPalette;
 NODE* pTree;
 UINT nLeafCount, nIndex;
 NODE* pReducibleNodes[9];
 HDC hdc;   
 BYTE* pBuffer;   
 BITMAPINFO bmi;

 // Initialize octree variables
 pTree = NULL;
 nLeafCount = 0;
 if (nColorBits > 8) // Just in case
  return NULL;
 for (i=0; i<=(int) nColorBits; i++)
  pReducibleNodes[i] = NULL;

 // Scan the DIB and build the octree
 GetObject (hImage, sizeof (ds), &ds);
 nPad = ds.dsBm.bmWidthBytes - (((ds.dsBmih.biWidth *
  ds.dsBmih.biBitCount) + 7) / 8);

 switch (ds.dsBmih.biBitCount) {

 case 1: // 1-bit DIB   
 case 4: // 4-bit DIB   
 case 8: // 8-bit DIB
  //       
  // The strategy here is to use ::GetDIBits to convert the
  // image into a 24-bit DIB one scan line at a time. A pleasant
  // side effect of using ::GetDIBits in this manner is that RLE-
  // encoded 4-bit and 8-bit DIBs will be uncompressed.        //
  hdc = GetDC (NULL);       
  pBuffer = new BYTE[ds.dsBmih.biWidth * 3];
  ZeroMemory (&bmi, sizeof (bmi));
  bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
  bmi.bmiHeader.biWidth = ds.dsBmih.biWidth;
  bmi.bmiHeader.biHeight = ds.dsBmih.biHeight;
  bmi.bmiHeader.biPlanes = 1;       
  bmi.bmiHeader.biBitCount = 24;
  bmi.bmiHeader.biCompression = BI_RGB;
  for (i=0; i<ds.dsBmih.biHeight; i++)
  {
   GetDIBits (hdc, (HBITMAP) hImage, i, 1, pBuffer, &bmi,
    DIB_RGB_COLORS);           
   pbBits = pBuffer;
   for (j=0; j<ds.dsBmih.biWidth; j++)
   {               
    b = *pbBits++;
    g = *pbBits++;               
    r = *pbBits++;
    AddColor (&pTree, r, g, b, nColorBits, 0, &nLeafCount,
     pReducibleNodes);
    while (nLeafCount > nMaxColors)
     ReduceTree (nColorBits, &nLeafCount, pReducibleNodes);           
   }       
  }
  delete pBuffer;       
  ReleaseDC (NULL, hdc);       
  break;   

 case 16: // One case for 16-bit DIBs
  if (ds.dsBmih.biCompression == BI_BITFIELDS) {
   rmask = ds.dsBitfields[0];
   gmask = ds.dsBitfields[1];
   bmask = ds.dsBitfields[2];
  }
  else {
   rmask = 0x7C00;
   gmask = 0x03E0;
   bmask = 0x001F;
  }

  rright = GetRightShiftCount (rmask);
  gright = GetRightShiftCount (gmask);
  bright = GetRightShiftCount (bmask);

  rleft = GetLeftShiftCount (rmask);
  gleft = GetLeftShiftCount (gmask);
  bleft = GetLeftShiftCount (bmask);

  pwBits = (WORD*) ds.dsBm.bmBits;
  for (i=0; i<ds.dsBmih.biHeight; i++) {
   for (j=0; j<ds.dsBmih.biWidth; j++) {
    wColor = *pwBits++;
    b = (BYTE) (((wColor & (WORD) bmask) >> bright) << bleft);
    g = (BYTE) (((wColor & (WORD) gmask) >> gright) << gleft);
    r = (BYTE) (((wColor & (WORD) rmask) >> rright) << rleft);
    AddColor (&pTree, r, g, b, nColorBits, 0, &nLeafCount,
     pReducibleNodes);
    while (nLeafCount > nMaxColors)
     ReduceTree (nColorBits, &nLeafCount, pReducibleNodes);
   }
   pwBits = (WORD*) (((BYTE*) pwBits) + nPad);
  }
  break;

 case 24: // Another for 24-bit DIBs
  pbBits = (BYTE*) ds.dsBm.bmBits;
  for (i=0; i<ds.dsBmih.biHeight; i++) {
   for (j=0; j<ds.dsBmih.biWidth; j++) {
    b = *pbBits++;
    g = *pbBits++;
    r = *pbBits++;
    AddColor (&pTree, r, g, b, nColorBits, 0, &nLeafCount,
     pReducibleNodes);
    while (nLeafCount > nMaxColors)
     ReduceTree (nColorBits, &nLeafCount, pReducibleNodes);
   }
   pbBits += nPad;
  }
  break;

 case 32: // And another for 32-bit DIBs
  if (ds.dsBmih.biCompression == BI_BITFIELDS) {
   rmask = ds.dsBitfields[0];
   gmask = ds.dsBitfields[1];
   bmask = ds.dsBitfields[2];
  }
  else {
   rmask = 0x00FF0000;
   gmask = 0x0000FF00;
   bmask = 0x000000FF;
  }

  rright = GetRightShiftCount (rmask);
  gright = GetRightShiftCount (gmask);
  bright = GetRightShiftCount (bmask);

  pdwBits = (DWORD*) ds.dsBm.bmBits;
  for (i=0; i<ds.dsBmih.biHeight; i++) {
   for (j=0; j<ds.dsBmih.biWidth; j++) {
    dwColor = *pdwBits++;
    b = (BYTE) ((dwColor & bmask) >> bright);
    g = (BYTE) ((dwColor & gmask) >> gright);
    r = (BYTE) ((dwColor & rmask) >> rright);
    AddColor (&pTree, r, g, b, nColorBits, 0, &nLeafCount,
     pReducibleNodes);
    while (nLeafCount > nMaxColors)
     ReduceTree (nColorBits, &nLeafCount, pReducibleNodes);
   }
   pdwBits = (DWORD*) (((BYTE*) pdwBits) + nPad);
  }
  break;

 default: // DIB must be 16, 24, or 32-bit!
  return NULL;
 }

 if (nLeafCount > nMaxColors) { // Sanity check
  DeleteTree (&pTree);
  return NULL;
 }

 // Create a logical palette from the colors in the octree
 dwSize = sizeof (LOGPALETTE) + ((nLeafCount - 1) * sizeof (PALETTEENTRY));
 if ((plp = (LOGPALETTE*) HeapAlloc (GetProcessHeap (), 0,
  dwSize)) == NULL) {
   DeleteTree (&pTree);
   return NULL;
 }

 plp->palVersion = 0x300;
 plp->palNumEntries = (WORD) nLeafCount;
 nIndex = 0;
 GetPaletteColors (pTree, plp->palPalEntry, &nIndex);
 hPalette = CreatePalette (plp);

 HeapFree (GetProcessHeap (), 0, plp);
 DeleteTree (&pTree);
 return hPalette;
}

void AddColor (NODE** ppNode, BYTE r, BYTE g, BYTE b, UINT nColorBits,
      UINT nLevel, UINT* pLeafCount, NODE** pReducibleNodes)
{
 int nIndex, shift;
 static BYTE mask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };

 // If the node doesn't exist, create it
 if (*ppNode == NULL)
  *ppNode = CreateNode (nLevel, nColorBits, pLeafCount,
  pReducibleNodes);

 // Update color information if it's a leaf node
 if ((*ppNode)->bIsLeaf) {
  (*ppNode)->nPixelCount++;
  (*ppNode)->nRedSum += r;
  (*ppNode)->nGreenSum += g;
  (*ppNode)->nBlueSum += b;
 }

 // Recurse a level deeper if the node is not a leaf
 else {
  shift = 7 - nLevel;
  nIndex = (((r & mask[nLevel]) >> shift) << 2) |
   (((g & mask[nLevel]) >> shift) << 1) |
   ((b & mask[nLevel]) >> shift);
  AddColor (&((*ppNode)->pChild[nIndex]), r, g, b, nColorBits,
   nLevel + 1, pLeafCount, pReducibleNodes);
 }
}

NODE* CreateNode (UINT nLevel, UINT nColorBits, UINT* pLeafCount,
      NODE** pReducibleNodes)
{
 NODE* pNode;

 if ((pNode = (NODE*) HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY,
  sizeof (NODE))) == NULL)
  return NULL;

 pNode->bIsLeaf = (nLevel == nColorBits) ? TRUE : FALSE;
 if (pNode->bIsLeaf)
  (*pLeafCount)++;
 else { // Add the node to the reducible list for this level
  pNode->pNext = pReducibleNodes[nLevel];
  pReducibleNodes[nLevel] = pNode;
 }
 return pNode;
}

void ReduceTree (UINT nColorBits, UINT* pLeafCount, NODE** pReducibleNodes)
{
 int i;
 NODE* pNode;
 UINT nRedSum, nGreenSum, nBlueSum, nChildren;

 // Find the deepest level containing at least one reducible node
 for (i=nColorBits - 1; (i>0) && (pReducibleNodes[i] == NULL); i--);

 // Reduce the node most recently added to the list at level i
 pNode = pReducibleNodes[i];
 pReducibleNodes[i] = pNode->pNext;

 nRedSum = nGreenSum = nBlueSum = nChildren = 0;
 for (i=0; i<8; i++) {
  if (pNode->pChild[i] != NULL) {
   nRedSum += pNode->pChild[i]->nRedSum;
   nGreenSum += pNode->pChild[i]->nGreenSum;
   nBlueSum += pNode->pChild[i]->nBlueSum;
   pNode->nPixelCount += pNode->pChild[i]->nPixelCount;
   HeapFree (GetProcessHeap (), 0, pNode->pChild[i]);
   pNode->pChild[i] = NULL;
   nChildren++;
  }
 }

 pNode->bIsLeaf = TRUE;
 pNode->nRedSum = nRedSum;
 pNode->nGreenSum = nGreenSum;
 pNode->nBlueSum = nBlueSum;
 *pLeafCount -= (nChildren - 1);
}

void DeleteTree (NODE** ppNode)
{
 int i;

 for (i=0; i<8; i++) {
  if ((*ppNode)->pChild[i] != NULL)
   DeleteTree (&((*ppNode)->pChild[i]));
 }
 HeapFree (GetProcessHeap (), 0, *ppNode);
 *ppNode = NULL;
}

void GetPaletteColors (NODE* pTree, PALETTEENTRY* pPalEntries, UINT* pIndex)
{
 int i;

 if (pTree->bIsLeaf) {
  pPalEntries[*pIndex].peRed =
   (BYTE) ((pTree->nRedSum) / (pTree->nPixelCount));
  pPalEntries[*pIndex].peGreen =
   (BYTE) ((pTree->nGreenSum) / (pTree->nPixelCount));
  pPalEntries[*pIndex].peBlue =
   (BYTE) ((pTree->nBlueSum) / (pTree->nPixelCount));
  (*pIndex)++;
 }
 else {
  for (i=0; i<8; i++) {
   if (pTree->pChild[i] != NULL)
    GetPaletteColors (pTree->pChild[i], pPalEntries, pIndex);
  }
 }
}

int GetRightShiftCount (DWORD dwVal)
{
 int i;

 for (i=0; i<sizeof (DWORD) * 8; i++) {
  if (dwVal & 1)
   return i;
  dwVal >>= 1;
 }
 return -1;
}

int GetLeftShiftCount (DWORD dwVal)
{
 int nCount, i;

 nCount = 0;
 for (i=0; i<sizeof (DWORD) * 8; i++) {
  if (dwVal & 1)
   nCount++;
  dwVal >>= 1;
 }
 return (8 - nCount);
}

/*************************************************************************
*
* ChangeDIBFormat()
*
* Parameter:
*
* HDIB             - handle to packed-DIB in memory
*
*     -DIB内存块句柄
*
* 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.
* 注意:本函数将DIB转化为指定格式DDB,源位图将不被修改,不要象下例一样调用
*   hMyDIB = ChangeDIBFormat(hMyDIB,8,BI_RLE4)
*   否则转化将失败,hMyDIB将为NULL,而源位图所站的内存将不被释放。
*
*
************************************************************************/
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.
*
*  功能:用指定的格式来创建DIB,将源图像拷贝到新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
*      TRUE:伸缩源位图到目标位图,FALSE:按原图像大小进行显示,起点为左上角
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.
*
*  功能:用于格式转换时颜色表的拷贝,保证不丢失颜色,如果DIB从高颜色分辨率到
*     低颜色分辨率的转化时,用此函数进行量化,并调用创建相应调色板函数CreateOctreePalette
*
*     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
*
*  功能:根据DIB创建DIBSection
*
*     PURPOSE:  Create DIBSECTION from DIB
*
*     PARAMS:   LPBYTE lpDIB - pointer to DIB data buffer
*
*  参数:DIB数据缓冲区地址
*
*     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;
}

/*************************************************************************
*
* 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);
 //The CreateDIBitmap function creates a compatible bitmap (DDB) from
 //a DIB and, optionally, sets the bitmap bits.

 

 // restore previous palette
 if (hOldPal)
  SelectPalette(hDC, hOldPal, FALSE);

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

 // return handle to the bitmap
 return hBitmap;
}


/*************************************************************************
*
* 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 = MYWIDTHBYTES((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;
}

bool GrayEqualize(HDIB hDib)
{

 int nHeight, nWidth, i, j, k;

 // 指向源图像的指针
 LPBYTE  lpSrc = NULL;
 WaitCursorBegin();
 
 // 灰度映射表
 int  bGray[256];
 long long bConvert[256],bHist[256];
 memset(bGray, 0 , 256* sizeof(int));
 memset(bHist, 0 , 256* sizeof(long));
 memset(bConvert, 0 , 256* sizeof(long));

 LPBYTE lpDIB = (LPBYTE) GlobalLock( hDib );
 int nNumColors = DIBBitCount(lpDIB);
 if( nNumColors != 8 )
  return false;

 LPBYTE lpDIBBits = FindDIBBits( lpDIB );
 nHeight  = DIBHeight( lpDIB );
 nWidth  = DIBWidth( lpDIB );

 // 计算图像每行的字节数
 LONG lLineBytes = BytesPerLine( lpDIB ); 
 lpSrc = lpDIBBits;
 for (i = 0, k = 0; i < nHeight; ++i, k += lLineBytes )
 {
  lpSrc = lpDIBBits + k; 
  for ( j = 0; j < nWidth; ++j, ++lpSrc )
  {
   bGray[*(lpSrc)]++;
  }  
 }
 bHist[0] = bGray[0];
 long long *pHist = bHist;
 int *pGray = bGray;
 long long *pConver = bConvert;
 int  nTotal = nHeight * nWidth;
 *pConver ++ = (long)  (*pHist * 255)/nTotal;
 pHist++;
 pGray++;
 for ( i = 1; i <= 255; i++, pHist++, pGray++ , pConver ++)
 {
  *pHist = *pGray + *(pHist-1); //形成累积直方图
  *pConver =((long long )  (*pHist) )*255 / nTotal ;  
 }
 
 for ( i = 0, k = 0; i < nHeight; i++, k+= lLineBytes )
 {
  lpSrc = lpDIBBits + k;
  for ( j = 0; j < nWidth; j++, lpSrc ++ )
  {
   *lpSrc = bConvert[*lpSrc];   //更新原始位图数据
  }
 }
 GlobalUnlock( hDib );
 WaitCursorEnd();
 return true;
}

bool GrayStretchDIB(int nMethod, HDIB hDib,BYTE bX1 = 0,BYTE bY1 = 0 ,BYTE bX2 = 255, BYTE  bY2 = 255 )
{
 WaitCursorBegin();

 LPBYTE lpDIB,lpDIBBits;
 DWORD lHeight,lWidth;

 // 指向源图像的指针
 unsigned char* lpSrc;

 // 循环变量
 LONG i = 0;
 // LONG j;

 // 灰度映射表
 BYTE bMap[256];

 // 图像每行的字节数
 LONG lLineBytes;

 lpDIB = (LPBYTE) GlobalLock( hDib );

 lpDIBBits = FindDIBBits( lpDIB );
 lHeight  = DIBHeight( lpDIB );
 lWidth  = DIBWidth( lpDIB );
 // 计算图像每行的字节数

 lLineBytes = BytesPerLine( lpDIB);
 if( nMethod == 0 ) //自动计算X1, Y1; X2,Y2;
 {
  int nHist[256];
  if( !GetGrayHist(lpDIBBits, lWidth, lHeight, nHist))
   return false;
  long nCumulHist[256];
  if( !GetCumulativeHist(nHist, 256, nCumulHist))
   return false;
  for( i = 0; i < 256; ++i )
  {
   if( nCumulHist[i] > lWidth * lHeight / 10 )
   {
    bX1 = i;
    break;
   }
  }
  for( i = 255; i > bX1; --i )
  {
   if(nCumulHist[i] < lHeight * lWidth * 9 / 10)
   {
    bX2 = i;
    break;
   }
  }  
 }


 // 计算灰度映射表
 memset(bMap, 0 , bX1 * sizeof(BYTE));
 float fTmp = 0;
 if( bX1 > 0 )
 {
  fTmp = float(bY1)/int(bX1);
  for (i = 0; i <= bX1; i++)
  {
   // 线性变换
    bMap[i] = (BYTE)  (i * fTmp);
  }
  }
 if( bX2 == bX1 )//判断bX1是否等于bX2(防止分母为0)
 {
  memset(bMap+ i, bY1, (bX2 - bX1 + 1) *sizeof(BYTE));
 }
 else
 {
  fTmp = float(bY2 - bY1) / int(bX2- bX1);
  for (; i <= bX2; i++)
  {
   // 线性变换
   bMap[i] = bY1 + (BYTE) ( (i - bX1) / fTmp);  
  }
 }
 fTmp = float ( 255- bY2 ) / int(255- bX2);

 if (bX2 == 255 )
 {
  memset(bMap + i,  255, (255-i +1) *sizeof(BYTE));
 }
 else
 {
  for (; i < 256; i++)
  {
   // 线性变换
   bMap[i] = bY2 + (BYTE) (fTmp * (i - bX2));
  }
 }
 

 // 每行
 for(DWORD i1 = 0, k = 0; i1 < lHeight; i1++, k+= lLineBytes )
 {
  lpSrc = lpDIBBits + k;
  // 每列
  for(DWORD j1 = 0; j1 < lWidth; j1++, lpSrc++)
  {
   // 计算新的灰度值
   *lpSrc = bMap[*lpSrc];
  }
 }
 GlobalUnlock( hDib );
 WaitCursorEnd();
 // 返回
 return TRUE;
}

bool GetGrayHist(const BYTE * pbImg, const int nImgWid, const int nImgHei, int *pnHist )
{
 if( pbImg == NULL || pnHist == NULL || nImgWid < 1 || nImgHei < 1 )
  return false;
 int i, j, k, nBytePerLine;
 const BYTE * lptmpBits = pbImg;
 memset(pnHist, 0, 256 * sizeof(int));

 nBytePerLine = MYWIDTHBYTES(nImgWid << 3);
 for ( i = 0, k = 0; i < nImgHei;  i++, k += nBytePerLine )  //ImageSize should be greater.
 {
  lptmpBits = pbImg + k;
  for ( j = 0; j < nImgWid; j++ )
  {
   pnHist[*lptmpBits ]++;
   lptmpBits++;
  }  
 }

 return true;
}
bool GetCumulativeHist(const int *pnHist, int nLength, long *pnCuHist)
{
 if( pnHist == NULL || pnCuHist == NULL || nLength < 1 )
  return false;

 memset( pnCuHist, 0, nLength * sizeof(long) );

 const int *pnIn = pnHist;
 long * pnOut = pnCuHist;

 *pnOut ++ = *pnIn ++;
 for( int i = 1; i < 256; i++, pnOut++, pnIn++  )
 {
  *pnOut = *pnIn + *(pnOut - 1);
 }
 return true;
}
// nMethod: 0:去污,原来白色的变为黑色,原来黑色的变成白色
// nMethod: 1 :磨白,把选中的区域变成白色
// nMethod 2:填充, 把选中的区域变成黑色
bool EliminateDirtDIB(int nMethod, HDIB hDib, CRect rect)
{
 WaitCursorBegin();
 LPBYTE lpDIB,lpDIBBits;
 lpDIB = lpDIBBits = NULL;
 lpDIB = (LPBYTE) GlobalLock( hDib );

 DWORD lHeight, lWidth;
 lpDIBBits = FindDIBBits( lpDIB );
 lHeight  = DIBHeight( lpDIB );
 lWidth  = DIBWidth( lpDIB );

 // 计算图像每行的字节数
 LONG lLineBytes = BytesPerLine( lpDIB);

 // 指向源图像的指针
 unsigned char* lpSrc = lpDIBBits;
 BYTE btmp = 0;
 int i, j, k, nSum = 0;
 if( nMethod == 0 )
 {
  for(  i = lHeight - rect.bottom, k = i * lLineBytes; i < lHeight - rect.top; i++, k += lLineBytes )
  {
   lpSrc = lpDIBBits + k + rect.left/8;
   for(  j = rect.left/8; j < rect.right/8; j++, lpSrc++  )
   {
    if( *lpSrc == 255 )
     nSum++;
   }
  }
  if( nSum < rect.Width() * rect.Height() / 2 )
   btmp = 255;
 }
 else if(nMethod == 1)
 {
  btmp = 255;
 }
 else
 {
  btmp = 0;
 }

 

 for(  i = lHeight - rect.bottom, k = i * lLineBytes; i < lHeight - rect.top; i++, k += lLineBytes )
 {
  lpSrc = lpDIBBits + k + rect.left/8;
  for( int j = rect.left/8; j < rect.right/8; j++, lpSrc++  )
  {
   *lpSrc = btmp;   
  }
 }
 GlobalUnlock( hDib );
 WaitCursorEnd();
 return true;
}
// nMethod: 0:去污,原来白色的变为黑色,原来黑色的变成白色
// nMethod:1 :磨白,把选中的区域变成白色
// nMethod 2:填充,把选中的区域变成黑色
bool EliminateDirtDIB(int nMethod, HDIB hDib, int nCircleX, int nCircleY, int nRadius )
{
 WaitCursorBegin();


 LPBYTE lpDIB,lpDIBBits;
 lpDIB = lpDIBBits = NULL;
 lpDIB = (LPBYTE) GlobalLock( hDib );

 DWORD lHeight, lWidth;
 lpDIBBits = FindDIBBits( lpDIB );
 lHeight  = DIBHeight( lpDIB );
 lWidth  = DIBWidth( lpDIB );

 // 计算图像每行的字节数
 LONG lLineBytes = BytesPerLine( lpDIB);

 // 指向源图像的指针
 unsigned char* lpSrc = lpDIBBits;
 int nLeft, nRight, nTop, nBottom, nX2, nY2, nC2;

 BYTE btmp = 0;
 nLeft = nCircleX - nRadius  > 0 ? nCircleX - nRadius : 0;
 nRight = nCircleX + nRadius < lWidth ? nCircleX + nRadius : lWidth - 1;
 nTop = lHeight - 1 - nCircleY - nRadius  > 0 ? lHeight - 1 - nCircleY - nRadius : 0;
 nBottom = lHeight - 1 - nCircleY + nRadius < lHeight ?  lHeight - 1 - nCircleY + nRadius : lHeight - 1;
 nC2 = nRadius * nRadius;
 int i, j, k, nSum = 0;
 if( nMethod == 0 )
 {
  for( i = nTop, k = i * lLineBytes; i < nBottom; i++, k += lLineBytes )
  {
   lpSrc = lpDIBBits + k + nLeft/8;
   nY2 = (lHeight - 1 - nCircleY - i) * (lHeight - 1 - nCircleY - i);
   for( j = nLeft/8; j < nRight/8; j++, lpSrc++  )
   {
    nX2 =( j * 8 - nCircleX ) * ( j * 8 - nCircleX);
    if( nX2 + nY2 < nC2 && *lpSrc == 255 )
    {
     nSum++;
    }
   }
  }
  if(nSum < 3.14 * nRadius * nRadius/2 )
   btmp = 255;
 }
 else if( nMethod == 1 )
 {
  btmp = 255;
 }
 else
 {
  btmp = 0;
 }
 

 for( i = nTop, k = i * lLineBytes; i < nBottom; i++, k += lLineBytes )
 {
  lpSrc = lpDIBBits + k + nLeft/8;
  nY2 = (lHeight - 1 - nCircleY - i) * (lHeight - 1 - nCircleY - i);
  for( j = nLeft/8; j < nRight/8; j++, lpSrc++  )
  {
   nX2 =( j * 8 - nCircleX ) * ( j * 8 - nCircleX);
   if( nX2 + nY2 < nC2 )
   {
    *lpSrc = btmp;   
   }
  }
 }

 GlobalUnlock( hDib );
 WaitCursorEnd();
 return true;
}


//saving bi-bitmap to file, only for debug
void SaveTo8bit_BMP(const BYTE* pbInputMat, int Width, int Height, const char* szFileName, int nGrayLevel)
{
 const BYTE* pbInput = pbInputMat;

 int nNewWidth = (Width + 3) / 4 * 4;
 long imageSize = nNewWidth * Height;

 BYTE* TmpImg = new BYTE[imageSize]; 
 memset(TmpImg, 255, imageSize * sizeof(BYTE));

 if (nGrayLevel == 2)
 {
  
  for (int i = 0; i < Height; ++i)
  {
   for (int j = 0; j < Width/8; ++j)
   {
    TmpImg[(Height-i-1)*nNewWidth + j] = 255 - pbInput[i*Width+j]*255;
   }
  }
 }
 else if (nGrayLevel == 8)
 {
  for (int i = 0; i < Height; ++i)
  {
   for (int j = 0; j < Width; ++j)
   {
    TmpImg[i*nNewWidth + j] = pbInput[i*nNewWidth+j];
   }
  }  
 } 
 else
 {
  return;
 }

 BYTE pbHead[1078];
 memset(pbHead, 0, 1078 * sizeof(BYTE));

 //设置各字段值 
 pbHead[0] = 0x42; //0x4d42
 pbHead[1] = 0x4D;

 DWORD nSize = imageSize + 1078;
 memcpy(pbHead + 2, &nSize, sizeof(DWORD));//size 

 pbHead[10] = 0x36; //offset
 pbHead[11] = 0x04;
 pbHead[12] = 0;
 pbHead[13] = 0;

 pbHead[14] = 0x28;

 LONG nxSize = nNewWidth;
 memcpy(pbHead + 18, &nxSize, sizeof(LONG));//WIDTH

 nxSize = Height;
 memcpy(pbHead + 22, &nxSize, sizeof(LONG));//HEIGHT  

 pbHead[26] = 0x1;

 pbHead[28] = 0x8;

 memcpy(pbHead + 34, &nSize, sizeof(DWORD)); 
 //pbHead[47] = 0x1;

 for (int i = 0 ; i < 256 ; i++)
 {
  pbHead[54 + i * 4] = i;
  pbHead[54 + i * 4 + 1] = i;
  pbHead[54 + i * 4 + 2] = i;
  pbHead[54 + i * 4 + 3] = 0;
 }  

 FILE* mFile = fopen(szFileName, ("wb"));
 if (!mFile)
 {   
  delete[] TmpImg;
  return;
 }
 LPBITMAPFILEHEADER ph = (LPBITMAPFILEHEADER)pbHead;
 LPBITMAPINFOHEADER pinfo = (LPBITMAPINFOHEADER) (pbHead + 14);
 fwrite(pbHead, sizeof(BYTE), 1078, mFile);
 fwrite(TmpImg, sizeof(BYTE), imageSize, mFile);
 fclose(mFile);   

 delete[] TmpImg;
}
HDIB ChangeDIBSize(HDIB hDIB, int nWidth, int nHeight)
{
 LPBITMAPINFO lpbmi = NULL;
 LPBYTE       lpSourceBits, lpTargetBits, lpResult;
 HDC    hDC = NULL, hSourceDC, hTargetDC;
 HBITMAP      hSourceBitmap, hTargetBitmap, hOldTargetBitmap, hOldSourceBitmap;
 DWORD        dwSourceBitsSize, dwTargetBitsSize, dwTargetHeaderSize;
 HDIB   hNewDIB;
 DWORD   dwSize;

 WaitCursorBegin();

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

 // Allocate and fill out a BITMAPINFO struct for the new DIB
 dwTargetHeaderSize = sizeof( BITMAPINFOHEADER ) + PaletteSize(lpSrcDIB);
 lpbmi = (LPBITMAPINFO)malloc( dwTargetHeaderSize );
 memcpy(lpbmi, lpSrcDIB, dwTargetHeaderSize);
 lpbmi->bmiHeader.biWidth = nWidth;
 lpbmi->bmiHeader.biHeight = nHeight;

 // 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 );

 // put old bitmap in new bitmap
 SetStretchBltMode( hTargetDC, COLORONCOLOR );
 StretchBlt( hTargetDC, 0, 0, lpbmi->bmiHeader.biWidth, lpbmi->bmiHeader.biHeight, hSourceDC, 0, 0, lpSrcDIB->bmiHeader.biWidth, lpSrcDIB->bmiHeader.biHeight, 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);
 WaitCursorEnd();

 return hNewDIB;
}

3)CompConnect.h

#pragma  once
#ifndef  COMPCONNECT_H
#define  COMPCONNECT_H

const UINT  COMP_NUM  = 1024;    //允许连通体的个数

//提取连通体为黑色区域
const BYTE  CC_START = 255;       
const BYTE     CC_CUR  = 0;

struct component
{
 CRect bound;
 int count;
 component *cnext;
 component()
 {
  count=0;
  cnext=NULL;
 }
};
struct Line
{
 int StartY;
 int EndY;
 int StartX;
 int EndX;
 int LenghthX;
 int LenghthY;
 int TotalSize;
 //Line *Next; 
 //float Type_Flag;
 component *cp;
 //Block *pBlkStart;
 //float AveComH;
 Line()
 {
  StartX =0;
  EndX =0;
  StartY = 0;
  EndY = 0;
  LenghthX = 0;
  LenghthY = 0;
  TotalSize = 0;
  cp = NULL;
 
 }
 ~Line()
 {
  component *temp;
  while(cp!=NULL)
  {
   temp = cp;
   cp  = cp->cnext;

   delete temp;
  }
 }

};

#endif

4)ImgCov.h 用于将jpg、tif等格式的文件转换成DIB格式

#ifndef IMGCONV_H
#define IMGCONV_H

extern "C"
{

#ifdef GENERATE_DLL
#define DLL_EXPORT __declspec(dllexport)
#else // #ifdef GENERATE_DLL
#define DLL_EXPORT
#endif // #ifdef GENERATE_DLL

/*  Format Description                             Qt's support
 *  BMP     Windows Bitmap                          Read/Write
 *  GIF     Graphic Interchange Format (optional)   Read
 *  JPG     Joint Photographic Experts Group        Read/Write
 *  JPEG    Joint Photographic Experts Group        Read/Write
 *  PNG     Portable Network Graphics               Read/Write
 *  PBM     Portable Bitmap                         Read
 *  PGM     Portable Graymap                        Read
 *  PPM     Portable Pixmap                         Read/Write
 *  TIFF    Tagged Image File Format                Read/write
 *  XBM     X11 Bitmap                              Read/Write
 *  XPM     X11 Pixmap                              Read/Write
 * note: this lib's support is exactly same as Qt's.
*/

enum ImageType
{
    imgBMP  =  0,
    imgGIF  =  1,
    imgJPG  =  2,
    imgJPEG =  3,
    imgPNG  =  4,
    imgPBM  =  5,
    imgPGM  =  6,
    imgPPM  =  7,
    imgTIFF =  8,
    imgXBM  =  9,
    imgXPM  = 10,
    imgMax  = 10,
};

// ppDestData and pDestDataLen are for outputs;
// when succeeded, *ppDestData is new-ed inside the function, and should be delete-ed by caller calling ImageDelete.
bool DLL_EXPORT ImageConvert(const unsigned char * pSrcData, int nSrcDataLen, ImageType itSrcImageType,
                             unsigned char * * ppDestData, int * pnDestDataLen, ImageType itDestImageType);

bool DLL_EXPORT ImageDelete(unsigned char * * ppImageData);

}
#endif // #ifndef IMGCONV_H

 

 

 

你可能感兴趣的:(常用用图像处理算法(二))