复制代码
- ///////////////////////////////////////////////////////////////////////
- /*
- 目的:BMP位图处理类。(源代码文件)
-
- 创建:张伟(SXZ)
- 版本:2.4
-
- SXZ software workgroup. No.200001
- */
- ///////////////////////////////////////////////////////////////////////
-
- ///////////////////////////////////////////////////////////////////////
- /*
- 注释:
-
- # 类中的位图都是兼容于当前显示器颜色格式的DDB位图
- # 如果读入的位图格式与当前显示器的颜色格式不同,则读入函数会先将其转换
- 为兼容于当前显示器颜色格式的位图之后才放入类中
- # 对于所有BOOL型返回的函数,TRUE表示成功,FALSE表示失败
-
-
- */
- ///////////////////////////////////////////////////////////////////////
-
- #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;;
- }
- }
-
-
-
- /*************************************************************************
- *
- * operator=()
- *
- * 参数说明:
- *
- * const HBITMAP sou - 源位图句柄
- *
- * 返回值:
- *
- * CBmpProc& - 类自身引用
- *
- * 描述:
- *
- * 复制取指定的位图
- *
- * 如果函数成功,则类中原来的位图(如果有的话)将被删除,如果不成功,它保留
- * 原位图。执行本函数之后,可调用该类的IsValid()函数判断是否成功复制(这种
- * 情况只使用于没有图像的类,如果复制前类中就存在图像,可用==操作符判断该类
- * 与源位图类是否相同,如果相同则表示复制成功,不同就说明失败)
- * 如果入口参数指定的位图句柄无效,则函数失败。
- *
- ************************************************************************/
-
-
- CBmpProc& CBmpProc::operator=(const HBITMAP sou)
- {
- // 入口检测
- if (!sou)
- return *this;
-
- CBmpProc tmp;
-
- if (!tmp.Attach(sou))
- return *this;
-
- ASSERT(sou == (HBITMAP)tmp);
-
- // 调用类赋值操作符函数
- *this = tmp;
- // 分离源位图,防止析构函数将其删除
- tmp.Detach();
-
- return *this;
- }
-
-
-
- /*************************************************************************
- *
- * operator==()
- *
- * 参数说明:
- *
- * const CBmpProc& ds - 源位图类
- *
- * 返回值:
- *
- * BOOL - 如果相同返回TRUE,不同返回FALSE
- *
- * 描述:
- *
- * 判断源位图类与本身类是否相同
- *
- * 该函数通过比较两个类的位图来判定它们是否具有相同的图像。
- *
- * 注:# 如果两个类都是空的(即都没有图像),则该函数将视它们是不相同的
- *
- ************************************************************************/
-
-
- BOOL CBmpProc::operator==(const CBmpProc& ds)
- {
- // 如果两个类中有一个或都是空的(即都没有图像),则该函数将视它们
- // 是不相同的
- if ((ds.IsValid()==FALSE)||(IsValid()==FALSE))
- return FALSE;
-
- // 如果是与自身比较,则直接返回TRUE
- if (this == &ds)
- return TRUE;
-
- ASSERT(m_pInfo);
- ASSERT(ds.m_pInfo);
- ASSERT(m_pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER));
- ASSERT(ds.m_pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER));
-
- // 信息块长度比较
- if (::_msize(m_pInfo) != ::_msize(ds.m_pInfo))
- return FALSE;
-
- // 信息块内容比较
- if (::memcmp((const void*)m_pInfo, \
- (const void*)ds.m_pInfo,::_msize(m_pInfo)))
- return FALSE;
-
- // 创建存放DIB位数据的缓冲区
- LPSTR pBits1 = (LPSTR)CreateMemoryBlockFromAddress((LPVOID)NULL,
- CalculateDIBitsSize((LPBITMAPINFOHEADER)m_pInfo));
- if (!pBits1)
- return FALSE;
-
- LPSTR pBits2 = (LPSTR)CreateMemoryBlockFromAddress((LPVOID)NULL,
- CalculateDIBitsSize((LPBITMAPINFOHEADER)m_pInfo));
- if (!pBits2)
- {
- ::free((void*)pBits1);
- return FALSE;
- }
-
- // 复制位图信息块,因为GetDIBits()函数有可能会改变颜色表数据
- LPBITMAPINFO pInfo = (LPBITMAPINFO)CreateMemoryBlockFromAddress(
- (LPVOID)m_pInfo);
- if (!pInfo)
- {
- ::free((void*)pBits1);
- ::free((void*)pBits2);
- return FALSE;
- }
-
- ASSERT(pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER));
-
- HWND hWnd = ::GetDesktopWindow();
- ASSERT(hWnd);
- HDC hDC;
-
- // 获取位图的DIB位数据
- hDC = ::GetDC(hWnd);
- ASSERT(m_hObject);
- ASSERT(ds.m_hObject);
- if (!::GetDIBits(hDC,(HBITMAP)m_hObject,0,pInfo->bmiHeader.biHeight, \
- (LPVOID)pBits1,pInfo,DIB_RGB_COLORS))
- {
- ::free((void*)pBits1);
- ::free((void*)pBits2);
- ::free((void*)pInfo);
- ::ReleaseDC(hWnd, hDC);
- return FALSE;
- }
- if (!::GetDIBits(hDC,(HBITMAP)ds.m_hObject,0,pInfo->bmiHeader.biHeight, \
- (LPVOID)pBits2,pInfo,DIB_RGB_COLORS))
- {
- ::free((void*)pBits1);
- ::free((void*)pBits2);
- ::free((void*)pInfo);
- ::ReleaseDC(hWnd, hDC);
- return FALSE;
- }
- ::ReleaseDC(hWnd, hDC);
- ::free((void*)pInfo);
-
- // 位内容比较
- LONG leng = (LONG)CalculateDIBitsSize((LPBITMAPINFOHEADER)m_pInfo)/4;
- LPDWORD lp1 = (LPDWORD)pBits1; // DIB位数据是DWORD对齐的
- LPDWORD lp2 = (LPDWORD)pBits2;
-
- // 因为不清楚memcmp()函数是否可以比较大于64K的数据,所以才采用这种
- // 老笨的方法。
- while(leng--)
- {
- if (*lp1 != *lp2) break;
- lp1++; lp2++;
- }
-
- // 比较完之后,位数据已无用,释放
- ::free((void*)pBits1);
- ::free((void*)pBits2);
-
- if (leng != -1L)
- return FALSE; // 位数据不同返回FALSE
-
- return TRUE;
- }
- /*************************************************************************
- *
- * operator!=()
- *
- * 参数说明:
- *
- * const CBmpProc& ds - 源位图类
- *
- * 返回值:
- *
- * BOOL - 如果不同返回TRUE,相同返回FALSE
- *
- * 描述:
- *
- * 判断源位图类是否与本身类不同
- *
- * 该函数通过比较两个类的位图来判定它们是否具有相同的图像。
- *
- * 注:# 如果两个类都是空的(即都没有图像),则该函数将视它们是不相同的
- *
- ************************************************************************/
-
-
- BOOL CBmpProc::operator!=(const CBmpProc& ds)
- {
- return ((*this) == ds) ? FALSE:TRUE;
- }
-
-
-
- /*************************************************************************
- *
- * Draw()
- *
- * 参数说明:
- *
- * CDC& dc - 显示位图的设备描述表
- * const CRect* rcDst - 目标矩形
- * const CRect* rcSrc - 源矩形
- *
- * 返回值:
- *
- * BOOL - 如果成功返回TRUE,否则返回FALSE
- *
- * 描述:
- *
- * 将类中指定区域的图像绘入目标设备描述表的指定区域,如果源区域(即矩形)
- * 和目标区域不同,将产生拉伸或压缩动作
- *
- * 如果源矩形和目标矩形是NULL,则函数将视这两个矩形都等于类中图像的尺寸
- *
- * 如果类中没有图像,它什么也不作,直接返回
- * 如果待绘制的图像不在当前剪贴区域内,则直接返回
- *
- ************************************************************************/
-
-
- 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;
- }
-
-
-
- /*************************************************************************
- *
- * DrawTile()
- *
- * 参数说明:
- *
- * CDC& dc - 显示位图的设备描述表
- * CRect* crArea - 铺设范围(矩形坐标)
- *
- * 返回值:
- *
- * BOOL - 如果成功返回TRUE,否则返回FALSE
- *
- * 描述:
- *
- * 将类中的图像以平铺方式排满指定区域
- *
- * 如果入口参数crArea是NULL,则函数返回FALSE,如果矩形坐标不符合规范(比如
- * 左边的坐标大于右边的坐标)则函数将自动将其规范化。如果矩形坐标的宽度
- * 或高度是0,则函数将返回FALSE
- *
- * 如果类中没有图像,它什么也不作,直接返回
- *
- ************************************************************************/
-
-
- BOOL CBmpProc::DrawTile(CDC& dc, CRect* crArea)
- {
- if (!crArea)
- return FALSE;
-
- // 如果类中没有图像,直接返回
- if (!IsValid())
- return TRUE;
-
- CRect rect = *crArea;
- CRect tprc;
-
- // 矩形坐标规范化
- rect.NormalizeRect();
-
- if ((rect.Width()==0)||(rect.Height()==0))
- return FALSE;
-
- ASSERT(m_pInfo);
- ASSERT(m_hObject);
-
- // 因为下面的代码将改变设备描述表中剪贴区域的设置,所以先将其保存
- int savedc = dc.SaveDC();
-
- CRgn newrgn;
- newrgn.CreateRectRgnIndirect(&rect);
- // 只显示指定矩形中可见的部分(用AND操作)
- dc.SelectClipRgn(&newrgn, RGN_AND);
-
- for (int y=rect.top;y {
- for (int x=rect.left;x {
- // 以瓦片方式重复显示图像
- tprc.SetRect(x,y,x+Width(),y+Height());
- Draw(dc, &tprc);
- }
- }
-
- dc.RestoreDC(savedc);
- // 恢复设备描述表的内容之后,将区域的句柄显示的删除
- // (微软在文档中特意注明要用CGdiObject::DeleteObject()
- // 函数显示的删除区域句柄,不知是什么原因)
- newrgn.CGdiObject::DeleteObject();
-
- return TRUE;
- }
-
-
-
- /*************************************************************************
- *
- * DrawCenter()
- *
- * 参数说明:
- *
- * CDC& dc - 显示位图的设备描述表
- * CRect* crArea - 显示范围(矩形坐标)
- *
- * 返回值:
- *
- * BOOL - 如果成功返回TRUE,否则返回FALSE
- *
- * 描述:
- *
- * 将类中图像绘入目标设备描述表的指定区域(矩形)的中央,即图像中点与矩
- * 形中点重合
- *
- * 如果矩形的尺寸小于图像尺寸,则图像的四周部分会不可见
- * 如果入口参数crArea是NULL,函数将返回FALSE
- * 如果类中没有图像,它什么也不作,直接返回
- * 如果矩形坐标不符合规范(比如左边的坐标大于右边的坐标)则函数将自动将
- * 其规范化。如果矩形坐标的宽度或高度是0,则函数将返回FALSE
- *
- ************************************************************************/
-
-
- BOOL CBmpProc::DrawCenter(CDC& dc, CRect* crArea)
- {
- if (!crArea)
- return FALSE;
-
- // 如果类中没有图像,直接返回
- if (!IsValid())
- return TRUE;
-
- CRect rect = *crArea;
-
- // 矩形坐标规范化
- rect.NormalizeRect();
-
- if ((rect.Width()==0)||(rect.Height()==0))
- return FALSE;
-
- ASSERT(m_pInfo);
- ASSERT(m_hObject);
-
- // 取指定矩形的中点坐标
- CPoint cpce = rect.CenterPoint();
- CRect tprc(CPoint(cpce.x-Width()/2,cpce.y-Height()/2), Size());
-
- // 因为下面的代码将改变设备描述表中剪贴区域的设置,所以先将其保存
- int savedc = dc.SaveDC();
-
- CRgn newrgn;
- newrgn.CreateRectRgnIndirect(&rect);
- // 只显示指定矩形中可见的部分(用AND操作)
- dc.SelectClipRgn(&newrgn, RGN_AND);
-
- Draw(dc, &tprc);
-
- dc.RestoreDC(savedc);
- newrgn.CGdiObject::DeleteObject();
-
- return TRUE;
- }
-
-
-
- /*************************************************************************
- *
- * DrawTranCenter()
- *
- * 参数说明:
- *
- * CDC& dc - 显示位图的设备描述表
- * CRect* crArea - 显示范围(矩形坐标)
- * COLORREF crColour - 要滤掉或保留的颜色(缺省值是白色)
- * int mode - 如果是0则将不显示指定的颜色,如果是1则保留指定
- * 的颜色(缺省值为0)
- *
- * 返回值:
- *
- * BOOL - 如果成功返回TRUE,否则返回FALSE
- *
- * 描述:
- *
- * 将类中图像透明的绘入目标设备描述表的指定区域(矩形)的中央,即图像中点
- * 与矩形中点重合
- *
- * 如果矩形的尺寸小于图像尺寸,则超出矩形的图像部分会不可见
- * 如果入口参数crArea是NULL,函数将返回FALSE
- * 如果类中没有图像,它什么也不作,直接返回
- * 如果矩形坐标不符合规范(比如左边的坐标大于右边的坐标)则函数将自动将
- * 其规范化。如果矩形坐标的宽度或高度是0,则函数将返回FALSE
- *
- ************************************************************************/
-
-
- BOOL CBmpProc::DrawTranCenter(CDC& dc,
- CRect* crArea,
- COLORREF crColour,
- int mode)
- {
- if (!crArea)
- return FALSE;
-
- // 如果类中没有图像,直接返回
- if (!IsValid())
- return TRUE;
-
- CRect rect = *crArea;
-
- // 矩形坐标规范化
- rect.NormalizeRect();
-
- if ((rect.Width()==0)||(rect.Height()==0))
- return FALSE;
-
- ASSERT(m_pInfo);
- ASSERT(m_hObject);
-
- // 取指定矩形的中点坐标
- CPoint cpce = rect.CenterPoint();
- CRect tprc(CPoint(cpce.x-Width()/2,cpce.y-Height()/2), Size());
-
- // 因为下面的代码将改变设备描述表中剪贴区域的设置,所以先将其保存
- int savedc = dc.SaveDC();
-
- CRgn newrgn;
- newrgn.CreateRectRgnIndirect(&rect);
- // 只显示指定矩形中可见的部分(用AND操作)
- dc.SelectClipRgn(&newrgn, RGN_AND);
-
- DrawTransparentInRect(dc, crColour, &tprc, NULL, mode); // 显示透明图像
-
- dc.RestoreDC(savedc);
- newrgn.CGdiObject::DeleteObject();
-
- return TRUE;
- }
-
-
-
- /*************************************************************************
- *
- * DrawTranTile()
- *
- * 参数说明:
- *
- * CDC& dc - 显示位图的设备描述表
- * CRect* crArea - 显示范围(矩形坐标)
- * COLORREF crColour - 要滤掉或保留的颜色(缺省值是白色)
- * int mode - 如果是0则将不显示指定的颜色,如果是1则保留指定
- * 的颜色(缺省值为0)
- *
- * 返回值:
- *
- * BOOL - 如果成功返回TRUE,否则返回FALSE
- *
- * 描述:
- *
- * 将类中的图像以平铺并且是透明的方式排满指定区域
- *
- * 如果入口参数crArea是NULL,则函数返回FALSE,如果矩形坐标不符合规范(比如
- * 左边的坐标大于右边的坐标)则函数将自动将其规范化。如果矩形坐标的宽度
- * 或高度是0,则函数将返回FALSE
- *
- * 如果类中没有图像,它什么也不作,直接返回
- *
- ************************************************************************/
-
-
- BOOL CBmpProc::DrawTranTile(CDC& dc,
- CRect* crArea,
- COLORREF crColour,
- int mode)
- {
- if (!crArea)
- return FALSE;
-
- // 如果类中没有图像,直接返回
- if (!IsValid())
- return TRUE;
-
- CRect rect = *crArea;
- CRect tprc;
-
- // 矩形坐标规范化
- rect.NormalizeRect();
-
- if ((rect.Width()==0)||(rect.Height()==0))
- return FALSE;
-
- ASSERT(m_pInfo);
- ASSERT(m_hObject);
-
- // 因为下面的代码将改变设备描述表中剪贴区域的设置,所以先将其保存
- int savedc = dc.SaveDC();
-
- CRgn newrgn;
- newrgn.CreateRectRgnIndirect(&rect);
- // 只显示指定矩形中可见的部分(用AND操作)
- dc.SelectClipRgn(&newrgn, RGN_AND);
-
- for (int y=rect.top;y {
- for (int x=rect.left;x {
- // 以瓦片方式重复显示图像
- tprc.SetRect(x,y,x+Width(),y+Height());
- // 显示透明图像
- DrawTransparentInRect(dc, crColour, &tprc, NULL, mode);
- }
- }
-
- dc.RestoreDC(savedc);
- newrgn.CGdiObject::DeleteObject();
-
- return TRUE;
- }
-
-
-
- /*************************************************************************
- *
- * 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;
- }
-
-
-
- /*************************************************************************
- *
- * Save()
- *
- * 参数说明:
- *
- * LPCTSTR lpszNewFileName - 指定的新文件名(可以是NULL)
- * WORD nBitsPerPixel - 指定的新颜色格式(即每像素多少位,可以是0)
- *
- * 返回值:
- *
- * BOOL - 如果成功返回TRUE,否则返回FALSE
- *
- * 描述:
- *
- * 将本身类中的位图以新的格式或新的名称保存到文件中
- *
- * 注:
- *
- * # 如果没有指定新的文件名(入口参数lpszNewFileName被指定为NULL),函数
- * 就使用类中原来的文件名,如果类中原来没有文件名则函数失败,返回FALSE
- * # 如果没有指定新的位数(入口参数nBitsPerPixel被指定为0),函数就使用类
- * 中原来的位数值。如果新指定的位数值非法则函数失败,返回FALSE。合法的
- * 位数值是1,4,8,16,24,32 其中之一
- * # 如果本身类中原来没有位图(空类),函数返回FALSE
- * # 如果文件没有打开或是写文件时出错,函数返回FALSE
- * # 函数执行成功之后,本身类中的文件名或位数将改为新值
- * # 无论函数成功与否,本身类中的位图不会改变
- *
- ************************************************************************/
-
-
- BOOL CBmpProc::Save(LPCTSTR lpszNewFileName, WORD nBitsPerPixel)
- {
- // 如果本身类中原来没有位图,函数返回FALSE
- if (!IsValid())
- return FALSE;
-
- ASSERT(m_pInfo);
- ASSERT(m_pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER));
-
- LPBITMAPINFO pInfo;
- BOOL bRet;
- CString cOldFN;
-
- // 以原来的格式保存到原来的文件中
- if ((lpszNewFileName==NULL)&&(nBitsPerPixel==0))
- {
- // 应该有文件名
- if (m_cFileName.IsEmpty())
- return FALSE;
-
- return SaveBaseSpecifyFileName((LPCTSTR)m_cFileName);
- }
-
- // 以原来的格式保存到新的文件中
- if ((lpszNewFileName!=NULL)&&(nBitsPerPixel==0))
- {
- bRet = SaveBaseSpecifyFileName((LPCTSTR)lpszNewFileName);
-
- if (bRet)
- m_cFileName = lpszNewFileName;
-
- return bRet;
- }
-
- // 以新的格式保存到原来的文件中
- if ((lpszNewFileName==NULL)&&(nBitsPerPixel!=0))
- {
- // 检测位数合法性
- if (!IsValidDibFormat(nBitsPerPixel))
- return FALSE;
-
- // 应该有文件名
- if (m_cFileName.IsEmpty())
- return FALSE;
-
- bRet = SaveBaseSpecifyFormat(nBitsPerPixel);
-
- if (bRet)
- {
- pInfo = GetSpecifyFormatInfo(nBitsPerPixel);
- if (!pInfo)
- return FALSE;
- ::free((void*)m_pInfo);
- m_pInfo = pInfo;
- }
- return bRet;
- }
-
- // 以新的格式保存到新的文件中
- if ((lpszNewFileName!=NULL)&&(nBitsPerPixel!=0))
- {
- // 检测位数合法性
- if (!IsValidDibFormat(nBitsPerPixel))
- return FALSE;
-
- cOldFN = m_cFileName;
- m_cFileName = lpszNewFileName;
-
- bRet = SaveBaseSpecifyFormat(nBitsPerPixel);
-
- if (bRet)
- { // 获取指定格式的信息块
- pInfo = GetSpecifyFormatInfo(nBitsPerPixel);
- if (!pInfo)
- {
- m_cFileName = cOldFN;
- return FALSE;
- }
- ::free((void*)m_pInfo);
- m_pInfo = pInfo;
- }
- else
- m_cFileName = cOldFN;
-
- return bRet;
- }
-
- return FALSE;
- }
-
-
-
- /*************************************************************************
- *
- * SaveToClipboard()
- *
- * 参数说明:无
- *
- *
- * 返回值:
- *
- * BOOL - 如果成功返回TRUE,否则返回FALSE
- *
- * 描述:
- *
- * 保存本身类中的位图到剪贴板
- *
- * 注:
- *
- * # 如果本身类中原来没有位图,函数返回FALSE
- * # 如果在打开或写入剪贴板时出错,函数返回FALSE
- * # 无论函数成功与否,本身类中的内容都不会改变
- *
- ************************************************************************/
-
-
- BOOL CBmpProc::SaveToClipboard()
- {
- // 如果本身类中原来没有位图,函数返回FALSE
- if (!IsValid())
- return FALSE;
-
- ASSERT(m_pInfo);
- ASSERT(m_pInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER));
-
- // 打开剪贴板
- if (::OpenClipboard(NULL))
- {
- // 清空剪贴板
- if (::EmptyClipboard())
- {
- DWORD DibSize = CalculateDIBSize((LPBITMAPINFOHEADER)m_pInfo);
- DWORD infosize =CalculateDIBInfoSize((LPBITMAPINFOHEADER)m_pInfo);
-
- // 分配DIB内部格式内存块
- HANDLE hDib = ::GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, DibSize);
- if (hDib)
- {
- LPSTR lpDib = (LPSTR)::GlobalLock(hDib);
- if (lpDib)
- {
- ::memcpy((void*)lpDib, (const void*)m_pInfo, infosize);
-
- // 获取DIB位数据
- HWND hWnd = ::GetDesktopWindow();
- ASSERT(hWnd);
- HDC hDC = ::GetDC(hWnd);
- if (!::GetDIBits(hDC,(HBITMAP)m_hObject,0,m_pInfo->bmiHeader.biHeight,\
- (LPVOID)((DWORD)lpDib+infosize),(LPBITMAPINFO)lpDib,DIB_RGB_COLORS))
- {
- ::GlobalUnlock(hDib);
- ::GlobalFree(hDib);
- ::CloseClipboard();
- ::ReleaseDC(hWnd, hDC);
- return FALSE;
- }
- ::ReleaseDC(hWnd, hDC);
-
- ::GlobalUnlock(hDib);
-
- // 将DIB数据贴入剪贴板
- if (::SetClipboardData(CF_DIB, hDib))
- {
- // 如果成功,DIB句柄不应释放
- ::CloseClipboard();
- return TRUE; // 成功
- }
- else
- {
- ::GlobalFree(hDib);
- ::CloseClipboard();
- return FALSE; // 失败
- }
- }
- ::GlobalFree(hDib);
- }
- }
- ::CloseClipboard();
- }
-
- return FALSE; // 失败
- }
|