Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1469399
  • 博文数量: 218
  • 博客积分: 6394
  • 博客等级: 准将
  • 技术积分: 2563
  • 用 户 组: 普通用户
  • 注册时间: 2008-02-08 15:33
个人简介

持之以恒

文章分类

全部博文(218)

文章存档

2013年(8)

2012年(2)

2011年(21)

2010年(55)

2009年(116)

2008年(16)

分类:

2009-09-18 17:21:30



下面这个函数是可以用来绘制半透明区域的
基本的思想是
源位图相应像素和目标位图相应像素计算得到叠加之后的像素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);
}




阅读(4359) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~