WindowsXP-SP1/windows/feime/cht/cblocks/dib.cpp
2020-09-30 16:53:49 +02:00

852 lines
24 KiB
C++

/*************************************************
* dib.cpp *
* *
* Copyright (C) 1995-1999 Microsoft Inc. *
* *
*************************************************/
// dib.cpp : implementation file
//
//
#include "stdafx.h"
#include "dib.h"
#include "malloc.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
#define WIDTHBYTES(i) ((i+31)/32*4)
/////////////////////////////////////////////////////////////////////////////
// CDIB
IMPLEMENT_SERIAL(CDIB, CObject, 0 /* schema number*/ )
// Create a small DIB here so m_pBMI and m_pBits are always valid
CDIB::CDIB()
{
m_pBMI = NULL;
m_pBits = NULL;
m_bMyBits = TRUE;
Create(16, 16);
}
CDIB::~CDIB()
{
// free the memory
if (m_pBMI != NULL) free(m_pBMI);
if (m_bMyBits && (m_pBits != NULL))
free(m_pBits);
}
/////////////////////////////////////////////////////////////////////////////
// CDIB serialization
// We dont' support this yet
void CDIB::Serialize(CArchive& ar)
{
ar.Flush();
CFile *fp = ar.GetFile();
if (ar.IsStoring()) {
Save(fp);
} else {
Load(fp);
}
}
/////////////////////////////////////////////////////////////////////////////
// Private functions
static BOOL IsWinDIB(BITMAPINFOHEADER *pBIH)
{
ASSERT(pBIH);
if (((BITMAPCOREHEADER *)pBIH)->bcSize == sizeof(BITMAPCOREHEADER)) {
return FALSE;
}
return TRUE;
}
static int NumDIBColorEntries(BITMAPINFO *pBmpInfo)
{
BITMAPINFOHEADER *pBIH;
BITMAPCOREHEADER *pBCH;
int iColors, iBitCount;
ASSERT(pBmpInfo);
pBIH = &(pBmpInfo->bmiHeader);
pBCH = (BITMAPCOREHEADER *) pBIH;
// start off by assuming the color table size from
// the bit per pixel field
if (IsWinDIB(pBIH)) {
iBitCount = pBIH->biBitCount;
} else {
iBitCount = pBCH->bcBitCount;
}
switch (iBitCount) {
case 1:
iColors = 2;
break;
case 4:
iColors = 16;
break;
case 8:
iColors = 256;
break;
default:
iColors = 0;
break;
}
// If this is a Windows DIB, then the color table length
// is determined by the biClrUsed field if it is non-zero
if (IsWinDIB(pBIH) && (pBIH->biClrUsed != 0)) {
iColors = pBIH->biClrUsed;
}
return iColors;
}
/////////////////////////////////////////////////////////////////////////////
// CDIB commands
// Create a new empty 8bpp DIB with a 256 entry color table
BOOL CDIB::Create(int iWidth, int iHeight)
{
// delete any existing stuff
if (m_pBMI != NULL) free(m_pBMI);
if (m_bMyBits && (m_pBits != NULL)) free(m_pBits);
// allocate memory for the header
m_pBMI = (BITMAPINFO *) malloc(sizeof(BITMAPINFOHEADER)
+ 256 * sizeof(RGBQUAD));
if (!m_pBMI) {
TRACE("Out of memory for DIB header");
return FALSE;
}
// allocate memory for the bits (DWORD aligned)
int iBitsSize = ((iWidth + 3) & ~3) * iHeight;
m_pBits = (BYTE *)malloc(iBitsSize);
if (!m_pBits) {
TRACE("Out of memory for DIB bits");
free(m_pBMI);
m_pBMI = NULL;
return FALSE;
}
m_bMyBits = TRUE;
// fill in the header info
BITMAPINFOHEADER *pBI = (BITMAPINFOHEADER *) m_pBMI;
pBI->biSize = sizeof(BITMAPINFOHEADER);
pBI->biWidth = iWidth;
pBI->biHeight = iHeight;
pBI->biPlanes = 1;
pBI->biBitCount = 8;
pBI->biCompression = BI_RGB;
pBI->biSizeImage = 0;
pBI->biXPelsPerMeter = 0;
pBI->biYPelsPerMeter = 0;
pBI->biClrUsed = 0;
pBI->biClrImportant = 0;
// create an arb color table (gray scale)
RGBQUAD *prgb = GetClrTabAddress();
for (int i = 0; i < 256; i++) {
prgb->rgbBlue = prgb->rgbGreen = prgb->rgbRed = (BYTE) i;
prgb->rgbReserved = 0;
prgb++;
}
// set all the bits to a known state (black)
memset(m_pBits, 0, iBitsSize);
return TRUE;
}
// Create a CDIB structure from existing header and bits. The DIB
// won't delete the bits and makes a copy of the header.
BOOL CDIB::Create(BITMAPINFO *pBMI, BYTE *pBits)
{
int iNumColorEntries;
ASSERT(pBMI);
ASSERT(pBits);
if (m_pBMI != NULL) free(m_pBMI);
m_pBMI = (BITMAPINFO *) malloc(sizeof(BITMAPINFOHEADER)
+ 256 * sizeof(RGBQUAD));
ASSERT(m_pBMI);
iNumColorEntries = NumDIBColorEntries(pBMI);
if ( iNumColorEntries > 256 )
iNumColorEntries = 256;
memcpy(m_pBMI, pBMI, sizeof(BITMAPINFOHEADER)+
iNumColorEntries * sizeof(RGBQUAD));
if (m_bMyBits && (m_pBits != NULL)) free(m_pBits);
m_pBits = pBits;
m_bMyBits = FALSE; // we can't delete the bits
return TRUE;
}
// Load a DIB from an open file.
BOOL CDIB::Load(CFile *fp)
{
BOOL bIsPM = FALSE;
BITMAPINFO *pBmpInfo = NULL;
BYTE *pBits = NULL;
// get the current file position
DWORD dwFileStart = fp->GetPosition();
// read the file header to get the file size and to
// find where the bits start in the file
BITMAPFILEHEADER BmpFileHdr;
int iBytes;
iBytes = fp->Read(&BmpFileHdr, sizeof(BmpFileHdr));
if (iBytes != sizeof(BmpFileHdr)) {
TRACE("Failed to read file header");
goto $abort;
}
// check we have the magic 'BM' at the start
if (BmpFileHdr.bfType != 0x4D42) {
TRACE("Not a bitmap file");
goto $abort;
}
// make a wild guess that the file is in Windows DIB
// format and read the BITMAPINFOHEADER. If it turns
// out to be a PM DIB file we'll convert it later.
BITMAPINFOHEADER BmpInfoHdr;
iBytes = fp->Read(&BmpInfoHdr, sizeof(BmpInfoHdr));
if (iBytes != sizeof(BmpInfoHdr)) {
TRACE("Failed to read BITMAPINFOHEADER");
goto $abort;
}
// check we got a real Windows DIB file
if (BmpInfoHdr.biSize != sizeof(BITMAPINFOHEADER)) {
if (BmpInfoHdr.biSize != sizeof(BITMAPCOREHEADER)) {
TRACE(" File is not Windows or PM DIB format");
goto $abort;
}
// set a flag to convert PM file to Win format later
bIsPM = TRUE;
// back up the file pointer and read the BITMAPCOREHEADER
// and create the BITMAPINFOHEADER from it
fp->Seek(dwFileStart + sizeof(BITMAPFILEHEADER), CFile::begin);
BITMAPCOREHEADER BmpCoreHdr;
iBytes = fp->Read(&BmpCoreHdr, sizeof(BmpCoreHdr));
if (iBytes != sizeof(BmpCoreHdr)) {
TRACE("Failed to read BITMAPCOREHEADER");
goto $abort;
}
BmpInfoHdr.biSize = sizeof(BITMAPINFOHEADER);
BmpInfoHdr.biWidth = (int) BmpCoreHdr.bcWidth;
BmpInfoHdr.biHeight = (int) BmpCoreHdr.bcHeight;
BmpInfoHdr.biPlanes = BmpCoreHdr.bcPlanes;
BmpInfoHdr.biBitCount = BmpCoreHdr.bcBitCount;
BmpInfoHdr.biCompression = BI_RGB;
BmpInfoHdr.biSizeImage = 0;
BmpInfoHdr.biXPelsPerMeter = 0;
BmpInfoHdr.biYPelsPerMeter = 0;
BmpInfoHdr.biClrUsed = 0;
BmpInfoHdr.biClrImportant = 0;
}
// Work out how much memory we need for the BITMAPINFO
// structure, color table and then for the bits.
// Allocate the memory blocks, copy the BmpInfoHdr we have so far
// and then read in the color table from the file.
int iColors;
int iColorTableSize;
iColors = NumDIBColorEntries((LPBITMAPINFO) &BmpInfoHdr);
iColorTableSize = iColors * sizeof(RGBQUAD);
int iBitsSize;
int iBISize;
// always allocate enough room for 256 entries
iBISize = sizeof(BITMAPINFOHEADER)
+ 256 * sizeof(RGBQUAD);
iBitsSize = BmpFileHdr.bfSize -
BmpFileHdr.bfOffBits;
// allocate the memory for the header
pBmpInfo = (LPBITMAPINFO) malloc(iBISize);
if (!pBmpInfo) {
TRACE("Out of memory for DIB header");
goto $abort;
}
// copy the header we already have
memcpy(pBmpInfo, &BmpInfoHdr, sizeof(BITMAPINFOHEADER));
// now read the color table in from the file
if (bIsPM == FALSE) {
// read the color table from the file
iBytes = fp->Read(((LPBYTE) pBmpInfo) + sizeof(BITMAPINFOHEADER),
iColorTableSize);
if (iBytes != iColorTableSize) {
TRACE("Failed to read color table");
goto $abort;
}
} else {
// read each PM color table entry in turn and convert it
// to Win DIB format as we go
LPRGBQUAD lpRGB;
lpRGB = (LPRGBQUAD) ((LPBYTE) pBmpInfo + sizeof(BITMAPINFOHEADER));
int i;
RGBTRIPLE rgbt;
for (i=0; i<iColors; i++) {
iBytes = fp->Read(&rgbt, sizeof(RGBTRIPLE));
if (iBytes != sizeof(RGBTRIPLE)) {
TRACE("Failed to read RGBTRIPLE");
goto $abort;
}
lpRGB->rgbBlue = rgbt.rgbtBlue;
lpRGB->rgbGreen = rgbt.rgbtGreen;
lpRGB->rgbRed = rgbt.rgbtRed;
lpRGB->rgbReserved = 0;
lpRGB++;
}
}
// allocate the memory for the bits
// and read the bits from the file
pBits = (BYTE *) malloc(iBitsSize);
if (!pBits) {
TRACE("Out of memory for DIB bits");
goto $abort;
}
// seek to the bits in the file
fp->Seek(dwFileStart + BmpFileHdr.bfOffBits, CFile::begin);
// read the bits
iBytes = fp->Read(pBits, iBitsSize);
if (iBytes != iBitsSize) {
TRACE("Failed to read bits");
goto $abort;
}
// Everything went OK
if (m_pBMI != NULL) free(m_pBMI);
m_pBMI = pBmpInfo;
if (m_bMyBits && (m_pBits != NULL)) free (m_pBits);
m_pBits = pBits;
m_bMyBits = TRUE;
return TRUE;
$abort: // something went wrong
if (pBmpInfo) free(pBmpInfo);
if (pBits) free (pBits);
return FALSE;
}
// Load a DIB from a disk file. If no file name is given, show
// an open file dialog to get one.
BOOL CDIB::Load(LPSTR pszFileName)
{
CString strFile;
if ((pszFileName == NULL)
|| (strlen(pszFileName) == 0)) {
// Show an open file dialog to get the name
CFileDialog dlg (TRUE, // open
NULL, // no default extension
NULL, // no initial file name
OFN_FILEMUSTEXIST
| OFN_HIDEREADONLY,
"Image files (*.DIB, *.BMP)|*.DIB;*.BMP|All files (*.*)|*.*||");
if (dlg.DoModal() == IDOK) {
strFile = dlg.GetPathName();
} else {
return FALSE;
}
} else {
// copy the supplied file path
strFile = pszFileName;
}
// Try to open the file for read access
CFile file;
if (! file.Open(strFile,
CFile::modeRead | CFile::shareDenyWrite)) {
AfxMessageBox("Failed to open file");
return FALSE;
}
BOOL bResult = Load(&file);
file.Close();
if (!bResult) AfxMessageBox("Failed to load file");
return bResult;
}
// Draw the DIB to a given DC
void CDIB::Draw(CDC *pDC, int x, int y)
{
::StretchDIBits(pDC->GetSafeHdc(),
x, // dest x
y, // dest y
DibWidth(), // dest width
DibHeight(), // dest height
0, // src x
0, // src y
DibWidth(), // src width
DibHeight(), // src height
GetBitsAddress(), // bits
GetBitmapInfoAddress(), // BITMAPINFO
DIB_RGB_COLORS, // options
SRCCOPY); // rop
}
// get the number of color table entries
int CDIB::GetNumClrEntries()
{
return NumDIBColorEntries(m_pBMI);
}
int Power(int s)
{
return s * s;
}
BYTE GetNearest(PALETTEENTRY* pe,int nSize,int R,int G,int B)
{
int nMin = 99999999;
BYTE nIndex = 0;
for (int i=0; i<nSize; i++)
{
int s = Power(R - pe[i].peRed) +
Power(G - pe[i].peGreen) +
Power(B - pe[i].peBlue);
if (s < nMin)
{
nMin = s;
nIndex = (BYTE)i;
}
}
return nIndex;
}
void CDIB::Inverse()
{
HWND hwndActive = ::GetActiveWindow();
HDC hdcScreen = ::GetDC(hwndActive);
ASSERT(hdcScreen);
if (!(GetDeviceCaps(hdcScreen, RASTERCAPS) & RC_PALETTE))
return;
int iSysColors = GetDeviceCaps(hdcScreen, NUMCOLORS);
int nColorMode;
if (iSysColors == 16)
nColorMode = 16;
else
nColorMode = 256;
BYTE *pBits = (BYTE *)GetBitsAddress();
int iSize = StorageWidth() * DibHeight();
while (iSize--)
{
*pBits = (nColorMode - *pBits + 10) % nColorMode;
pBits++;
}
}
// NOTE: This assumes all CDIB objects have 256 color table entries
BOOL CDIB::MapColorsToPalette(CPalette *pPal)
{
if (!pPal) {
TRACE("No palette to map to");
return FALSE;
}
ASSERT(m_pBMI->bmiHeader.biBitCount == 8);
ASSERT(m_pBMI);
ASSERT(m_pBits);
LPRGBQUAD pctThis = GetClrTabAddress();
ASSERT(pctThis);
// build an index translation table to map this DIBs colors
// to those of the reference DIB
BYTE imap[256];
int iChanged = 0; // for debugging only
int i;
for (i = 0; i < 256; i++) {
imap[i] = (BYTE) pPal->GetNearestPaletteIndex(
RGB(pctThis->rgbRed,
pctThis->rgbGreen,
pctThis->rgbBlue));
pctThis++;
if (imap[i] != i) iChanged++; // for debugging
}
// now map the DIB bits
BYTE *pBits = (BYTE *)GetBitsAddress();
int iSize = StorageWidth() * DibHeight();
while (iSize--) {
*pBits = imap[*pBits];
pBits++;
}
// Now reset the DIB color table so that its RGB values match
// those in the palette
PALETTEENTRY pe[256];
pPal->GetPaletteEntries(0, 256, pe);
pctThis = GetClrTabAddress();
for (i = 0; i < 256; i++) {
pctThis->rgbRed = pe[i].peRed;
pctThis->rgbGreen = pe[i].peGreen;
pctThis->rgbBlue = pe[i].peBlue;
pctThis++;
}
return TRUE;
}
// Get a pointer to a pixel
// NOTE: DIB scan lines are DWORD aligned. The scan line
// storage width may be wider than the scan line image width
// so calc the storage width by rounding the image width
// to the next highest dword value
void *CDIB::GetPixelAddress(int x, int y)
{
int iWidth;
// This version only deals with 8 bpp DIBs
ASSERT(m_pBMI->bmiHeader.biBitCount == 8);
// make sure it's in range and if not return zero
if ((x >= DibWidth())
|| (y >= DibHeight())) {
TRACE("Attempt to get out of range pixel addr");
return NULL;
}
// Calculate the scan line storage width
iWidth = StorageWidth();
return m_pBits + (DibHeight()-y-1) * iWidth + x;
}
// get the bounding rectangle
void CDIB::GetRect(CRect* pRect)
{
pRect->top = 0;
pRect->left = 0;
pRect->bottom = DibHeight();
pRect->right = DibWidth();
}
// Copy a rectangle of the DIB to another DIB
// Note we only support 8bpp DIBs here
void CDIB::CopyBits(CDIB* pdibDest,
int xd, int yd,
int w, int h,
int xs, int ys,
COLORREF clrTrans)
{
ASSERT(m_pBMI->bmiHeader.biBitCount == 8);
ASSERT(pdibDest);
// test for strange cases
if (w == 0 || h == 0) return;
// get pointers to the start points in the source
// and destination DIBs. Note that this will be the bottom left
// corner of the DIB as the scan lines are reversed in memory
BYTE* pSrc = (BYTE*)GetPixelAddress(xs, ys + h - 1);
ASSERT(pSrc);
if ( pSrc == NULL )
return;
BYTE* pDest = (BYTE*)pdibDest->GetPixelAddress(xd, yd + h - 1);
ASSERT(pDest);
if ( pDest == NULL )
return;
// get the scan line widths of each DIB
int iScanS = StorageWidth();
int iScanD = pdibDest->StorageWidth();
if (clrTrans == 0xFFFFFFFF) {
// copy the lines
while (h--) {
memcpy(pDest, pSrc, w);
pSrc += iScanS;
pDest += iScanD;
}
} else {
// copy lines with transparency
// We only accept a PALETTEINDEX description
// for the color definition
ASSERT((clrTrans & 0xFF000000) == 0x01000000);
BYTE bTransClr = LOBYTE(LOWORD(clrTrans));
int iSinc = iScanS - w; // source inc value
int iDinc = iScanD - w; // dest inc value
int iCount;
BYTE pixel;
while (h--) {
iCount = w; // no of pixels to scan
while (iCount--) {
pixel = *pSrc++;
// only copy pixel if not transparent
if (pixel != bTransClr) {
*pDest++ = pixel;
} else {
pDest++;
}
}
// move on to the next line
pSrc += iSinc;
pDest += iDinc;
}
}
}
// Save a DIB to a disk file
// This is somewhat simplistic because we only deal with 256 color DIBs
// and we always write a 256 color table
BOOL CDIB::Save(CFile *fp)
{
BITMAPFILEHEADER bfh;
// construct the file header
bfh.bfType = 0x4D42; // 'BM'
bfh.bfSize =
sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER) +
256 * sizeof(RGBQUAD) +
StorageWidth() * DibHeight();
bfh.bfReserved1 = 0;
bfh.bfReserved2 = 0;
bfh.bfOffBits =
sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER) +
256 * sizeof(RGBQUAD);
// write the file header
int iSize = sizeof(bfh);
TRY {
fp->Write(&bfh, iSize);
} CATCH(CFileException, e) {
TRACE("Failed to write file header");
return FALSE;
} END_CATCH
// write the BITMAPINFO
// Note: we assume there are always 256 colors in the
// color table
ASSERT(m_pBMI);
iSize =
sizeof(BITMAPINFOHEADER) +
256 * sizeof(RGBQUAD);
TRY {
fp->Write(m_pBMI, iSize);
} CATCH(CFileException, e) {
TRACE("Failed to write BITMAPINFO");
return FALSE;
} END_CATCH
// write the bits
iSize = StorageWidth() * DibHeight();
TRY {
fp->Write(m_pBits, iSize);
} CATCH(CFileException, e) {
TRACE("Failed to write bits");
return FALSE;
} END_CATCH
return TRUE;
}
// Save a DIB to a disk file. If no file name is given, show
// a save file dialog to get one.
BOOL CDIB::Save(LPSTR pszFileName)
{
CString strFile;
if ((pszFileName == NULL)
|| (strlen(pszFileName) == 0)) {
// Show a save file dialog to get the name
CFileDialog dlg (FALSE, // save
NULL, // no default extension
NULL, // no initial file name
OFN_OVERWRITEPROMPT
| OFN_HIDEREADONLY,
"Image files (*.DIB, *.BMP)|*.DIB;*.BMP|All files (*.*)|*.*||");
if (dlg.DoModal() == IDOK) {
strFile = dlg.GetPathName();
} else {
return FALSE;
}
} else {
// copy the supplied file path
strFile = pszFileName;
}
// Try to open the file for write access
CFile file;
if (! file.Open(strFile,
CFile::modeReadWrite
| CFile::modeCreate
| CFile::shareExclusive)) {
AfxMessageBox("Failed to open file");
return FALSE;
}
BOOL bResult = Save(&file);
file.Close();
if (!bResult) AfxMessageBox("Failed to save file");
return bResult;
}
WORD DibNumColors (VOID FAR * pv)
{
INT bits;
LPBITMAPINFOHEADER lpbi;
LPBITMAPCOREHEADER lpbc;
lpbi = ((LPBITMAPINFOHEADER)pv);
lpbc = ((LPBITMAPCOREHEADER)pv);
/* With the BITMAPINFO format headers, the size of the palette
* is in biClrUsed, whereas in the BITMAPCORE - style headers, it
* is dependent on the bits per pixel ( = 2 raised to the power of
* bits/pixel).
*/
if (lpbi->biSize != sizeof(BITMAPCOREHEADER)){
if (lpbi->biClrUsed != 0)
return (WORD)lpbi->biClrUsed;
bits = lpbi->biBitCount;
}
else
bits = lpbc->bcBitCount;
switch (bits){
case 1:
return 2;
case 4:
return 16;
case 8:
return 256;
default:
/* A 24 bitcount DIB has no color table */
return 0;
}
}
WORD PaletteSize (VOID FAR * pv)
{
LPBITMAPINFOHEADER lpbi;
WORD NumColors;
lpbi = (LPBITMAPINFOHEADER)pv;
NumColors = DibNumColors(lpbi);
if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
return (WORD)(NumColors * sizeof(RGBTRIPLE));
else
return (WORD)(NumColors * sizeof(RGBQUAD));
}
BOOL CDIB::Load(CBitmap* pBmp)
{
CPalette* pPal;
BITMAP bm;
BITMAPINFOHEADER bi;
WORD biBits;
DWORD biStyle;
DWORD dwLen;
CDC dcMem;
BYTE *lpbi;
BYTE *lpBits;
if (! pBmp)
return FALSE;
pPal = CPalette::FromHandle((HPALETTE ) GetStockObject(DEFAULT_PALETTE));
pBmp->GetObject(sizeof(BITMAP),&bm);
biBits = 8;
biStyle = BI_RGB;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bm.bmWidth;
bi.biHeight = bm.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = biBits;
bi.biCompression = biStyle;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
dwLen = bi.biSize + PaletteSize (&bi);
dcMem.CreateCompatibleDC(NULL);
pPal = dcMem.SelectPalette(pPal,FALSE);
dcMem.RealizePalette();
lpbi = (BYTE *) malloc(dwLen);
memcpy(lpbi,&bi,sizeof(BITMAPINFOHEADER));
GetDIBits(dcMem.GetSafeHdc(),
(HBITMAP) pBmp->GetSafeHandle(),
0L,
(DWORD) bi.biHeight,
(LPBYTE) NULL,
(LPBITMAPINFO)lpbi,
(DWORD) DIB_RGB_COLORS);
memcpy(&bi,lpbi,sizeof(BITMAPINFOHEADER));
if (bi.biSizeImage == 0)
{
bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * biBits) * bm.bmHeight;
if (biStyle != BI_RGB)
bi.biSizeImage = (bi.biSizeImage * 3) / 2;
}
lpBits = (BYTE *) malloc(bi.biSizeImage);
GetDIBits(dcMem.GetSafeHdc(),
(HBITMAP) pBmp->GetSafeHandle(),
0L,
(DWORD) bi.biHeight,
lpBits,
(LPBITMAPINFO)lpbi,
(DWORD) DIB_RGB_COLORS);
dcMem.DeleteDC();
// because default constructor has created 16x16 bitmap by default
// so we need to release first, otherwise it will cause memory leack !
if (m_pBMI)
delete m_pBMI;
if (m_pBits)
delete m_pBits;
m_pBMI = (LPBITMAPINFO) lpbi;
m_pBits = lpBits;
m_bMyBits = TRUE;
return TRUE;
}