📄 bmpproc.cpp
字号:
BOOL CBmpProc::Create(int width,
int height,
WORD nBitCount,
const void *lpBits)
{
// 检测宽度和高度值
if ((width==0)||(height==0))
return FALSE;
// 检测位数合法性
if (!IsValidDibFormat(nBitCount))
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;
}
/*************************************************************************
*
* 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,则新创建的位不被初始化
*
************************************************************************/
BOOL CBmpProc::CreateCompatible(int width,
int height,
CDC *pDC,
const void *lpBits)
{
// 检测宽度和高度值
if ((width==0)||(height==0))
return FALSE;
int iCurDevBitPix, iCurDevPlanes;
// 获取当前系统显示器的颜色格式(位数和平面数)
HWND hWnd = ::GetDesktopWindow();
ASSERT(hWnd);
if (pDC == NULL)
{
// 如果没有指定设备描述表,则使用当前显示器的颜色格式
HDC hDC = ::GetDC(hWnd);
iCurDevBitPix = GetDeviceCaps(hDC,BITSPIXEL);
iCurDevPlanes = GetDeviceCaps(hDC,PLANES);
::ReleaseDC(hWnd, hDC);
}
else
{
iCurDevBitPix = GetDeviceCaps(pDC->GetSafeHdc(),BITSPIXEL);
iCurDevPlanes = GetDeviceCaps(pDC->GetSafeHdc(),PLANES);
}
// 在16色的系统中,每像素的位数是1,而平面是4,将其颠倒后容易处理
if ((iCurDevPlanes!=1)&&(iCurDevBitPix==1))
{
iCurDevBitPix = iCurDevPlanes;
iCurDevPlanes = 1;
}
// 创建位图(DDB)
return Create(width, height, iCurDevBitPix, lpBits);
}
/*************************************************************************
*
* CopyFromObject()
*
* 参数说明:
*
* CBmpProc& souBmp - 源位图目标
* CRect *pDesRect - 目标矩形
* CRect *pSouRect - 源矩形
*
* 返回值:
*
* BOOL - 如果成功返回TRUE,否则返回FALSE
*
* 描述:
*
* 复制源位图目标中指定区域(矩形)的图像到本身类中图像的指定区域
*
* 如果入口参数pDesRect设为NULL,则目标矩形等于源图像的尺寸
* 如果入口参数pSouRect设为NULL,则源目标矩形等于源图像的尺寸
* 如果入口参数pDesRect和pSouRect不同,该函数可能会产生拉伸或压缩动作
*
* 注:# 本身类中原来必需已存在位图,且调用之后的位图不会被删除
* # 如果源位图类是空的,则返回FALSE
* # 如果本身类中没有位图,则函数返回FALSE
*
************************************************************************/
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;
}
/*************************************************************************
*
* CopyFromHbmp()
*
* 参数说明:
*
* HBITMAP souBmp - 源位图句柄
* CRect *pDesRect - 目标矩形
* CRect *pSouRect - 源矩形
*
* 返回值:
*
* BOOL - 如果成功返回TRUE,否则返回FALSE
*
* 描述:
*
* 复制源位图中指定区域(矩形)的图像到本身类中图像的指定区域
*
* 如果入口参数pDesRect设为NULL,则目标矩形等于源图像的尺寸
* 如果入口参数pSouRect设为NULL,则源目标矩形等于源图像的尺寸
* 如果入口参数pDesRect和pSouRect不同,该函数可能会产生拉伸或压缩动作
*
* 注:# 本身类中原来必需已存在位图,且调用之后的位图不会被删除
* # 如果源位图类是空的,则返回FALSE
* # 如果本身类中没有位图,则函数返回FALSE
*
************************************************************************/
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;
}
/*************************************************************************
*
* CopyTran()
*
* 参数说明:
*
* CBmpProc& souBmp - 源位图目标
* COLORREF crColour - 要滤掉或保留的颜色(缺省值是白色)
* int x - 目标矩形左上角X坐标(缺省值为0)
* int y - 目标矩形左上角Y坐标(缺省值为0)
* CRect *pSouRect - 源矩形(缺省值为NULL)
* int mode - 如果是0则将不拷贝指定的颜色,如果是1则保留指定
* 的颜色(缺省值为0)
*
* 返回值:
*
* BOOL - 如果成功返回TRUE,否则返回FALSE
*
* 描述:
*
* 透明的复制源位图目标中指定矩形的图像到本身类中图像的指定区域
*
* 如果入口参数pSouRect设为NULL,则源目标矩形等于源图像的尺寸。这样该
* 函数将不产生拉伸或压缩动作。
* 如果入口参数pSouRect不设为NULL,该函数会产生拉伸或压缩动作
*
* 注:# 本身类中原来必需已存在位图,且调用之后的位图不会被删除
* # 如果源位图类是空的,则返回FALSE
* # 如果本身类中不存在位图,函数将返回FALSE
*
************************************************************************/
BOOL CBmpProc::CopyTran(CBmpProc& souBmp,
COLORREF crColour,
int x, int y,
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(souBmp.Rect());
dr.OffsetRect(x, y);
return CopyTran(souBmp, crColour, &dr, pSouRect, mode);
}
/*************************************************************************
*
* 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;
}
/*************************************************************************
*
* CopyTranCenter()
*
* 参数说明:
*
* CBmpProc& souBmp - 源位图目标
* CRect* crArea - 居中的范围(缺省值为NULL)
* COLORREF crColour - 要滤掉或保留的颜色(缺省值是白色)
* int mode - 如果是0则将不拷贝指定的颜色,如果是1则保留指定
* 的颜色(缺省值为0)
*
* 返回值:
*
* BOOL - 如果成功返回TRUE,否则返回FALSE
*
* 描述:
*
* 将源位图透明的复制到本类中指定矩形的中央
*
* 如果入口参数crArea设为NULL,则居中矩形等于本身类中图像的尺寸。
* 该函数不会产生拉伸或压缩动作。
*
* 注:# 本身类中原来必需已存在位图,且调用之后的位图不会被删除
* # 如果源位图类是空的,则返回FALSE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -