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 // 用于调试目的计数变量,它表示程序中构造的CBmpProc类实例个数 // 可以用类中static DWORD GetObjectCount()成员函数访问该变量 // 注意:该变量和访问它的函数都只是在调试模式下才会有效,如果 // 转换为发布模式,它们都会失效。所以在使用GetObjectCount() // 这个成员函数时,应加入#ifdef _DEBUG .... #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类目标的个数。 ************************************************************************* #ifdef _DEBUG DWORD CBmpProc::GetObjectCount() { return m_ObjectCount; } #endif *************************************************************************/ /************************************************************************* * 析构函数。如果类不为空则清空它。 *************************************************************************/ CBmpProc::~CBmpProc() { Clear(); #ifdef _DEBUG CBmpProc::m_ObjectCount--; #endif } /************************************************************************* * * operator=() * * 参数说明: * * const CBmpProc& ds - 源位图类 * * 返回值: * * CBmpProc& - 类自身引用 * * 描述: * * 复制取指定的位图类 * * 如果函数成功,则类中原来的位图(如果有的话)将被删除,如果不成功,它保留 * 原位图。执行本函数之后,可调用该类的IsValid()函数判断是否成功复制(这种 * 情况只使用于没有图像的类,如果复制前类中就存在图像,可用==操作符判断该类 * 与源位图类是否相同,如果相同则表示复制成功,不同就说明失败) * ************************************************************************/ 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; } /************************************************************************* * * DrawTranCenter() * * 参数说明: * * CDC& dc - 显示位图的设备描述表 * CRect* crArea - 显示范围(矩形坐标) * COLORREF crColour - 要滤掉或保留的颜色(缺省值是白色) * int mode - 如果是0则将不显示指定的颜色,如果是1则保留指定 * 的颜色(缺省值为0) * * 返回值: * * BOOL - 如果成功返回TRUE,否则返回FALSE * * 描述: * * 将类中图像透明的绘入目标设备描述表的指定区域(矩形)的中央,即图像中点 * 与矩形中点重合 * * 如果矩形的尺寸小于图像尺寸,则超出矩形的图像部分会不可见 * 如果入口参数crArea是NULL,函数将返回FALSE * 如果类中没有图像,它什么也不作,直接返回 * 如果矩形坐标不符合规范(比如左边的坐标大于右边的坐标)则函数将自动将 * 其规范化。如果矩形坐标的宽度或高度是0,则函数将返回FALSE * ************************************************************************/ /************************************************************************* * * DrawTranTile() * * 参数说明: * * CDC& dc - 显示位图的设备描述表 * CRect* crArea - 显示范围(矩形坐标) * COLORREF crColour - 要滤掉或保留的颜色(缺省值是白色) * int mode - 如果是0则将不显示指定的颜色,如果是1则保留指定 * 的颜色(缺省值为0) * * 返回值: * * BOOL - 如果成功返回TRUE,否则返回FALSE * * 描述: * * 将类中的图像以平铺并且是透明的方式排满指定区域 * * 如果入口参数crArea是NULL,则函数返回FALSE,如果矩形坐标不符合规范(比如 * 左边的坐标大于右边的坐标)则函数将自动将其规范化。如果矩形坐标的宽度 * 或高度是0,则函数将返回FALSE * * 如果类中没有图像,它什么也不作,直接返回 * ************************************************************************/ /************************************************************************* * * Clear() * * 参数说明:无 * * * 返回值:无 * * * 描述: * * 清除类中的图像 * * 这个函数将删除类中的位图句柄,并清除类中的描述变量 * * 如果类中没有图像,它什么也不作,直接返回 * ************************************************************************/ 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; } } /************************************************************************* * * Attach() * * 参数说明: * * HBITMAP hBmp - 待粘贴的位图句柄 * * 返回值: * * BOOL - 如果成功返回TRUE,否则返回FALSE * * 描述: * * 将指定的位图贴入本身类中。 * * 注: * * # 如果hBmp是一个无效的句柄或是NULL,函数返回FALSE * # 如果本身类中原来存在图像,则调用函数成功之后,原来的图像将被删除 * # hBmp必须是一个兼容于当前显示器颜色格式的DDB位图句柄 * # 如果函数执行成功后,调用它的程序不应再使用hBmp句柄,因为它已被贴入类中 * # 如果函数失败,调用它的程序仍可以正常使用hBmp句柄 * ************************************************************************/ 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; } /************************************************************************* * * Detach() * * 参数说明:无 * * * 返回值: * * HBITMAP - 如果成功,返回分离出的位图句柄,否则返回NULL * * 描述: * * 将本身类中的位图分离出来。 * * 注: * * # 如果本身类中原来存在位图,函数成功调用之后,本身类将被清空 * # 如果本身类中原来没有位图,函数返回NULL * ************************************************************************/ 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; } /************************************************************************* * * Create() * * 参数说明: * * int width - 创建位图的宽度 * int height - 创建位图的高度 * WORD nBitCount - 创建位图中每个像素所占的位数 * const void *lpBits - 新位图的初始化位数据(可以是NULL) * * 返回值: * * BOOL - 如果成功返回TRUE,否则返回FALSE * * 描述: * * 根据指定的数据创建一个位图,并贴入本身类中 * * 注: * * # 入口参数width和height不能是0,如果指定了0,函数返回FALSE * # 入口参数nBitCount的有效值可以是1,4,8,16,24,32,其它的值将视为非法 * # 如果本身类中原来存在图像,则调用函数成功之后,原来的图像将被删除 * # 如果入口参数lpBits是NULL,则新创建的位不被初始化 * ************************************************************************/ /************************************************************************* * * CreateCompatible() * * 参数说明: * * int width - 创建位图的宽度 * int height - 创建位图的高度 * CDC *pDC, - 设备描述表(可以是NULL) * const void *lpBits - 新位图的初始化位数据(可以是NULL) * * 返回值: * * BOOL - 如果成功返回TRUE,否则返回FALSE * * 描述: * * 根据指定的数据创建一个颜色格式兼容于指定描述表的位图,并贴入本身类中 * * 注: * * # 入口参数width和height不能是0,如果指定了0,函数返回FALSE * # 入口参数pDC可以是NULL,这时函数将按当前显示器的颜色格式创建位图,如果 * pDC不是NULL,则它必须指向一个有效的设备描述表 * # 如果本身类中原来存在图像,则调用函数成功之后,原来的图像将被删除 * # 如果入口参数lpBits是NULL,则新创建的位不被初始化 * ************************************************************************/ /************************************************************************* * * CopyTran() * * 参数说明: * * CBmpProc& souBmp - 源位图目标 * COLORREF crColour - 要滤掉或保留的颜色(缺省值是白色) * CRect *pDesRect - 目标矩形(缺省值为NULL) * CRect *pSouRect - 源矩形(缺省值为NULL) * int mode - 如果是0则将不拷贝指定的颜色,如果是1则保留指定 * 的颜色(缺省值为0) * * 返回值: * * BOOL - 如果成功返回TRUE,否则返回FALSE * * 描述: * * 透明的复制源位图目标中指定矩形的图像到本身类中图像的指定区域 * * 如果入口参数pDesRect设为NULL,则目标矩形等于源图像的尺寸。 * 如果入口参数pSouRect设为NULL,则源目标矩形等于源图像的尺寸。 * 如果pDesRect和pSouRect相同,则该函数将不会产生拉伸或压缩动作。 * * 注:# 本身类中原来必需已存在位图,且调用之后的位图不会被删除 * # 如果源位图类是空的,则返回FALSE * # 如果本身类中不存在位图,函数将返回FALSE * ************************************************************************/ 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; } /************************************************************************* * * LoadFromResourceID() * * 参数说明: * * UINT uID - 待读入的位图资源名称(标识值) * HINSTANCE hInstance - 位图资源所在实例的句柄(如果它被设为NULL,则 * 函数将该值设为当前应用程序进程) * * 返回值: * * BOOL - 如果成功返回TRUE,否则返回FALSE * * 描述: * * 读取指定位图资源到类中 * * 如果函数成功,则类中原来的位图(如果有的话)将被删除 * ************************************************************************/ BOOL CBmpProc::LoadFromResourceID(UINT uID, HINSTANCE hInst) { return LoadFromResourceName((LPCTSTR)MAKEINTRESOURCE(uID), hInst); } /************************************************************************* * * CalculateDIBFileSize() * * 参数说明: * * LPBITMAPINFOHEADER lpbi - 指向内存DIB的BITMAPINFOHEADER结构 * * 返回值: * * DWORD - 返回DIB文件的尺寸 * * 描述: * * 计算具有指定信息格式的DIB位图的尺寸(以字节为单位) * ************************************************************************/ /************************************************************************* * * CalculateDIBSize() * * 参数说明: * * LPBITMAPINFOHEADER lpbi - 指向内存DIB的BITMAPINFOHEADER结构 * * 返回值: * * DWORD - 返回DIB内部形式的尺寸 * * 描述: * * 计算具有指定信息格式的DIB内部形式的尺寸(以字节为单位) * * 内部形式是指除去文件头结构的DIB文件内容在内存中的实现 * ************************************************************************/ /************************************************************************* * * CalculateDIBitsOff() * * 参数说明: * * LPBITMAPINFOHEADER lpbi - 指向内存DIB的BITMAPINFOHEADER结构 * * 返回值: * * DWORD - 返回在DIB文件中位的偏移 * * 描述: * * 计算具有指定信息格式的DIB位图中位的偏移(以字节为单位) * ************************************************************************/ /************************************************************************* * * CalculateDIBInfoSize() * * 参数说明: * * LPBITMAPINFOHEADER lpbi - 指向内存DIB的BITMAPINFOHEADER结构 * * 返回值: * * DWORD - 返回在DIB文件中信息块的长度 * * 描述: * * 计算具有指定信息格式的DIB位图中信息块的长度(以字节为单位) * * 信息块是指BITMAPINFO结构。注意,其中含有颜色表! * ************************************************************************/ /************************************************************************* * * CalculateDIBitsSize() * * 参数说明: * * LPBITMAPINFOHEADER lpbi - 指向内存DIB的BITMAPINFOHEADER结构 * * 返回值: * * DWORD - 返回在DIB文件中位的尺寸 * * 描述: * * 计算具有指定信息格式的DIB位图中位的(以字节为单位) * ************************************************************************/ 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); } /****************************** DIB Function ****************************/ /* DIB 函数注释: # 不支持OS/2操作系统产生的DIB位图 # 不支持压缩位图(RLE压缩编码) # FindDIBBits()的入口参数lpbi是指向包括信息头、颜色表、位数据的内存块 # 其它函数的入口参数lpbi是指向信息块,即BITMAPINFOHEADER结构 # 函数的入口参数lpbi中的数据必需是有效的! */ /************************************************************************* * * FindDIBBits() * * 参数说明: * * LPSTR lpbi - 指向内存DIB的首地址 * * 返回值: * * LPSTR - 指向DIB位数据的地址 * * 描述: * * 这个函数计算DIB的位数据地址,并将它返回。 * ************************************************************************/ LPSTR CBmpProc::FindDIBBits(LPSTR lpbi) const { ASSERT(lpbi); ASSERT(((LPBITMAPINFOHEADER)lpbi)->biSize == sizeof(BITMAPINFOHEADER)); return (lpbi + *(LPDWORD)lpbi + PaletteSize((LPBITMAPINFOHEADER)lpbi)); } /************************************************************************* * * DIBWidth() * * 参数说明: * * LPBITMAPINFOHEADER lpbi - 指向内存DIB的BITMAPINFOHEADER 结构 * * 返回值: * * DWORD - DIB的宽度 * * 描述: * * 获取DIB的宽度。(像素) * * 它从BITMAPINFOHEADER结构的biWidth成员提取宽度值。 * ************************************************************************/ DWORD CBmpProc::DIBWidth(LPBITMAPINFOHEADER lpbi) const { ASSERT(lpbi); ASSERT(lpbi->biSize == sizeof(BITMAPINFOHEADER)); return lpbi->biWidth; } /************************************************************************* * * DIBHeight() * * 参数说明: * * LPBITMAPINFOHEADER lpbi - 指向内存DIB的BITMAPINFOHEADER结构 * * 返回值: * * DWORD - DIB的高度 * * 描述: * * 获取DIB的高度。(像素) * * 它从BITMAPINFOHEADER结构的biHeight成员提取高度值。 * ************************************************************************/ DWORD CBmpProc::DIBHeight(LPBITMAPINFOHEADER lpbi) const { ASSERT(lpbi); ASSERT(lpbi->biSize == sizeof(BITMAPINFOHEADER)); return lpbi->biHeight; } /************************************************************************* * * PaletteSize() * * 参数说明: * * LPBITMAPINFOHEADER lpbi - 指向内存DIB的BITMAPINFOHEADER结构 * * 返回值: * * WORD - DIB调色板的尺寸(以字节为单位) * * 描述: * * 获取指定DIB的调色板尺寸(以字节为单位) * * 这个函数先获取DIB的颜色个数,然后用颜色个数值乘与RGBQUAD的结构尺寸。 * ************************************************************************/ 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; } /************************************************************************* * * DIBNumColors() * * 参数说明: * * LPBITMAPINFOHEADER lpbi - 指向内存DIB的BITMAPINFOHEADER结构 * * 返回值: * * WORD - 颜色表中颜色的个数 * * 描述: * * 获取DIB颜色表中的颜色个数。 * * 这个函数通过DIB中每个像素所占的位数来计算它的颜色表中颜色的个数。比如 * 一个像素占用一位,则有两种颜色,占用四位,则有16种颜色。占用8位,则有 * 256种颜色,而占用16或更多位,则颜色表中就没有颜色数据了。 * * (注意:16位和32位位图的颜色表并不是空的,其中有三个DWORD型的数值,用 * 以表示红、绿、蓝在位数据中的掩码,而24位位图的颜色表则是空的,即颜色 * 表的尺寸为0,但本函数并不将掩码作为颜色,所以如果是16位和32位位图,本 * 函数仍将返回0。如果位图信息中biClrUsed成员不是0,本函数将使用这个值,而 * 不去计算) ************************************************************************/ 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; } } /************************************************************************* * * CreateMemoryBlockFromAddress() * * 参数说明: * * LPVOID pSou - 待复制的内存块地址(可以是NULL,参见注释) * DWORD dwCount - 复制范围(即复制字节的个数,可以是0,参见注释) * * 返回值: * * LPVOID - 新的内存块地址,如果失败,返回NULL * * 描述: * * 复制内存块。(也可用于创建内存块) * * 该函数先创建一个长度为dwCount的内存,并将新创建的内存初始化为0,然后 * 复制pSou中长度为dwCount的内容到新的内存块。如果pSou为NULL,则不复制 * * 如果入口参数dwCount被指定为0,则函数将复制整个原地址的内容,新内存块 * 的尺寸将与源地址内存块的尺寸相同 * 入口参数pSou和dwCount不能同时为0,否则函数将返回NULL * * 函数返回的内存块不再使用时,应调用free()函数将其释放 * * pSou参数指定的内存块必须是由malloc(),calloc(),realloc()函数分配的!!! * ************************************************************************/ 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; } /************************************************************************* * * CreateMemoryBlockFromHandle() * * 参数说明: * * HANDLE handle - 待复制的内存句柄(可以是NULL,参见注释) * DWORD dwCount - 新创内存块的尺寸(可以是0,参见注释) * * 返回值: * * LPVOID - 新的内存块地址,如果失败,返回NULL * * 描述: * * 复制指定尺寸的内存句柄内容到一个新的内存块中(也可用于创建内存块) * * 注: * * 该函数先创建一个指定长度的内存块,并将新创建的内存初始化为0,然后 * 复制句柄handle中指定大小的内容到新的内存块中。 * * 如果入口参数handle被指定为NULL,则函数只创建内存,不复制 * 如果入口参数dwCount被指定为0,则函数将复制整个原句柄的内容,新内存块 * 的尺寸将与源句柄的尺寸相同 * 入口参数handle和dwCount不能同时为0,否则函数将返回NULL * * 函数返回的内存块不再使用时,应调用free()函数将其释放 * ************************************************************************/ /************************************************************************* * * GetBitsPerPixel() * * 参数说明: * * LPBITMAPINFOHEADER lpbi - 指向内存DIB的BITMAPINFOHEADER结构 * * 返回值: * * int - 返回每个像素所占的位数。 * * 描述: * * 获取指定DIB中每个像素所占的位数。 * ************************************************************************/ int CBmpProc::GetBitsPerPixel(LPBITMAPINFOHEADER lpbi) const { ASSERT(lpbi); ASSERT(lpbi->biSize == sizeof(BITMAPINFOHEADER)); return lpbi->biBitCount; // DIB位计数 } /***************************** 内部访问函数 **************************/ /************************************************************************* * * Size() * * 参数说明:无 * * * 返回值: * * CSize - 返回包含图像尺寸的CSize目标,如果失败,CSize目标 * 中的宽度和高度都是0 * * 描述: * * 获取类中图像的宽度和高度(以像素为单位) * ************************************************************************/ 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)); } /************************************************************************* * * Rect() * * 参数说明:无 * * * 返回值: * * CRect - 返回包含图像尺寸的CRect目标,如果失败,CRect目标 * 中的数据均是0 * * 描述: * * 获取类中图像的尺寸数据(以像素为单位) * ************************************************************************/ CRect CBmpProc::Rect() const { if (m_mark == FALSE) return CRect(0,0,0,0); ASSERT(m_pInfo); return CRect(CPoint(0, 0), Size()); } /************************************************************************* * * Width() * * 参数说明:无 * * * 返回值: * * int - 返回图像的宽度,如果失败返回0 * * 描述: * * 获取类中图像的宽度数据(以像素为单位) * ************************************************************************/ int CBmpProc::Width() const { if (m_mark == FALSE) return 0; ASSERT(m_pInfo); return (int)DIBWidth((LPBITMAPINFOHEADER)m_pInfo); } /************************************************************************* * * Height() * * 参数说明:无 * * * 返回值: * * int - 返回图像的高度,如果失败返回0 * * 描述: * * 获取类中图像的高度数据(以像素为单位) * ************************************************************************/ int CBmpProc::Height() const { if (m_mark == FALSE) return 0; ASSERT(m_pInfo); return (int)DIBHeight((LPBITMAPINFOHEADER)m_pInfo); } /************************************************************************* * * IsValid() * * 参数说明:无 * * * 返回值: * * BOOL - 如果类中存在位图则返回TRUE,否则返回FALSE * * 描述: * * 判断类中是否存在有效的位图 * ************************************************************************/ BOOL CBmpProc::IsValid() const { return m_mark; } /************************************************************************* * * GetObject() * * 参数说明: * * LPBITMAP lpBitmap - 接收信息数据的结构变量地址 * * 返回值: * * int - 如果成功返回以获取的字节个数,如果失败,返回0 * * 描述: * * 获取位图的BITMAP信息 * * 注:# 函数成功返回之后,BITMAP结构中只有width,height及颜色格式信息有效 * # 如果类中原来没有位图,函数失败,返回0 * ************************************************************************/ int CBmpProc::GetObject(LPBITMAP lpBitmap) const { if (m_mark == FALSE) return 0; ASSERT(m_hObject); ASSERT(lpBitmap); return CGdiObject::GetObject(sizeof(BITMAP), (LPVOID)lpBitmap); } /************************************************************************* * * PasteAvailable() * * 参数说明:无 * * * 返回值: * * BOOL - 如果剪贴板中存在DIB格式的数据,则返回TRUE,否则 * 返回FALSE * * 描述: * * 判断剪贴板中是否存在DIB格式的数据。 * ************************************************************************/ /************************************************************************* * * ClearAndSetData() * * 参数说明: * * int type - 新位图来源类型 * DWORD addinfo - 新位图的附加信息值 * LPCTSTR lpFn - 新位图的文件名字符串 * LPBITMAPINFO pInfo - 新位图的信息块地址 * HBITMAP hBmp - 新位图的位图句柄 * * 返回值: * * BOOL - 如果成功返回TRUE,否则返回FALSE * * 描述: * * 清除类中原来的位图,并用指定的数据设置位图 * * # 如果本身类中原来有位图,函数将清除它们 * # 入口指定的参数必须保证是有效的数据 * ************************************************************************/ 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; } } /************************************************************************* * * DrawTransparentInPoint() * * 参数说明: * * CDC& dc - 显示位图的设备描述表 * COLORREF crColour - 图像中要被滤掉的颜色(缺省值为白色) * int x - 目标矩形的左上角坐标 X(缺省值为0) * int y - '' Y(缺省值为0) * CRect* crSou - 源图像待显示部分的矩形坐标(缺省值是NULL) * int mode - 如果是0则将不显示指定的颜色,如果是1则保留指定 * 的颜色(缺省值为0) * * 返回值: * * BOOL - 如果成功返回TRUE,否则返回FALSE * * 描述: * * 将类中的图像透明的绘入目标设备描述表指定区域,如有必要可以产生拉伸或压缩 * 动作 * * 如果类中没有图像,它什么也不作,直接返回 * 如果待绘制的图像不在当前剪贴区域内,则直接返回 * 如果入口参数crSou被设为NULL,则函数将不会产生图像的拉伸或压缩 * ************************************************************************/ /************************************************************************* * * DrawTransparentInRect() * * 参数说明: * * CDC& dc - 显示位图的设备描述表 * COLORREF crColour - 图像中要被滤掉的颜色(缺省值为白色) * CRect* crDest - 目标矩形坐标数据(缺省值是NULL) * CRect* crSou - 源图像待显示部分的矩形坐标(缺省值是NULL) * int mode - 如果是0则将不显示指定的颜色,如果是1则保留指定 * 的颜色(缺省值为0) * * 返回值: * * BOOL - 如果成功返回TRUE,否则返回FALSE * * 描述: * * 将类中的图像透明的绘入目标设备描述表指定区域,如有必要可以产生拉伸或压缩 * 动作 * * 如果类中没有图像,它什么也不作,直接返回 * 如果待绘制的图像不在当前剪贴区域内,则直接返回 * 如果入口参数crDest和crSou都是NULL,则函数将在设备描述表的0,0位置不变形的 * 绘制类中位图的整个内容 * 如果入口参数crDest和crSou的宽度或高度值不同,则绘制出来的图像会变形(被 * 拉伸或被压缩) * ************************************************************************/ /************************************************************************* * * Fill() * * 参数说明: * * COLORREF crColour - 指定要填充的颜色(缺省值是白色) * CRect *crArea - 填充的区域矩形(缺省值是NULL) * * 返回值: * * BOOL - 如果成功返回TRUE,否则返回FALSE * * 描述: * * 用指定的颜色填充本身类中位图的指定区域(矩形) * * 如果入口参数crArea被设为NULL,则函数将填充整个的位图 * 如果类中没有图像,直接返回FALSE * ************************************************************************/ 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; } /************************************************************************* * * ReSetColor() * * 参数说明: * * COLORREF oldcolr - 待替换的旧颜色 * COLORREF newcolr - 将要替换上去的新的颜色 * CRect *crArea - 要替换的范围(缺省值是NULL) * * 返回值: * * BOOL - 如果成功返回TRUE,否则返回FALSE * * 描述: * * 用一种颜色替换另一种颜色,在位图的指定矩形中 * * 如果入口参数crArea被设为NULL,则函数将替换整个的位图指定颜色 * 如果类中没有图像,直接返回FALSE * ************************************************************************/ 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; }