透明位图的三种做法(转)

http://www.handytech.cn/main/ArticleShow_38.htm
在编程中我们都希望程序的界面能够尽可能的美观,因此可以在程序中使用位图资源。但是位图是一个矩形阵列,在显示时总是以矩形形式显示,有什么方法能够让位图也显示成为不规则式样呢(即位图中有的颜色不显示在屏幕上)?在这里介绍几种透明位图的创建方法:


注:下列代码都是在CView类的OnDraw(CDC*pDC)函数中的源代码


一、

源代码:

 void AnomalyBitmap(CDC*pDC,int nX,int nY,int nBitmapID)
{                   
        CDC dcMem; 
 CBitmap bitmap,combmp;
 BITMAP bp;
 dcMem.CreateCompatibleDC(pDC);                                  //创建内存兼容设备描述表
 bitmap.LoadBitmap(nBitmapID);                              
 bitmap.GetBitmap(&bp);
 combmp.CreateCompatibleBitmap(pDC,bp.bmWidth,bp.bmHeight);
 dcMem.SelectObject(&combmp);
 dcMem.BitBlt(0,0,bp.bmWidth,bp.bmHeight,pDC,0,0,SRCCOPY);
 dcMem.DrawState(CPoint(0,0),CSize(bp.bmWidth,bp.bmHeight),&bitmap,DSS_NORMAL);
  pDC->DrawState(CPoint(nX,nY),CSize(bp.bmWidth,bp.bmHeight),&bitmap,DSS_MONO,&CBrush(RGB(255,255,255)));
 pDC->BitBlt(nX,nY,bp.bmWidth,bp.bmHeight,&dcMem,0,0,SRCAND);
}
   
原理:
     采用这种方法一定要将位图不想显示的部分用白色填充。
当程序执行到10行时,会将位图复制到内存兼容设备的(0,0)位置
当程序执行到11行时,这是关键的一步,会在显示设备指定位置画一张单色位图,这时位图中的白色将不会显示了,而将位图中的非白色全部用画刷指定的颜色来填充,这里的指定颜色为白色,即位图要显示的部分已经成白色了,而不要显示的部分(原来白色部分)则显示成原来屏幕的颜色了
当程序执行到12行时,将内存中的位图与屏幕上的位图做与操作并显示在屏幕上,因为任何颜色跟白色(RGB值为0x00ffffff)做与运算都将保持其原来的颜色,因此内存中的位图中的要显示的部分将会与屏幕上的要显示部分(此时为白色)做与操作时将会保留内存中的颜色,而内存中的白色部分(不要显示部分)将与屏幕上原来的颜色(11步已经将屏幕上不要显示的白色转换成原来颜色)做与运算而得到屏幕上原来的颜色了.这样就实现了位图的不规则显示.但是这种方法有一个缺陷即一旦位图中有白色都将不会显示在屏幕上,因此这种方法不适合有些部分要显示白色的位图.


二、

原理:
   上面的方法中一旦位图中有白色则会屏蔽掉,不显示出来。因此我们可以建立一张与彩色位图对应的单色位图,我们称之为掩膜,并将掩膜要显示的部分填为白色,而屏蔽的部分填为黑色,同时彩色位图中不显示的部分任用白色填充。
同时将掩膜位图与屏幕做位或运算,然后在将彩色位图与屏幕做位与运算即可。因为将掩膜与屏幕做或运算时屏幕上要显示的部分变为白色,而屏蔽的部分则变屏幕颜色不变,此时再将彩色位图与屏幕做与运算则会有屏幕要显示的部分变为彩色位图要显示的部分,而彩色位图不要显示的部分则维持屏幕的颜色不变。这种方法可以克服第一种的缺陷,但是缺点是还要画一张掩膜位图(此张掩膜必须要为16色)。

源代码:
       void AnomalyBitmap(CDC*pDC,int nX,int nY,int nBitmapID,int nMaskID)
 {
         CDC dcMem,dcMask;
  CBitmap colorbitmap,maskbitmap;
  BITMAP bp;
  dcMem.CreateCompatibleDC(pDC);
  dcMask.CreateCompatibleDC(pDC);
  colorbitmap.LoadBitmap(nBitmapID);
  maskbitmap.LoadBitmap(nMaskID);
     colorbitmap.GetBitmap(&bp);
  dcMem.SelectObject(&colorbitmap);
  dcMask.SelectObject(&maskbitmap);
  pDC->BitBlt(nX,nY,bp.bmWidth,bp.bmHeight,&dcMask,0,0,SRCPAINT);
  pDC->BitBlt(nX,nY,bp.bmWidth,bp.bmHeight,&dcMem,0,0,SRCAND);
        }

三、

原理:
    上面第一种方法只能指定白色为屏蔽色,因此有一定的局限性,可不可以将任意一种颜色指定为屏蔽色呢?
因为掩膜位图只有两种颜色0x00000000为前景色黑色,0x00ffffff为背景色白色,可以将彩色位图转化成为掩膜位图,也可以掩膜位图转化成为彩色位图,这可以利用CDC类的两个成员函数:
COLORREF SetBkColor( COLORREF crColor );
COLORREF SetTextColor(COLORREF crColor);
在彩色位图转换成为掩膜位图时就会将SetBkColor指定的颜色转换为掩膜中的背景色白色,同样会将SetTextColor指定的颜色转换为掩膜的前景色黑色。例如:若将一彩色位图中的黄色设置为背景色,则此彩色位图转换成为掩膜位图时,黄颜色都会转化成为白色而其他颜色则转换成为黑色。

在掩膜位图转化成为彩色位图时就会将黑色转化为SetTextColor指定的颜色,而将白色转化为SetBkColor指定的颜色。
因为在位图中没有这两个函数,所以要将位图装入设备描述表中以后才能进行转化。这种方法跟第一种方法的缺陷一样,但是确可以指定屏蔽的颜色,而不象第一种只能将白色作为屏蔽的颜色.

源代码:
    void AnomalyBitmap(CDC*pDC,int nX,int nY,int nBitmapID,COLORREF maskcolor)
{
 COLORREF crOldText,crOldBk;
        CDC dcMem,dcMask;
 CBitmap colorbitmap,maskbitmap;
 BITMAP bp;
 dcMem.CreateCompatibleDC(pDC);
 dcMask.CreateCompatibleDC(pDC);
  colorbitmap.LoadBitmap(nBitmapID);
        colorbitmap.GetBitmap(&bp);
 maskbitmap.CreateBitmap(bp.bmWidth,bp.bmHeight,1,1,NULL);
  dcMem.SelectObject(&colorbitmap);
 dcMask.SelectObject(&maskbitmap);
  dcMem.SetBkColor(maskcolor);
 dcMask.BitBlt(0,0,bp.bmWidth,bp.bmHeight,&dcMem,0,0,SRCCOPY);
          //将彩色位图中maskcolor颜色指定为掩膜位图中的白色,其他颜色转化为黑色(要显示的为黑,屏蔽部分为白)
 dcMem.SetTextColor(RGB(255,255,255));
 dcMem.SetBkColor(RGB(0,0,0));
 dcMem.BitBlt(0,0,bp.bmWidth,bp.bmHeight,&dcMask,0,0,SRCAND);
           //将掩膜位图中的颜色反转再与彩色位图做与运算(此时彩色位图要显示的部分为彩色,屏蔽的部分为黑)
 crOldText=pDC->SetTextColor(RGB(0,0,0));
 crOldBk=pDC->SetBkColor(RGB(255,255,255));
 pDC->BitBlt(nX,nY,bp.bmWidth,bp.bmHeight,&dcMask,0,0,SRCAND);
          //将掩膜与屏幕做与运算(此时屏幕要显示的为黑,屏蔽的部分保留原来颜色)
 pDC->BitBlt(nX,nY,bp.bmWidth,bp.bmHeight,&dcMem,0,0,SRCPAINT);
           //将彩色位图与屏幕做或运算(获得了不规则位图,并输出)
 pDC->SetTextColor(crOldText);
 pDC->SetBkColor(crOldBk);

}

说明:
可以将函数放在类中并做一定的修改,则可以加速程序的运行,并通过更改,显示为可变大小的透明位图
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值