下面这个函数是可以用来绘制半透明区域的
基本的思想是
源位图相应像素和目标位图相应像素计算得到叠加之后的像素RGB值,再绘制即可void CBaseWnd:: DrawSemiTransparentRect(CDC *pDstDC, CRect rtTran, COLORREF clrSrc) {
int nSavedDC = pDstDC->SaveDC();//保存原始DC
int nWidth = rtTran.Width();//半透明区域的宽度
int nHeight = rtTran.Height();//半透明区域的高度
//拷屏 , 新建一个DC来拷贝目标区域
CDC bmpDC;
bmpDC.CreateCompatibleDC(pDstDC);
//创建一个屏幕上现有的相应位置的底图
CBitmap bmp ;
bmp.CreateCompatibleBitmap(pDstDC , nWidth , nHeight);
CBitmap* pOldBmp = (CBitmap*)bmpDC.SelectObject(&bmp);
bmpDC.BitBlt(0 , 0 , nWidth , nHeight , pDstDC , rtTran.left , rtTran.top , SRCCOPY);
//获取bmpDC中的图形数据到BYTE数组存放在pbtPixels中
HDC hDIBDC = CreateCompatibleDC(NULL);
BITMAPINFO hdr;
ZeroMemory(&hdr , sizeof(BITMAPINFO));
hdr.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
hdr.bmiHeader.biWidth = nWidth;
hdr.bmiHeader.biHeight = nHeight;
hdr.bmiHeader.biPlanes = 1;
hdr.bmiHeader.biBitCount = 32;
//这里统一用32位图形 ,原因是32位图形结构相对固定 , 每个
//像素用4个字节表示 。每行末尾不需要添加额外的字节。
//而24位图形 , 每行末尾需要添加额外的字节 , 以保证每行的
//字节数是4的整数倍
//如果想缩减开销和字节数 , 可以采用24位的图形 ,不过就会多
//出一些判断添加额外自己的代码 。
BYTE * pbtPixels = NULL ;
HBITMAP hDIBitmap = CreateDIBSection(hDIBDC,(BITMAPINFO *)&hdr,DIB_RGB_COLORS,(void **)&pbtPixels,NULL,0);
HBITMAP hOldBmp = (HBITMAP)SelectObject(hDIBDC, hDIBitmap);
BitBlt(hDIBDC,0,0,nWidth,nHeight,bmpDC.m_hDC,0,0,SRCCOPY);
SelectObject(hDIBDC, hOldBmp);
//对BYTE数组进行Alpha混和
int nPixelSize = 4 ;//每个像素点用4个字节来存储
BYTE btSR = GetRValue(clrSrc);
BYTE btSG = GetGValue(clrSrc);
BYTE btSB = GetBValue(clrSrc);
for(int i = 0 ; i < nHeight ; i ++)
{
for(int j = 0 ; j < nWidth ; j ++)
{
BYTE btB = pbtPixels[i * nWidth * nPixelSize + j * nPixelSize ] ;
BYTE btG = pbtPixels[i * nWidth * nPixelSize + j * nPixelSize + 1 ] ; BYTE btR = pbtPixels[i * nWidth * nPixelSize + j * nPixelSize + 2 ];
btB = (btSB + btB ) >> 1 ; //btB = btSB * 0.5 + (1-0.5) * btB;
btG = (btSG + btG ) >> 1 ; //btG = btSG * 0.5 + (1-0.5) * btG;
btR = (btSR + btR ) >> 1 ; //btR = btSR * 0.5 + (1-0.5) * btR;
pbtPixels[i * nWidth * nPixelSize + j * nPixelSize ] = btB ;
pbtPixels[i * nWidth * nPixelSize + j * nPixelSize + 1 ] = btG ;
pbtPixels[i * nWidth * nPixelSize + j * nPixelSize + 2 ] = btR ;
}
}
//绘制最终半透明图形到目标区域
SetDIBitsToDevice(pDstDC->GetSafeHdc(),rtTran.left,rtTran.top,nWidth,nHeight,
0,0,0,nHeight,(void*)pbtPixels,(BITMAPINFO*)&hdr,DIB_RGB_COLORS);
//析构和清空
bmpDC.SelectObject(pOldBmp);
bmp.DeleteObject();
delete [] pbtPixels ;
bmpDC.DeleteDC();
DeleteObject(hDIBDC);
DeleteObject(hDIBitmap);
pDstDC->RestoreDC(nSavedDC);//恢复初始DC
pbtPixels=NULL;
}
画透明位图通常的方法是使用遮罩。所谓遮罩就是一张黑白双色的位图,他和要透明的位图是对应的,遮罩描述了位图中需要透明的部分,不透明的部分是黑色的,而透明的是白色的
白色:RGB(255,255,255)
黑色:RGB(0,0,0)
假设图A是要画的透明位图,图B是遮罩。
图A上是一个大写字母Q,字母是红色的,背景是黑色的
遮罩:图B背景是白色的,上面有一个黑色的字母Q和图A的形
状是一样的。
比如我们要在一张蓝天白云的背景上透明地画出字母Q,就是只把红色的字母Q画上去。我们可以先将图B和背景进行与操作,再把图A和背景进行或操作
就可以了。void TransparentBltImage(HDC hdcDest,int nXOriginDest,int nYOriginDest,int nWidthDest,int nHeightDest,HDC hdcSrc,int nXOriginSrc,int nYOriginSrc,int nWidthSrc,int nHeightSrc,UINT crTransparent)
{
HBITMAP hOldImageBMP,hImageBMP = CreateCompatibleBitmap(hdcDest,nWidthDest,nHeightDest);//创建兼容位图
HBITMAP hOldMaskBMP,hMaskBMP = CreateBitmap(nWidthDest,nHeightDest,1,1,NULL); //创建单色掩码位图
HDC hImageDC = CreateCompatibleDC(hdcDest);
HDC hMaskDC = CreateCompatibleDC(hdcDest);
hOldImageBMP = (HBITMAP)SelectObject(hImageDC,hImageBMP);
hOldMaskBMP = (HBITMAP)SelectObject(hMaskDC,hMaskBMP);
//将源DC中的位图拷贝到临时DC中
if (nWidthDest == nWidthSrc && nHeightDest == nHeightSrc)
BitBlt(hImageDC,0,0,nWidthDest,nHeightDest,hdcSrc,nXOriginSrc,nYOriginSrc,SRCCOPY);
else
StretchBlt(hImageDC,0,0,nWidthDest,nHeightDest,hdcSrc,nXOriginSrc,nYOriginSrc,nWidthSrc,nHeightSrc,SRCCOPY);
//设置透明色
SetBkColor(hImageDC,crTransparent);
//生成透明区域为白色,其它区域为黑色的掩码位图
BitBlt(hMaskDC,0,0,nWidthDest,nHeightDest,hImageDC,0,0,SRCCOPY);
//生成透明区域为黑色,其它区域保持不变的位图
SetBkColor(hImageDC,RGB(0,0,0));
SetTextColor(hImageDC,RGB(255,255,255));
BitBlt(hImageDC,0,0,nWidthDest,nHeightDest,hMaskDC,0,0,SRCAND);
//透明部分保持屏幕不变,其它部分变成黑色
SetBkColor(hdcDest,RGB(255,255,255));
SetTextColor(hdcDest,RGB(0,0,0));
BitBlt(hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest,hMaskDC,0,0,SRCAND);
//"或"运算,生成最终效果
BitBlt(hdcDest,nXOriginDest,nYOriginDest,nWidthDest,nHeightDest,hImageDC,0,0,SRCPAINT);
//清理、恢复
SelectObject(hImageDC,hOldImageBMP);
DeleteDC(hImageDC);
SelectObject(hMaskDC,hOldMaskBMP);
DeleteDC(hMaskDC);
DeleteObject(hImageBMP);
DeleteObject(hMaskBMP);
}