www.pudn.com > gis_graphic_item_lib.rar > BmpProc.cpp


#include "stdafx.h" 
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
 
#include "BmpProc.h" 
 
 
////////////////////////////// defines /////////////////////////////////// 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
#ifdef _DEBUG 
	DWORD CBmpProc::m_ObjectCount = 0; 
#endif 
 
/************************************************************************* 
 * 构造函数。初始化类为空。 
*************************************************************************/ 
 
 
CBmpProc::CBmpProc() 
{ 
	// 初始化核心数据为空 
	m_mark = FALSE;			// 有效标志。(TRUE-有有效位图,否则为FALSE) 
	m_type = IT_NULL;		// 图像类型。 
	m_addInfo = 0;			// 附加信息。 
	m_cFileName.Empty();	// 文件路径。 
	m_pInfo = NULL;			// DIB信息结构 
	m_hObject = NULL;		// 清除核心DDB位图句柄。(基类成员) 
 
#ifdef _DEBUG 
	CBmpProc::m_ObjectCount++; 
#endif 
} 
 
CBmpProc::~CBmpProc() 
{ 
	Clear(); 
 
#ifdef _DEBUG 
	CBmpProc::m_ObjectCount--; 
#endif 
} 
 
CBmpProc& CBmpProc::operator=(const CBmpProc& ds) 
{ 
	// 如果类中没有图像,直接返回 
	if (!ds.IsValid()) 
		return *this; 
 
	ASSERT(ds.m_pInfo); 
	ASSERT(ds.m_pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)); 
 
	// 复制源图信息块 
	LPBITMAPINFO pInfo = (LPBITMAPINFO)CreateMemoryBlockFromAddress( 
		(LPVOID)ds.m_pInfo); 
	if (!pInfo) 
		return *this; 
 
	// 复制源图 
	CBitmap		tempBmp; 
	HBITMAP		hBmp; 
 
	HWND hWnd = ::GetDesktopWindow(); 
	ASSERT(hWnd); 
	HDC hDC = ::GetDC(hWnd); 
	CDC dc; 
	dc.Attach(hDC); 
 
	if (tempBmp.CreateCompatibleBitmap(&dc, ds.Width(), ds.Height())) 
	{ 
		CDC			compDC, compDC2; 
		CBitmap		*pOldBmp, *pOldBmp2; 
 
		// 创建与当前显示设备兼容的内存设备描述表 
		compDC.CreateCompatibleDC(NULL); 
		compDC2.CreateCompatibleDC(NULL); 
 
		pOldBmp	= compDC.SelectObject((CBitmap*)&tempBmp); 
		pOldBmp2= compDC2.SelectObject((CBitmap*)&ds); 
 
		// 复制指定尺寸的源位图到目标位图 
		compDC.BitBlt(0, 0, ds.Width(), ds.Height(),  
					&compDC2, 0, 0, SRCCOPY); 
 
		compDC2.SelectObject(pOldBmp2); 
		compDC.SelectObject(pOldBmp); 
 
		hBmp = (HBITMAP)tempBmp.Detach(); 
		// 如果分离操作失败,返回FALSE 
		ASSERT(hBmp); 
		if (!hBmp) 
		{ 
			::ReleaseDC(hWnd, dc.Detach()); 
			::free((void*)pInfo); 
			return *this;; 
		} 
		::ReleaseDC(hWnd, dc.Detach()); 
 
		// 删除原来的图像,并且设置新的位图 
		if (!ClearAndSetData(IT_MEMORY,0,(LPCTSTR)"",pInfo,hBmp)) 
		{ 
			::free((void*)pInfo); 
			::DeleteObject(hBmp); 
			return *this; 
		} 
		return *this; 
	} 
	else 
	{ 
		::ReleaseDC(hWnd, dc.Detach()); 
		::free((void*)pInfo); 
 
		return *this;; 
	} 
} 
 
 
BOOL CBmpProc::Draw(CDC& dc, const CRect* rcDst, const CRect* rcSrc) 
{ 
	// 如果类中没有图像,直接返回 
	if (!IsValid()) 
		return TRUE; 
 
	ASSERT(m_hObject); 
 
	// 缺省矩形等于图像尺寸 
	CRect DCRect(Rect());			// 目标位置数据 
	CRect DibRect(Rect());			// 源位置数据 
 
	if (rcDst) 
		DCRect = *rcDst; 
	if (rcSrc) 
		DibRect = *rcSrc; 
 
	// 如果待绘制的图像不在当前剪贴区域内,则直接返回 
	if (!dc.RectVisible(&DCRect)) 
		return TRUE; 
 
	CDC			compDC; 
	CBitmap		*pOldBmp; 
 
	compDC.CreateCompatibleDC(NULL); 
	pOldBmp	= compDC.SelectObject((CBitmap*)this); 
 
	/* 设置目标DC的拉伸模式为STRETCH_DELETESCANS,也就是不显示拉伸掉的图像 */ 
	int srlold = dc.SetStretchBltMode(STRETCH_DELETESCANS); 
 
	// 显示位图 
	dc.StretchBlt(DCRect.left, DCRect.top, DCRect.Width(), DCRect.Height(),  
					&compDC, DibRect.left, DibRect.top,  
					DibRect.Width(), DibRect.Height(), SRCCOPY); 
	 
	// 恢复设备描述表原来的设置 
	dc.SetStretchBltMode(srlold); 
	compDC.SelectObject(pOldBmp); 
 
	return TRUE; 
} 
 
void CBmpProc::Clear() 
{ 
	// 如果本类中没有有效的BMP,则直接返回 
	if (m_mark == FALSE) 
	{ 
		ASSERT(m_type == IT_NULL); 
		ASSERT(m_pInfo == NULL); 
		ASSERT(m_hObject == NULL); 
		return; 
	} 
 
	switch(m_type) 
	{ 
	case	IT_NULL: 
		ASSERT(FALSE);	// 此时m_type不应该是IT_NULL 
		break; 
	case	IT_DISKFILE: 
		ASSERT(!m_cFileName.IsEmpty());	// 文件来源的位图应该有文件名 
	case	IT_RESOURCE: 
	case	IT_MEMORY: 
	case	IT_CLIP: 
	case	IT_CREATE: 
		m_cFileName.Empty(); 
 
		ASSERT(m_pInfo); 
		::free((void*)m_pInfo); 
		m_pInfo = NULL; 
 
		// 先分离出原来的BMP句柄,然后删除 
		ASSERT((HBITMAP)m_hObject); 
		::DeleteObject(CGdiObject::Detach()); 
		m_hObject = NULL; 
 
		m_addInfo = 0; 
		m_type = IT_NULL; 
		m_mark = FALSE; 
		break; 
	default: 
		ASSERT(FALSE); 
		break; 
	} 
} 
 
BOOL CBmpProc::Attach(HBITMAP hBmp) 
{ 
	ASSERT(hBmp); 
	// 如果hBmp是NULL,则立即返回 
	if (!hBmp) 
		return FALSE; 
 
	HWND hWnd = ::GetDesktopWindow(); 
	ASSERT(hWnd); 
	HDC hDC; 
	BITMAP	bmp; 
 
	// 获取给定位图的宽度、高度及颜色格式信息 
	if (::GetObject(hBmp, sizeof(BITMAP), (LPVOID)&bmp) != sizeof(BITMAP)) 
		return FALSE; 
 
	// 创建临时位图信息块(不带颜色表) 
	LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)CreateMemoryBlockFromAddress( 
		(LPVOID)NULL, sizeof(BITMAPINFOHEADER)); 
	if (!lpbi) 
		return FALSE; 
 
	// 设置DIB信息块内容 
	lpbi->biSize = sizeof(BITMAPINFOHEADER); 
	lpbi->biWidth = bmp.bmWidth; 
	lpbi->biHeight = bmp.bmHeight; 
	lpbi->biPlanes = 1; 
	// 在16色系统中,平面数是4,而位数是1,但这在DIB中是不允许的 
	lpbi->biBitCount = max(bmp.bmPlanes, bmp.bmBitsPixel); 
	if ((lpbi->biBitCount==16)||(lpbi->biBitCount==32)) 
		lpbi->biCompression = BI_BITFIELDS; 
	else 
		lpbi->biCompression = BI_RGB; 
 
	// 计算设备分辩率 
	hDC = ::GetDC(hWnd); 
	lpbi->biXPelsPerMeter = \ 
		(GetDeviceCaps(hDC,HORZRES)*1000)/GetDeviceCaps(hDC,HORZSIZE); 
	lpbi->biYPelsPerMeter = \ 
		(GetDeviceCaps(hDC,VERTRES)*1000)/GetDeviceCaps(hDC,VERTSIZE); 
	::ReleaseDC(hWnd, hDC); 
 
	lpbi->biClrUsed = 0; 
	lpbi->biClrImportant = 0; 
	lpbi->biSizeImage = CalculateDIBitsSize(lpbi); 
 
	// 计算颜色表的尺寸 
	WORD wPalSize = PaletteSize(lpbi); 
 
	// 创建带颜色表的信息块,并复制lpbi信息块中的内容 
	LPBITMAPINFO pInfo = (LPBITMAPINFO)CreateMemoryBlockFromAddress( 
		(LPVOID)lpbi, sizeof(BITMAPINFOHEADER)+wPalSize); 
	if (!pInfo) 
	{ 
		::free((void*)lpbi); 
		return FALSE; 
	} 
 
	ASSERT(pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)); 
 
	// 此时该结构已经无用,释放 
	::free((void*)lpbi); 
 
	// 创建存放DIB位数据的缓冲区 
	LPSTR pBits = (LPSTR)CreateMemoryBlockFromAddress((LPVOID)NULL,  
		pInfo->bmiHeader.biSizeImage); 
	if (!pBits) 
	{ 
		::free((void*)pInfo); 
		return FALSE; 
	} 
 
	// 下面的代码并不是要获取位图的DIB位数据,而是要取得位图的颜色表 
	// 颜色表数据在函数(GetDIBits())调用成功后被填写在pInfo结构中 
	hDC = ::GetDC(hWnd); 
	if (!::GetDIBits(hDC,hBmp,0,pInfo->bmiHeader.biHeight, \ 
			(LPVOID)pBits,pInfo,DIB_RGB_COLORS)) 
	{ 
		::free((void*)pBits); 
		::free((void*)pInfo); 
		::ReleaseDC(hWnd, hDC); 
		return FALSE; 
	} 
	::ReleaseDC(hWnd, hDC); 
 
	// 此时并不需要DIB位数据,释放 
	::free((void*)pBits); 
 
	// 删除原来的图像,并且设置新的位图 
	if (!ClearAndSetData(IT_MEMORY,0,(LPCTSTR)"",pInfo,hBmp)) 
	{ 
		::free((void*)pInfo); 
		// hBmp指定的位图并不删除 
		return FALSE; 
	} 
 
	return TRUE; 
} 
 
HBITMAP CBmpProc::Detach() 
{ 
	if (!IsValid()) 
		return NULL; 
 
	ASSERT(m_pInfo); 
	ASSERT(m_hObject); 
 
	HBITMAP hBmp = (HBITMAP)CGdiObject::Detach(); 
	ASSERT(hBmp); 
	if (!hBmp) 
		return NULL; 
 
	m_hObject = NULL; 
 
	switch(m_type) 
	{ 
	case	IT_NULL: 
		ASSERT(FALSE);	// 此时m_type不应该是IT_NULL 
		break; 
	case	IT_DISKFILE: 
		ASSERT(!m_cFileName.IsEmpty());	// 文件来源的位图应该有文件名 
	case	IT_RESOURCE: 
	case	IT_MEMORY: 
	case	IT_CLIP: 
	case	IT_CREATE: 
		m_cFileName.Empty(); 
 
		ASSERT(m_pInfo); 
		::free((void*)m_pInfo); 
		m_pInfo = NULL; 
 
		m_addInfo = 0; 
		m_type = IT_NULL; 
		m_mark = FALSE; 
		break; 
	default: 
		ASSERT(FALSE); 
		break; 
	} 
 
	return hBmp; 
} 
 
BOOL CBmpProc::CopyTran(CBmpProc& souBmp,  
						COLORREF crColour,  
						CRect *pDesRect,  
						CRect *pSouRect,  
						int mode) 
{ 
	if (!IsValid()) 
		return FALSE; 
 
	ASSERT(m_pInfo); 
	ASSERT(m_pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)); 
 
	if (!souBmp.IsValid()) 
		return FALSE; 
 
	ASSERT(souBmp.m_pInfo); 
	ASSERT(souBmp.m_pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)); 
 
 
	// 如果未指定矩形数据,则使用源图的矩形数据 
	CRect dr; 
	CRect sr; 
 
	if (pDesRect == NULL) 
		dr = souBmp.Rect(); 
	else 
		dr = *pDesRect; 
 
	if (pSouRect == NULL) 
		sr = souBmp.Rect(); 
	else 
		sr = *pSouRect; 
 
	// 复制源图 
	CDC			compDC; 
	CBitmap		*pOldBmp; 
 
	// 创建与当前显示设备兼容的内存设备描述表 
	compDC.CreateCompatibleDC(NULL); 
	pOldBmp	= compDC.SelectObject((CBitmap*)this); 
 
	// 复制指定尺寸的源位图到目标位图 
	souBmp.DrawTransparentInRect(compDC, crColour, pDesRect, pSouRect, mode); 
 
	compDC.SelectObject(pOldBmp); 
 
	return TRUE; 
} 
 
BOOL CBmpProc::LoadFromResourceID(UINT uID, HINSTANCE hInst)  
{  
	return LoadFromResourceName((LPCTSTR)MAKEINTRESOURCE(uID), hInst);  
} 
 
DWORD CBmpProc::CalculateDIBitsSize(LPBITMAPINFOHEADER lpbi) const 
{ 
	ASSERT(lpbi); 
	ASSERT(lpbi->biSize == sizeof(BITMAPINFOHEADER)); 
 
	DWORD s = DIBSCANLINE_WIDTHBYTES(DIBWidth(lpbi)*GetBitsPerPixel(lpbi)); 
 
	return s*DIBHeight(lpbi); 
} 
 
LPSTR CBmpProc::FindDIBBits(LPSTR lpbi) const 
{ 
	ASSERT(lpbi); 
	ASSERT(((LPBITMAPINFOHEADER)lpbi)->biSize == sizeof(BITMAPINFOHEADER)); 
	return (lpbi + *(LPDWORD)lpbi + PaletteSize((LPBITMAPINFOHEADER)lpbi)); 
} 
 
DWORD CBmpProc::DIBWidth(LPBITMAPINFOHEADER lpbi) const 
{ 
	ASSERT(lpbi); 
	ASSERT(lpbi->biSize == sizeof(BITMAPINFOHEADER)); 
	return 	lpbi->biWidth; 
} 
 
DWORD CBmpProc::DIBHeight(LPBITMAPINFOHEADER lpbi) const 
{ 
	ASSERT(lpbi); 
	ASSERT(lpbi->biSize == sizeof(BITMAPINFOHEADER)); 
	return 	lpbi->biHeight; 
} 
 
WORD CBmpProc::PaletteSize(LPBITMAPINFOHEADER lpbi) const 
{ 
	WORD size, wBitCount; 
 
	ASSERT(lpbi); 
	ASSERT(lpbi->biSize == sizeof(BITMAPINFOHEADER)); 
	// 获得每个像素所占的位数 
	wBitCount = GetBitsPerPixel(lpbi); 
				 
	// 16位和32位位图在颜色表中占用三个DWORD数值来表示 
	// 红、绿、蓝在位数据中的掩码 
	if ((wBitCount == 16)||(wBitCount == 32)) 
	{ 
		ASSERT(lpbi->biCompression == BI_BITFIELDS); 
		size = sizeof(DWORD)*3; 
	} 
	else 
	{ 
		// 不支持压缩位图 
		ASSERT(lpbi->biCompression == BI_RGB); 
		size = (WORD)(DIBNumColors(lpbi) * sizeof(RGBQUAD)); 
	} 
 
	return size; 
} 
 
WORD CBmpProc::DIBNumColors(LPBITMAPINFOHEADER lpbi) const 
{ 
	ASSERT(lpbi); 
	ASSERT(lpbi->biSize == sizeof(BITMAPINFOHEADER)); 
	WORD wBitCount = GetBitsPerPixel(lpbi);  // DIB位计数 
 
	// 如果位图指定了颜色表中颜色的个数,则直接使用这个值 
	if (lpbi->biClrUsed) 
		return (WORD)(lpbi->biClrUsed); 
 
	/*  通过DIB中每个像素所占的位数来计算它的颜色表中颜色的个数 */ 
	switch (wBitCount) 
	{ 
		case 1: 
			return 2;		// 单色位图,只有黑白两种颜色 
		case 4: 
			return 16;		// 标准VGA位图,有16种颜色 
		case 8: 
			return 256;		// SVGA位图,有256种颜色 
		case	16:			// 64K色位图 
		case	24:			// 16M色位图(真彩色) 
		case	32:			// 16M+色位图(真彩色) 
			return 0;		// 颜色表中没有颜色数据返回0 
		default: 
			ASSERT(FALSE); 
			return 0; 
	} 
} 
 
LPVOID CBmpProc::CreateMemoryBlockFromAddress(LPVOID pSou, DWORD dwCount) 
{ 
	// 入口参数pSou和dwCount不能同时为0 
	if ((pSou==NULL)&&(dwCount==0)) 
		return NULL; 
 
	LPSTR lpt; 
 
	// 只创建,不复制 
	if (pSou == NULL) 
	{ 
		ASSERT(dwCount); 
		lpt = (LPSTR)::malloc((size_t)dwCount); 
		if (!lpt) 
			return NULL; 
 
		::memset((void *)lpt, 0, dwCount); 
 
		return lpt; 
	} 
 
	DWORD dwCopyNum, dwAllocNum; 
 
	if (dwCount == 0) 
	{ 
		dwCopyNum = (DWORD)::_msize((void*)pSou); 
		dwAllocNum = dwCopyNum; 
	} 
	else 
	{ 
		// 如果pSou内存块的尺寸小于dwCount指定的值,则将pSou中的内容 
		// 全部复制到新的内存块中,否则只复制dwCount长度的内容 
		dwCopyNum = min((DWORD)::_msize((void*)pSou), dwCount); 
		dwAllocNum = dwCount; 
	} 
 
	lpt = (LPSTR)::malloc((size_t)dwAllocNum); 
 
	if (!lpt) 
		return NULL; 
 
	// 初始化新内存块 
	::memset((void *)lpt, 0, dwAllocNum); 
 
	// 复制源内存中的内容到新的内存中 
	::memcpy((void*)lpt, (const void*)pSou, (size_t)dwCopyNum); 
 
	return (LPVOID)lpt; 
} 
 
int	CBmpProc::GetBitsPerPixel(LPBITMAPINFOHEADER lpbi) const 
{ 
	ASSERT(lpbi); 
	ASSERT(lpbi->biSize == sizeof(BITMAPINFOHEADER)); 
	return lpbi->biBitCount;  // DIB位计数 
} 
 
CSize CBmpProc::Size() const 
{  
	if (m_mark == FALSE) 
		return CSize(0,0); 
 
	ASSERT(m_pInfo); 
	ASSERT(DIBWidth((LPBITMAPINFOHEADER)m_pInfo));	// 宽度和高度不能为0 
	ASSERT(DIBHeight((LPBITMAPINFOHEADER)m_pInfo)); 
 
	return CSize(DIBWidth((LPBITMAPINFOHEADER)m_pInfo), DIBHeight((LPBITMAPINFOHEADER)m_pInfo)); 
} 
 
CRect CBmpProc::Rect() const 
{  
	if (m_mark == FALSE) 
		return CRect(0,0,0,0); 
 
	ASSERT(m_pInfo); 
 
	return CRect(CPoint(0, 0), Size());  
} 
 
int CBmpProc::Width() const 
{ 
	if (m_mark == FALSE) 
		return 0; 
 
	ASSERT(m_pInfo); 
 
	return (int)DIBWidth((LPBITMAPINFOHEADER)m_pInfo); 
} 
 
int CBmpProc::Height() const 
{  
	if (m_mark == FALSE) 
		return 0; 
 
	ASSERT(m_pInfo); 
 
	return (int)DIBHeight((LPBITMAPINFOHEADER)m_pInfo); 
} 
 
BOOL  CBmpProc::IsValid() const 
{  
	return m_mark; 
} 
 
int CBmpProc::GetObject(LPBITMAP lpBitmap) const 
{  
	if (m_mark == FALSE) 
		return 0; 
 
	ASSERT(m_hObject); 
	ASSERT(lpBitmap); 
 
	return CGdiObject::GetObject(sizeof(BITMAP), (LPVOID)lpBitmap);  
} 
 
BOOL CBmpProc::ClearAndSetData(int type,  
							   DWORD addinfo,  
							   LPCTSTR lpFn,  
							   LPBITMAPINFO pInfo,  
							   HBITMAP hBmp) 
{ 
	ASSERT(pInfo); 
	ASSERT(hBmp); 
 
	// 如果原来存在位图 
	if (m_mark == TRUE) 
	{ 
		// 分离出原来的位图句柄 
		ASSERT((HBITMAP)m_hObject); 
		HBITMAP hOldBmp = (HBITMAP)CGdiObject::Detach(); 
		ASSERT(hOldBmp); 
		if (!CGdiObject::Attach((HGDIOBJ)hBmp)) 
		{ 
			// 如果失败,恢复原来的位图句柄。 
			CGdiObject::Attach((HGDIOBJ)hOldBmp); 
			return FALSE; 
		} 
		// 如果成功,原来的位图句柄将无用,释放 
		::DeleteObject((HGDIOBJ)hOldBmp); 
 
		m_type = type,			// 位图来源 
		m_addInfo = addinfo;	// 附加信息 
		m_cFileName.Empty(); 
		m_cFileName = lpFn;		// 文件路径。 
		ASSERT(m_pInfo); 
		::free((void*)m_pInfo); 
		m_pInfo = pInfo;		// DIB信息结构 
 
		return TRUE; 
	} 
	else	// 原来没有位图 
	{ 
		ASSERT(m_pInfo == NULL); 
		ASSERT(m_hObject == NULL); 
 
		if (!CGdiObject::Attach((HGDIOBJ)hBmp)) 
			return FALSE; 
 
		m_mark = TRUE;			// 有效标志置 
		m_type = type,			// 位图来源 
		m_addInfo = addinfo;	// 附加信息 
		m_cFileName = lpFn;		// 文件路径。 
		m_pInfo = pInfo;		// DIB信息结构 
 
		return TRUE; 
	} 
} 
 
BOOL CBmpProc::Fill(COLORREF crColour, CRect *crArea) 
{ 
	// 本身类中必须存在位图 
	if (!IsValid()) 
		return FALSE; 
 
	ASSERT(m_pInfo); 
	ASSERT(m_pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)); 
 
	CRect	rect(Rect()); 
 
	if (crArea) 
		rect = *crArea; 
 
	// 复制源图 
	CDC			compDC; 
	CBitmap		*pOldBmp; 
 
	// 创建与当前显示设备兼容的内存设备描述表 
	compDC.CreateCompatibleDC(NULL); 
	pOldBmp	= compDC.SelectObject((CBitmap*)this); 
 
	// 填充指定颜色 
	compDC.FillSolidRect((LPCRECT)&rect, crColour); 
 
	compDC.SelectObject(pOldBmp); 
 
	return TRUE; 
} 
 
BOOL CBmpProc::ReSetColor(COLORREF oldcolr, COLORREF newcolr, CRect *crArea) 
{ 
	// 本身类中必须存在位图 
	if (!IsValid()) 
		return FALSE; 
 
	ASSERT(m_pInfo); 
	ASSERT(m_pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)); 
 
	// 复制本身类中的位图作为副本 
	CBmpProc tmp; 
	 
	tmp = *this; 
 
	if (!tmp.IsValid()) 
		return FALSE; 
 
	// 填充指定矩形为新的颜色 
	Fill(newcolr, crArea); 
	// 复制去掉旧颜色的图像 
	CopyTran(tmp, oldcolr, crArea, crArea, 0); 
 
	return TRUE; 
} 
 
BOOL CBmpProc::LoadFromResourceName(LPCTSTR lpResourceName, HINSTANCE hInstance) 
{ 
	HINSTANCE	hInst = hInstance; 
	HBITMAP hBmp = NULL; 
 
	//如果入口参数hInstance是NULL,则函数将用当前应用程序进程的实例句柄 
	if (hInst == NULL) 
		hInst = ::AfxGetResourceHandle(); 
 
	ASSERT(hInst); 
 
	HRSRC hSrc = ::FindResource(hInst, lpResourceName, RT_BITMAP); 
	BOOL bSuccess = FALSE; 
 
	if (!hSrc) 
		return bSuccess; 
 
	// 由LoadResource()函数读入的资源目标不需要显示的删除它,Windows 
	// 系统会自动删除。LockResource()锁定的资源目标也不需要显示的解锁 
	HGLOBAL hResData = LoadResource(hInst, hSrc); 
	if (hResData) 
	{ 
		LPVOID lpResData = LockResource(hResData); 
		if (lpResData) 
		{ 
			// 如果是有效的DIB资源,则资源的首位应该是BITMAPINFOHEADER 
			// 结构 
			ASSERT(*((DWORD*)lpResData) == sizeof(BITMAPINFOHEADER)); 
 
			LPSTR pBits = FindDIBBits((LPSTR)lpResData); 
			ASSERT(pBits > (LPSTR)lpResData); 
 
			HWND hWnd = ::GetDesktopWindow(); 
			ASSERT(hWnd); 
			HDC hDC = ::GetDC(hWnd); 
 
			hBmp = CreateDIBitmap(hDC,			// 创建DDB位图。(将DIB位数据 
				(BITMAPINFOHEADER *)lpResData,	// 转换为DDB位数据) 
				CBM_INIT, pBits,  
				(BITMAPINFO *)lpResData,  
				DIB_RGB_COLORS); 
 
			::ReleaseDC(hWnd, hDC); 
 
			if (hBmp)	// 成功 
			{ 
				DWORD dwInfoSize = (DWORD)((LPSTR)pBits-(LPSTR)lpResData); 
				ASSERT(dwInfoSize > (DWORD)(sizeof(BITMAPFILEHEADER))); 
 
				LPBITMAPINFO lpbi = (LPBITMAPINFO)CreateMemoryBlockFromAddress( 
					(LPVOID)NULL, dwInfoSize); 
				if (lpbi) 
				{ 
					// 复制位图信息块,因为lpResData所指的内存不是运行时态库 
					// 函数分配的内存块,所以未用CreateMemoryBlockFromAddress() 
					// 的复制功能 
					::memcpy((void*)lpbi, (const void*)lpResData, dwInfoSize); 
				} 
				else 
				{ 
					::DeleteObject(hBmp); 
					return FALSE; 
				} 
 
				if ((((DWORD)lpResourceName)>>16) == 0) 
				{// 如果指定资源时使用的是标识,则串指针的高16位是0 
					// 删除原来的图像,并且设置新的位图 
					if (!ClearAndSetData(IT_RESOURCE,(DWORD)lpResourceName,(LPCTSTR)"",lpbi,hBmp)) 
					{ 
						::free((void*)lpbi); 
						::DeleteObject(hBmp); 
						return FALSE; 
					} 
				} 
				else 
				{ 
					// 删除原来的图像,并且设置新的位图 
					if (!ClearAndSetData(IT_RESOURCE,0, lpResourceName,lpbi,hBmp)) 
					{ 
						::free((void*)lpbi); 
						::DeleteObject(hBmp); 
						return FALSE; 
					} 
				} 
				bSuccess = TRUE; 
			} 
		} 
	} 
 
	return bSuccess; 
} 
 
BOOL CBmpProc::CopyFromHbmp(HBITMAP souBmp, CRect *pDesRect, CRect *pSouRect) 
{ 
	// 检查入口参数 
	if (!souBmp) 
		return FALSE; 
 
	// 检查本类中是否有图像 
	if (!IsValid()) 
		return FALSE; 
 
	ASSERT(m_pInfo); 
	ASSERT(m_pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)); 
 
	CBmpProc tmp; 
 
	// 将句柄贴入临时类中 
	if (!tmp.Attach(souBmp)) 
		return FALSE; 
 
	BOOL ret = CopyFromObject(tmp, pDesRect, pSouRect); 
 
	tmp.Detach(); 
 
	return ret; 
} 
 
BOOL CBmpProc::CopyFromObject(CBmpProc &souBmp, CRect *pDesRect, CRect *pSouRect) 
{ 
	if (!IsValid()) 
		return FALSE; 
 
	ASSERT(m_pInfo); 
	ASSERT(m_pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)); 
 
	if (!souBmp.IsValid()) 
		return FALSE; 
 
	ASSERT(souBmp.m_pInfo); 
	ASSERT(souBmp.m_pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)); 
 
 
	// 如果未指定矩形数据,则使用源图的矩形数据 
	CRect dr; 
	CRect sr; 
 
	if (pDesRect == NULL) 
		dr = souBmp.Rect(); 
	else 
		dr = *pDesRect; 
 
	if (pSouRect == NULL) 
		sr = souBmp.Rect(); 
	else 
		sr = *pSouRect; 
 
 
	// 复制源图 
	CDC			compDC, compDC2; 
	CBitmap		*pOldBmp, *pOldBmp2; 
 
	// 创建与当前显示设备兼容的内存设备描述表 
	compDC.CreateCompatibleDC(NULL); 
	compDC2.CreateCompatibleDC(NULL); 
 
	pOldBmp	= compDC.SelectObject((CBitmap*)this); 
	pOldBmp2= compDC2.SelectObject((CBitmap*)&souBmp); 
 
	// 设置目标DC的拉伸模式为COLORONCOLOR,也就是不显示拉伸掉的图像 
	compDC.SetStretchBltMode(COLORONCOLOR); 
 
	// 复制指定尺寸的源位图到目标位图 
	compDC.StretchBlt(dr.left, dr.top, dr.Width(), dr.Height(),  
			&compDC2, sr.left, sr.top, sr.Width(), sr.Height(), SRCCOPY); 
 
	compDC2.SelectObject(pOldBmp2); 
	compDC.SelectObject(pOldBmp); 
 
	return TRUE; 
} 
 
BOOL CBmpProc::DrawTransparentInRect(CDC& dc,  
							   COLORREF crColour,  
							   CRect* crDest,  
							   CRect* crSou,  
							   int mode) 
{ 
	// 如果类中没有图像,直接返回  
	if (!IsValid()) 
		return TRUE; 
 
	ASSERT(m_hObject); 
 
	// 缺省矩形等于图像尺寸 
	CRect DCRect(Rect());			// 目标位置 
	CRect SORect(Rect());			// 源位置 
 
	if (crDest) 
		DCRect = *crDest; 
	if (crSou) 
		SORect = *crSou; 
 
	// 如果待绘制的图像不在当前剪贴区域内,则直接返回 
	if (!dc.RectVisible(&DCRect)) 
		return TRUE; 
 
	COLORREF crOldBack; 
	COLORREF crOldText; 
 
	if (mode==0) 
	{	// 去除指定的颜色 
		crOldBack = dc.SetBkColor(RGB(255,255,255)); 
		crOldText = dc.SetTextColor(RGB(0,0,0)); 
	} 
	else 
	{	// 保留指定的颜色 
		crOldBack = dc.SetBkColor(RGB(0,0,0)); 
		crOldText = dc.SetTextColor(RGB(255,255,255)); 
	} 
 
	CDC dcImage, dcTrans; 
 
	// 创建内存设备描述表 
	dcImage.CreateCompatibleDC(&dc); 
	dcTrans.CreateCompatibleDC(&dc); 
 
	// 选择原始图像到DC中 
	CBitmap* pOldBitmapImage = dcImage.SelectObject(this); 
 
	// 创建掩码位图 
	CBitmap bitmapTrans; 
	int nWidth = SORect.Width(); 
	int nHeight = SORect.Height(); 
	bitmapTrans.CreateBitmap(nWidth, nHeight, 1, 1, NULL); 
 
	// 选择掩码位图到DC中 
	CBitmap* pOldBitmapTrans = dcTrans.SelectObject(&bitmapTrans); 
 
	// 创建掩码图像(基于指定的颜色) 
	dcImage.SetBkColor(crColour); 
	dcTrans.BitBlt(0, 0, nWidth, nHeight, &dcImage, SORect.left, SORect.top, SRCCOPY); 
 
	// 显示透明位图 
 
	/* 设置目标DC的拉伸模式为STRETCH_DELETESCANS,也就是不显示拉伸掉的图像 */ 
	int srlold = dc.SetStretchBltMode(STRETCH_DELETESCANS); 
 
	// 显示位图 
	dc.StretchBlt(DCRect.left,DCRect.top,DCRect.Width(),DCRect.Height(), 
		&dcImage,SORect.left,SORect.top,SORect.Width(),SORect.Height(),SRCINVERT); 
	dc.StretchBlt(DCRect.left,DCRect.top,DCRect.Width(),DCRect.Height(), 
		&dcTrans,SORect.left,SORect.top,SORect.Width(),SORect.Height(),SRCAND); 
	dc.StretchBlt(DCRect.left,DCRect.top,DCRect.Width(),DCRect.Height(), 
		&dcImage,SORect.left,SORect.top,SORect.Width(),SORect.Height(),SRCINVERT); 
 
	// 恢复设备描述表原来的设置 
	dc.SetStretchBltMode(srlold); 
 
	// 恢复设置 
	dcImage.SelectObject(pOldBitmapImage); 
	dcTrans.SelectObject(pOldBitmapTrans); 
	dc.SetBkColor(crOldBack); 
	dc.SetTextColor(crOldText); 
 
	return TRUE; 
} 
 
BOOL CBmpProc::Create(int width,  
					  int height,  
					  WORD nBitCount,  
					  const void *lpBits) 
{ 
	// 检测宽度和高度值 
	if ((width==0)||(height==0)) 
		return FALSE; 
 
	CBitmap		cBmp; 
	HBITMAP		hBmp; 
	int			iCurDevBitPix, iCurDevPlanes; 
 
	// 获取当前系统显示器的颜色格式(位数和平面数) 
	HWND hWnd = ::GetDesktopWindow(); 
	ASSERT(hWnd); 
	HDC hDC = ::GetDC(hWnd); 
	iCurDevBitPix = GetDeviceCaps(hDC,BITSPIXEL); 
	iCurDevPlanes = GetDeviceCaps(hDC,PLANES); 
	::ReleaseDC(hWnd, hDC); 
 
	// 创建指定尺寸并兼容当前显示器颜色格式的位图(DDB) 
	if (!cBmp.CreateBitmap(width, height, iCurDevPlanes, iCurDevBitPix, lpBits)) 
		return FALSE; 
 
	hBmp = (HBITMAP)cBmp.Detach(); 
	ASSERT(hBmp); 
	if (!hBmp) 
		return FALSE; 
 
	// 创建临时位图信息块(不带颜色表) 
	LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)CreateMemoryBlockFromAddress( 
		(LPVOID)NULL, sizeof(BITMAPINFOHEADER)); 
	if (!lpbi) 
	{ 
		::DeleteObject(hBmp); 
		return FALSE; 
	} 
 
	// 设置DIB信息块内容 
	lpbi->biSize = sizeof(BITMAPINFOHEADER); 
	lpbi->biWidth = width; 
	lpbi->biHeight = height; 
	lpbi->biPlanes = 1; 
	lpbi->biBitCount = nBitCount; 
	if ((nBitCount==16)||(nBitCount==32)) 
		lpbi->biCompression = BI_BITFIELDS; 
	else 
		lpbi->biCompression = BI_RGB; 
 
	// 计算设备分辩率 
	hDC = ::GetDC(hWnd); 
	lpbi->biXPelsPerMeter = \ 
		(GetDeviceCaps(hDC,HORZRES)*1000)/GetDeviceCaps(hDC,HORZSIZE); 
	lpbi->biYPelsPerMeter = \ 
		(GetDeviceCaps(hDC,VERTRES)*1000)/GetDeviceCaps(hDC,VERTSIZE); 
	::ReleaseDC(hWnd, hDC); 
 
	lpbi->biClrUsed = 0; 
	lpbi->biClrImportant = 0; 
	lpbi->biSizeImage = CalculateDIBitsSize(lpbi); 
 
	// 计算颜色表的尺寸 
	WORD wPalSize = PaletteSize(lpbi); 
 
	// 创建带颜色表的信息块,并复制lpbi信息块中的内容 
	LPBITMAPINFO pInfo = (LPBITMAPINFO)CreateMemoryBlockFromAddress( 
		(LPVOID)lpbi, sizeof(BITMAPINFOHEADER)+wPalSize); 
	if (!pInfo) 
	{ 
		::free((void*)lpbi); 
		::DeleteObject(hBmp); 
		return FALSE; 
	} 
 
	ASSERT(pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER)); 
 
	// 此时该结构已经无用,释放 
	::free((void*)lpbi); 
 
	// 创建存放DIB位数据的缓冲区 
	LPSTR pBits = (LPSTR)CreateMemoryBlockFromAddress((LPVOID)NULL,  
		pInfo->bmiHeader.biSizeImage); 
	if (!pBits) 
	{ 
		::free((void*)pInfo); 
		::DeleteObject(hBmp); 
		return FALSE; 
	} 
 
	// 下面的代码并不是要获取位图的DIB位数据,而是要取得位图的颜色表 
	// 颜色表数据在函数(GetDIBits())调用成功后被填写在pInfo结构中 
	hDC = ::GetDC(hWnd); 
	if (!::GetDIBits(hDC,hBmp,0,height,(LPVOID)pBits,pInfo,DIB_RGB_COLORS)) 
	{ 
		::free((void*)pBits); 
		::free((void*)pInfo); 
		::ReleaseDC(hWnd, hDC); 
		::DeleteObject(hBmp); 
		return FALSE; 
	} 
	::ReleaseDC(hWnd, hDC); 
 
	// 此时并不需要DIB位数据,释放 
	::free((void*)pBits); 
 
	// 删除原来的图像,并且设置新的位图 
	if (!ClearAndSetData(IT_CREATE,0,(LPCTSTR)"",pInfo,hBmp)) 
	{ 
		::free((void*)pInfo); 
		::DeleteObject(hBmp); 
		return FALSE; 
	} 
 
	return TRUE; 
}