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