#ifndef __MEMORYDC_H__
#define __MEMORYDC_H__
class CMemoryDC : public CDC
{
public:
CMemoryDC() { }
CMemoryDC(int cx, int cy, CDC* pDC = nullptr);
CMemoryDC(int nID, CDC* pDC = nullptr);
CMemoryDC(LPCTSTR szBitmapFile, CDC* pDC = nullptr);
~CMemoryDC();
public:
inline int GetWidth() const { return m_size.cx; }
inline int GetHeight() const { return m_size.cy; }
public:
BOOL DeleteDC();
BOOL CreateBitmap(int cx, int cy, CDC* pDC = nullptr);
BOOL LoadBitmap(LPCTSTR szBitmapFile, CDC* pDC = nullptr);
BOOL LoadBitmap(int nID, CDC* pDC = nullptr);
void MakeRgn(CRgn& rgn, COLORREF clTrans);
void BitTrans(int nXDest, int nYDest, int nWidthDest, int nHeightDest, CDC* pDestDC, int nXSrc, int nYSrc, COLORREF clTrans);
void StretchTrans(int nXDest, int nYDest, int nWidthDest, int nHeightDest, CDC* pDestDC, int nXSrc, int nYSrc, int nWidthSrc,
int nHeightSrc, COLORREF clTrans);
private:
CSize m_size;
};
#endif // __MEMORYDC_H__
#include "MemoryDC.h"
#include "MemoryDC.h"
CMemoryDC::CMemoryDC(int cx, int cy, CDC* pDC)
{
CreateBitmap(cx, cy, pDC);
}
CMemoryDC::CMemoryDC(int nID, CDC* pDC)
{
LoadBitmap(nID, pDC);
}
CMemoryDC::CMemoryDC(LPCTSTR szBitmapFile, CDC* pDC)
{
LoadBitmap(szBitmapFile, pDC);
}
CMemoryDC::~CMemoryDC()
{
DeleteDC();
}
BOOL CMemoryDC::DeleteDC()
{
if (!GetSafeHdc()) return TRUE;
CBitmap* pBitmap = GetCurrentBitmap();
pBitmap->DeleteObject();
return CDC::DeleteDC();
}
BOOL CMemoryDC::CreateBitmap(int cx, int cy, CDC* pDC)
{
CClientDC dc(nullptr);
if (!pDC) pDC = &dc;
CBitmap bmp;
if (!bmp.CreateCompatibleBitmap(pDC, cx, cy))
return FALSE;
if (!GetSafeHdc() && !pDC->CreateCompatibleDC(pDC))
return FALSE;
SelectObject(&bmp);
m_size = { cx, cy };
return TRUE;
}
BOOL CMemoryDC::LoadBitmap(int nID, CDC* pDC)
{
CBitmap bmp;
if (!bmp.LoadBitmap(nID))
return FALSE;
if (!GetSafeHdc() && !pDC->CreateCompatibleDC(pDC))
return FALSE;
BITMAP bm;
bmp.GetBitmap(&bm);
m_size = { bm.bmWidth, bm.bmHeight };
return TRUE;
}
void CMemoryDC::MakeRgn(CRgn& rgn, COLORREF clTrans)
{
rgn.DeleteObject();
rgn.CreateRectRgn(0, 0, 0, 0); // 在窗口(0, 0)出创建一个面积为0的区域
int i = GetWidth(); // 获取PaintDC的宽度
while (i-- > 0)
{
int j = GetHeight(); // 获取PaintDC的高度
while (j-- > 0)
{ // PaintDC上像素颜色与将要转化为透明区域的颜色一致, 到下一处像素点比较颜色
if (GetPixel(i, j) == clTrans) continue;
CRgn r;
r.CreateRectRgn(i, j, i + 1, j + 1); // 建立一个像素点大小的区域
r.CombineRgn(&r, &rgn, RGN_OR); // 将该像素点并入区域r
}
}
}
BOOL CMemoryDC::LoadBitmap(LPCTSTR szBitmapFile, CDC* pDC)
{
CClientDC dc(nullptr);
if (!pDC) pDC = &dc;
if (!szBitmapFile) return FALSE;
HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, szBitmapFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (!hBitmap) return FALSE;
BITMAP bm;
GetObject(hBitmap, sizeof(bm), &bm);
CreateCompatibleDC(pDC);
SelectObject(hBitmap);
DeleteObject(hBitmap);
m_size = { bm.bmWidth, bm.bmHeight };
return TRUE;
}
void CMemoryDC::BitTrans(int nXDest, int nYDest, int nWidthDest, int nHeightDest, CDC* pDestDC, int nXSrc, int nYSrc, COLORREF clTrans)
{
// 产生前景图的兼容DC 前景图紫色背景彩色图形
CMemoryDC dcFrontImage(nWidthDest, nHeightDest, pDestDC);
dcFrontImage.SetBkColor(clTrans);
dcFrontImage.BitBlt(0, 0, nWidthDest, nHeightDest, this, nXSrc, nYSrc, SRCCOPY);
// 产生前景掩码图的兼容DC 掩码图 (要消去的区域为白色, 要留下的区域为黑色)
CBitmap bmpMask;
bmpMask.CreateBitmap(nWidthDest, nHeightDest, 1, 1, NULL); // 构造单色掩码图(像素点非黑即白)
CDC dcMask;
dcMask.CreateCompatibleDC(pDestDC);
dcMask.SelectObject(&bmpMask);
dcMask.BitBlt(0, 0, nWidthDest, nHeightDest, &dcFrontImage, nXSrc, nYSrc, SRCCOPY);
// 指定前景图的背景颜色与前景颜色
dcFrontImage.SetBkColor(RGB(0, 0, 0)); // 前景图要消去的区域设置黑色 0x000000
dcFrontImage.SetTextColor(RGB(255, 255, 255)); // 前景图要保留的区域设置白色 0xFFFFFF
// 掩码图同前景图做与运算
// 掩码图白色区域与前景图要消去的黑色区域 0xFFFFFF & 0x000000 = 0 黑白抵消, 前景图要消去的区域变为黑色
// 掩码图黑色区域与前景图要保留的偏白区域 0x000000 & 0xFFFFFF = 0 黑白抵消, 前景图要保留的彩色区域恢复原色
dcFrontImage.BitBlt(0, 0, nWidthDest, nHeightDest, &dcMask, nXSrc, nYSrc, SRCAND); // 前景图黑色背景彩色图形
// 掩码图同背景图做与运算 背景图被前景图覆盖的区域,每个像素的颜色为0xXXXXXX
// 掩码图的白色区域与背景图 0xFFFFFF & 0xXXXXXX = 0xXXXXXX, 白色区域消去, 被白色遮罩的背景显露出来
// 掩码图的黑色区域与背景图 0x000000 & 0xXXXXXX = 0x000000, 黑色区域保留, 背景的一部分被黑色遮罩住
pDestDC->BitBlt(nXDest, nYDest, nWidthDest, nHeightDest, &dcMask, nXSrc, nYSrc, SRCAND); // 背景图被掩码图黑色图形遮罩
// 前景图要消去的区域为黑色, 背景图对应的区域为任意颜色 0x000000 | 0xXXXXXX = 0xXXXXXX 保留对应区域的背景颜色
// 前景图要保留的区域为彩色, 背景图对应的区域为黑色 0xXXXXXX | 0x000000 = 0xXXXXXX 保留对应区域的前景颜色
pDestDC->BitBlt(nXDest, nYDest, nWidthDest, nHeightDest, &dcFrontImage, nXSrc, nYSrc, SRCPAINT); // 背景图被前景图的彩色图形遮罩
}
void CMemoryDC::StretchTrans(int nXDest, int nYDest, int nWidthDest, int nHeightDest, CDC* pDestDC, int nXSrc, int nYSrc,
int nWidthSrc, int nHeightSrc, COLORREF clTrans)
{
// 产生前景图的兼容DC
CMemoryDC dcFrontImage(nWidthDest, nHeightDest, pDestDC);
dcFrontImage.SetBkColor(clTrans);
if (nWidthDest == nWidthSrc && nHeightDest == nHeightSrc)
dcFrontImage.BitBlt(0, 0, nWidthDest, nHeightDest, this, nXSrc, nYSrc, SRCCOPY);
else
dcFrontImage.StretchBlt(0, 0, nWidthDest, nHeightDest,
this, nXSrc, nYSrc, nWidthSrc, nHeightSrc, SRCCOPY);
// 产生前景掩码图的兼容DC 掩码图 (要消去的区域为白色, 要留下的区域为黑色)
CBitmap bmpMask;
bmpMask.CreateBitmap(nWidthDest, nHeightDest, 1, 1, NULL); // 构造单色掩码图(像素点非黑即白)
CDC dcMask;
dcMask.CreateCompatibleDC(pDestDC);
dcMask.SelectObject(&bmpMask);
dcMask.BitBlt(0, 0, nWidthDest, nHeightDest, &dcFrontImage, nXSrc, nYSrc, SRCCOPY);
// 指定前景图的背景颜色与前景颜色
dcFrontImage.SetBkColor(RGB(0, 0, 0)); // 前景图要消去的区域设置黑色 0x000000
dcFrontImage.SetTextColor(RGB(255, 255, 255)); // 前景图要保留的区域设置白色 0xFFFFFF
// 掩码图同前景图做与运算
// 掩码图白色区域与前景图要消去的黑色区域 0xFFFFFF & 0x000000 = 0 黑白抵消, 前景图要消去的区域变为黑色
// 掩码图黑色区域与前景图要保留的白色区域 0x000000 & 0xFFFFFF = 0 黑白抵消, 前景图要保留的彩色区域恢复原色
dcFrontImage.BitBlt(0, 0, nWidthDest, nHeightDest, &dcMask, nXSrc, nYSrc, SRCAND);
// 掩码图同背景图做与运算 背景图视为非黑色即为非零
// 掩码图的白色区域与背景图 0xFFFFFF & 0xXXXXXX = 0xXXXXXX, 白色区域消去, 被白色遮罩的背景显露出来
// 掩码图的黑色区域与背景图 0x000000 & 0xXXXXXX = 0x000000, 黑色区域保留, 背景的一部分被黑色遮罩住
pDestDC->BitBlt(nXDest, nYDest, nWidthDest, nHeightDest, &dcMask, nXSrc, nYSrc, SRCAND);
// 前景图要消去的区域为黑色, 背景图对应的区域为任意颜色 0x000000 | 0xXXXXXX = 0xXXXXXX 保留对应区域的背景颜色
// 前景图要保留的区域为彩色, 背景图对应的区域为黑色 0xXXXXXX | 0x000000 = 0xXXXXXX 保留对应区域的前景颜色
pDestDC->BitBlt(nXDest, nYDest, nWidthDest, nHeightDest, &dcFrontImage, nXSrc, nYSrc, SRCPAINT);
}