透明位图的显示 SRCINVERT 掩码图

透明位图的显示 SRCINVERT 掩码图

(2012-07-17 15:04:13)
标签:

it

分类: 软件_Software

掩码图是指一幅图,将需要保留的图象用一种颜色来表示,这种颜色一般选原图中没有的颜色,  
然后将原图与掩码图做位与操作,可将原图中需要的图形扣出来。

1。将hdc中的图片贴到dctrans中,如果dctrans中已经有图片,则采用覆盖的方式。  
2。将hdc中的图片贴到dcm中,如果dcm中已经有图片,则采用取反的方式。  
3。将dctrans中的图片贴到dcm中,如果dcm中已经有图片,则采用按位与的方式。  
4。将hdc中的图片贴到dcm中,如果dcm中已经有图片,则采用取反的方式。  
SRCINVERT、SRCAND等都是光栅操作。就是说,如果原来有图片,那么新的图片贴到原来的图片上时,两个图片采用怎样的结合方式。这样,我们就会有透明啊,伪彩色等等很多种的图像效果。

 

实现透明位图,有一个知识点必须要提前知道,那就是:

如果一个单色位图向彩色位图转换,那么单色位图为1的部分(也就是白色部分),会转换为彩色位图的背景色,单色位图为0的部分(黑色部分),会转换为彩色位图的背景色。
如果一个彩色位图向单色位图转换,那么彩色位图的背景色转换到单色位图中则为1(白色),其他的则转换为0(黑色)。//好像这一点不太正确,背景色应该转换为透明即新设备底色
当然上面的1和0都是指bit位的值,还有这些转换是在设备上下文间的块数据操作前就进行的。
由于windows上所有的位图操作都是基于内存设备上下文的,所以我们还需要创建两个设备上下文分别用于存放源位图和“掩码”位图。
位图在设备上下文之间块数据传递需要通过Biltblt实现,对于这个函数和关于bitblt的最后一个参数的光栅操作的具体含义的介绍,这里就不再赘述,具体可看MSDN上关于bilblt的描述。
接下去直接看代码,在代码中再通过注释对一些细节进行详细的描述。

CBitmap btfile;
 btfile.LoadBitmap(IDB_BITMAP1);
 
 BITMAP btinfo;
 btfile.GetBitmap(&btinfo); //获取源位图的大小等信息
 
 CClientDC dcClient(this);
 CDC dcImage, dcMask;
    //分别创建对预显示位图的DC的兼容DC
 dcImage.CreateCompatibleDC(&dcClient);
 dcMask.CreateCompatibleDC(&dcClient);
 
 CBitmap btSingleColor;
    //创建单色位图
 btSingleColor.CreateBitmap(btinfo.bmWidth, btinfo.bmHeight, 1, 1, NULL);
    //载入源位图
 dcImage.SelectObject(&btfile);
 //VC默认的背景色白色
    //设置背景色,也就是源位图的透明色
    dcImage.SetBkColor(RGB(0,255,0));//如何才能知道一副图片的前景色和背景色…… by ralf
    //载入单色位图
 dcMask.SelectObject(&btSingleColor);
 //这里DC之间的块数据拷贝就用到了开头提到的知识点,从彩色位图向单色位图转换,
 //源位图的背景图拷到掩码DC中后变为白色,其他则为黑色
 dcMask.BitBlt(0, 0, btinfo.bmWidth, btinfo.bmHeight, &dcImage, 0, 0, SRCCOPY);
     
 //设置显示DC的背景色和前景色
 COLORREF color1 = dcClient.SetBkColor(RGB(255, 255, 255));//RGB ( 255, 255,255 )为白色,亮度最高//RALF  这样是不是制作了一个空空的白图片啊,亲人无论COLORREF color1 = dcClient.SetBkColor(RGB(0,0, 0));中RGB的参数是啥,最后的图片都是白的啊,是不是这样呢,如果真是这样的话,就可以讲通了……
 COLORREF color2 = dcClient.SetTextColor(RGB(0, 0, 0));//RGB ( 0, 0, 0 )为黑色,亮度最低
 // SRCINVERT:这个ROP代表异或位操作,SRCAND:代表与操作
 //如果对一数据做两次异或操作,那么数据将恢复到原数据,跟没操作一样
 //透明位图就是利用这个特性,将源位图异或的方式拷贝到显示DC两次
 //但是只拷贝两次的话,那么源位图将不显示,换种说法就是整张位图都被透明了
 //这可不是我们想要的结果,我们的目的只是将背景色透明,所以我们还需要在这两次
 //异或操作中加入其他操作来实现我们想要的结果,这时候就需要上面准备的“掩码”
 //DC来帮忙了
 dcClient.BitBlt(0, 0, btinfo.bmWidth, btinfo.bmHeight, &dcImage, 0, 0, SRCINVERT);//by ralf 注意:0和别人异或不变
 
// dcClient.BitBlt(0, 0, btinfo.bmWidth, btinfo.bmHeight, &dcImage, 0, 0, SRCINVERT);//add by ralf 完全拷贝
 
    //解决这个问题其实很简单,就是维持背景色不变,这样它在下次异或操作后会恢复源
 //数据,被透明了;然后将前景色变黑。
    //掩码DC内的单色位图为1的部分,将会转换为显示DC的背景色,为0的部分转换
 //为显示DC的前景色,然后再与显示DC的块数据做与(SRCAND)操作,在位操作后,
 //背景色维持不变,前景色为0(黑色)
 dcClient.BitBlt(0, 0, btinfo.bmWidth, btinfo.bmHeight, &dcMask, 0, 0, SRCAND);


    //然后源数据DC再与显示DC的数据块再做一次异或操作的,背景色恢复为显示DC
 //的图像数据,前景色则显示为源数据DC内的图像数据(0^1 = 1)//这里注意:0和别人异或不变  by ralf
 dcClient.BitBlt(0, 0, btinfo.bmWidth, btinfo.bmHeight, &dcImage, 0, 0, SRCINVERT);
 //恢复显示DC的前景和背景色
 dcClient.SetBkColor(color1);
 dcClient.SetTextColor(color2);
——————————————————————————————————

CRect rect;
GetClientRect(&rect);
int nWidth=rect.Width(),nHeight=rect.Height();
//COLORREF srcbkcolor=pDC->GetBkColor();
CBitmap *lineimage=new CBitmap;
dcImage->CreateCompatibleDC(pDC);
lineimage->CreateCompatibleBitmap(pDC,nWidth,nHeight);

 

OnPrepareDC(dcImage,NULL);
CBrush brushBkColor;
brushBkColor.CreateSolidBrush(RGB(255,255,255));   
CBitmap* pOldBitmapImage=dcImage->SelectObject(lineimage);
dcImage->FillRect(rect,&brushBkColor);//填充位图数据,默认为白色
//dcImage->SetBkColor(RGB(255,255,255));
dcImage->Ellipse(CRect(120,120,200,200));

//pDC->BitBlt(0, 0, nWidth, nHeight, dcImage, 0, 0, SRCCOPY);

dcImage->SetBkColor(RGB(255,255,255));//设置透明色
dcMask->CreateCompatibleDC(pDC);
OnPrepareDC(dcMask,NULL);
CBitmap bitmapMask;   //掩码位图
bitmapMask.CreateBitmap(nWidth, nHeight, 1, 1, NULL);
CBitmap* pOldBitmapMask = dcMask->SelectObject(&bitmapMask);

dcMask->BitBlt(0, 0, nWidth, nHeight, dcImage, 0, 0, SRCCOPY);//分3步进行实际的绘   
pDC->BitBlt(0, 0, nWidth, nHeight, dcImage, 0, 0, SRCINVERT); //原图像数据和目标数据异或
pDC->BitBlt(0, 0, nWidth, nHeight, dcMask, 0, 0, SRCAND);   //原图像数据和目标数据相与
pDC->BitBlt(0, 0, nWidth, nHeight, dcImage, 0, 0, SRCINVERT); //恢复原先设置   
dcImage->SelectObject(pOldBitmapImage);  
dcMask->SelectObject(pOldBitmapMask);
ReleaseDC(dcImage);
ReleaseDC(dcMask);

___________________________________________________________

初始化位图时有一下两种选择 1.单色位图  2.彩色位图   虽然现视出来都是黑色但是两者大大有区别
Bitmap.CreateBitmap(x,y,1,1,null);//单色

Bitmap.CreateCompatibleBitmap(pDC,x,y);//彩色


把不同位图选入dc时,dc会有不同的效果。当选入单色位图时,dc会被初始化为单色的,选入彩色位图时,dc会被初始化为彩色的,单色dc只能显示两种颜色(黑白),彩色dc那就能显示彩色图像,

当把彩色位图选入单色dc时,彩色位图的背景色会变为白色,前景色会变为黑色

利用这种效果,可以把彩色位图的背景色变为白的色


 
》》》》》》》》》》》》》》》》》》》》》》》》》》》

 

透明位图的显示

 

包含透明色的位图的绘制方法有多种,最简单的方法是调用现成的函数:TransparentBlt,也可以通过自己的代码实现类似TransparentBlt的功能,实现过程也有两种形式,一种是事先做一张掩码位图,另一种是动态生成掩码位图。本文将介绍动态生成掩码位图绘制具有透明区域位图的方法。

一、TransparentBlt 函数的使用

TransparentBlt 函数在Windows98/Windows2000以上版本运行,系统中需要包含 Msimg32.dll,使用时可以链接 Msimg32.lib。

Windows98下的TransparentBlt会产生资源泄漏,所以不建议在WIN98下使用该函数。

TransparentBlt函数原型如下:

BOOL TransparentBlt(HDC hdcDest, // 目标DCint nXOriginDest, // 目标X偏移int nYOriginDest, // 目标Y偏移int nWidthDest, // 目标宽度int hHeightDest, // 目标高度HDC hdcSrc, // 源DCint nXOriginSrc, // 源X起点int nYOriginSrc, // 源Y起点int nWidthSrc, // 源宽度int nHeightSrc, // 源高度UINT crTransparent // 透明色,COLORREF类型);

 

使用示例:

CBitmap FootballBMP;FootballBMP.LoadBitmap(IDB_FOOTBALLBMP);CDC ImageDC;ImageDC.CreateCompatibleDC(pDC);CBitmap *pOldImageBMP = ImageDC.SelectObject(&FootballBMP);TransparentBlt(pDC->m_hDC, 0, 0, 218, 199, ImageDC.m_hDC, 0, 0, 218, 199, RGB(0,0,0xff));ImageDC.SelectObject(pOldImageBMP);

 

二、实现TransparentBlt函数

为了理解具有透明色位图的绘制过程,我们来亲手建立一个具有同TransparentBlt功能一致的实验函数,称之为TransparentBlt2。

实验素材:有两张位图:bk.bmp是背景位图,football.bmp包含透明区域,透明色为蓝色RGB(0,0,0xff)

实验目的:以bk.bmp为背景,将football.bmp绘制到背景中,形成如下的最终效果图。

 

2.1 透明位图绘制原理

假设football.bmp ->载入 HBITMAP hImageBMP -> 选入 HDC hImageDC

2.1.1 生成足球的单色掩码位图,透明区域为白色(全1),非透明区域为黑色(全0)

HBITMAP hMaskBMP = CreateBitmap(nWidthDest, nHeightDest, 1, 1, NULL); // 建立单色位图SetBkColor(hImageDC, RGB(0,0,0xff)); // 设置背景色为蓝色BitBlt(hMaskDC, 0, 0, nWidthDest, nHeightDest, hImageDC, 0, 0, SRCCOPY); // 拷贝到hMaskDC这样足球位图中蓝色区域在掩码位图中成了白色,其它区域为黑色,此时hMaskBMP 如下图:

 (图一)

2.1.2 设置背景色为黑色,前景色为白色,将掩码位图(图一)与足球位图相"与"

SetBkColor(hImageDC, RGB(0,0,0));SetTextColor(hImageDC, RGB(255,255,255));BitBlt(hImageDC, 0, 0, nWidthDest, nHeightDest, hMaskDC, 0, 0, SRCAND);这样,掩码位图中背景色(黑色)的区域在hImageBMP中被保留,前景色(白色)的部分变为黑色。此时hImageBMP 如下图:

 (图二)

2.1.3 设置背景色为白色,前景色为黑色,将掩码位图(图一)与背景进行“与”运算

SetBkColor(hdcDest,RGB(255,255,255));SetTextColor(hdcDest,RGB(0,0,0));BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hMaskDC, 0, 0, SRCAND);掩码中白色区域(数据与1相“与”结果不变)使背景保持不变,黑色区域变成黑色,此时背景显示如下:

 (图三)

2.1.4 将hImageBMP(图二)与背景(图三)进行“或”运算

BitBlt(hdcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, hImageDC, 0, 0, SRCPAINT);这样就将足球绘制到背景上了。

2.2 TransparentBlt2函数全部实现代码

void TransparentBlt2( HDC hdcDest,      // 目标DC
      int nXOriginDest,   // 目标X偏移
      int nYOriginDest,   // 目标Y偏移
      int nWidthDest,     // 目标宽度
      int nHeightDest,    // 目标高度
      HDC hdcSrc,         // 源DC
      int nXOriginSrc,    // 源X起点
      int nYOriginSrc,    // 源Y起点
      int nWidthSrc,      // 源宽度
      int nHeightSrc,     // 源高度
      UINT crTransparent  // 透明色,COLORREF类型
      )
{
 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);
}

 

2.3 TransparentBlt的另外一个版本:TransparentBltU

TransparentBltU是Christian Graus 在WinDEV发表的一个函数,功能与TransparentBlt一致,以下是全部实现代码:

bool TransparentBltU( HDC dcDest, // handle to Dest DC int nXOriginDest, // x-coord of destination upper-left corner int nYOriginDest, // y-coord of destination upper-left corner int nWidthDest, // width of destination rectangle int nHeightDest, // height of destination rectangle HDC dcSrc, // handle to source DC int nXOriginSrc, // x-coord of source upper-left corner int nYOriginSrc, // y-coord of source upper-left corner int nWidthSrc, // width of source rectangle int nHeightSrc, // height of source rectangle UINT crTransparent // color to make transparent )

{

 if (nWidthDest < 1) return false;

if (nWidthSrc < 1) return false;

if (nHeightDest < 1) return false;

if (nHeightSrc < 1) return false;

HDC dc = CreateCompatibleDC(NULL);

HBITMAP bitmap = CreateBitmap(nWidthSrc, nHeightSrc, 1, GetDeviceCaps(dc, BITSPIXEL), NULL);

if (bitmap == NULL) { DeleteDC(dc); return false; } HBITMAP oldBitmap = (HBITMAP)SelectObject(dc, bitmap);

if (!BitBlt(dc, 0, 0, nWidthSrc, nHeightSrc, dcSrc, nXOriginSrc, nYOriginSrc, SRCCOPY))

{ SelectObject(dc, oldBitmap);

DeleteObject(bitmap);

DeleteDC(dc);

return false; }

 

HDC maskDC = CreateCompatibleDC(NULL);

HBITMAP maskBitmap = CreateBitmap(nWidthSrc, nHeightSrc, 1, 1, NULL);

if (maskBitmap == NULL)

{ SelectObject(dc, oldBitmap);

DeleteObject(bitmap);

DeleteDC(dc);

DeleteDC(maskDC);

return false; }

 

HBITMAP oldMask = (HBITMAP)SelectObject(maskDC, maskBitmap);

SetBkColor(maskDC, RGB(0,0,0));

SetTextColor(maskDC, RGB(255,255,255));

if (!BitBlt(maskDC, 0,0,nWidthSrc,nHeightSrc,NULL,0,0,BLACKNESS))

{ SelectObject(maskDC, oldMask);

DeleteObject(maskBitmap);

DeleteDC(maskDC);

SelectObject(dc, oldBitmap);

DeleteObject(bitmap);

DeleteDC(dc);

return false; }

 

SetBkColor(dc, crTransparent);

BitBlt(maskDC, 0,0,nWidthSrc,nHeightSrc,dc,0,0,SRCINVERT);

SetBkColor(dc, RGB(0,0,0));

SetTextColor(dc, RGB(255,255,255));

BitBlt(dc, 0,0,nWidthSrc,nHeightSrc,maskDC,0,0,SRCAND);

HDC newMaskDC = CreateCompatibleDC(NULL);

HBITMAP newMask;

newMask = CreateBitmap(nWidthDest, nHeightDest, 1, GetDeviceCaps(newMaskDC, BITSPIXEL), NULL);

if (newMask == NULL) { SelectObject(dc, oldBitmap); DeleteDC(dc); SelectObject(maskDC, oldMask); DeleteDC(maskDC);

DeleteDC(newMaskDC);

DeleteObject(bitmap);

DeleteObject(maskBitmap);

return false; }

 

SetStretchBltMode(newMaskDC, COLORONCOLOR);

HBITMAP oldNewMask = (HBITMAP) SelectObject(newMaskDC, newMask);

StretchBlt(newMaskDC, 0, 0, nWidthDest, nHeightDest, maskDC, 0, 0, nWidthSrc, nHeightSrc, SRCCOPY); SelectObject(maskDC, oldMask);

DeleteDC(maskDC);

DeleteObject(maskBitmap);

HDC newImageDC = CreateCompatibleDC(NULL);

HBITMAP newImage = CreateBitmap(nWidthDest, nHeightDest, 1, GetDeviceCaps(newMaskDC, BITSPIXEL), NULL);

if (newImage == NULL) { SelectObject(dc, oldBitmap);

DeleteDC(dc);

DeleteDC(newMaskDC);

DeleteObject(bitmap);

return false; }

 

HBITMAP oldNewImage = (HBITMAP)SelectObject(newImageDC, newImage);

StretchBlt(newImageDC, 0, 0, nWidthDest, nHeightDest, dc, 0, 0, nWidthSrc, nHeightSrc, SRCCOPY); SelectObject(dc, oldBitmap);

DeleteDC(dc); DeleteObject(bitmap);

BitBlt( dcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, newMaskDC, 0, 0, SRCAND);

BitBlt( dcDest, nXOriginDest, nYOriginDest, nWidthDest, nHeightDest, newImageDC, 0, 0, SRCPAINT); SelectObject(newImageDC, oldNewImage);

DeleteDC(newImageDC);

SelectObject(newMaskDC, oldNewMask);

DeleteDC(newMaskDC);

DeleteObject(newImage);

DeleteObject(newMask);

return true;}

 

说明:本文提供的TransparentBlt2函数旨在说明透明位图的显示原理,在Windows2000以上环境实际运用中建议使用现成的TransparentBlt函数来绘制透明位图。
 

 

 因为掩膜位图只有两种颜色0x00000000为前景色黑色,0x00ffffff为背景色白色,可以将彩色位图转化成为掩膜位图,也可以掩膜位图转化成为彩色位图,这可以利用CDC类的两个成员函数:

COLORREF SetBkColor( COLORREF crColor );

COLORREF SetTextColor(COLORREF crColor);

在彩色位图转换成为掩膜位图时就会将SetBkColor指定的颜色转换为掩膜中的背景色白色,同样会将SetTextColor指定的颜色转换为掩膜的前景色黑色。例如:若将一彩色位图中的黄色设置为背景色,则此彩色位图转换成为掩膜位图时,黄颜色都会转化成为白色而其他颜色则转换成为黑色。

在掩膜位图转化成为彩色位图时就会将黑色转化为SetTextColor指定的颜色,而将白色转化为SetBkColor指定的颜色。

 

谁能解释清楚这里为什么要设置前景色,背景色?我怎么觉得没必要呢?

HBITMAP hMaskBMP = CreateBitmap(nWidthDest, nHeightDest, 1, 1, NULL); // 建立单色位图

SetBkColor(hImageDC, RGB(0,0,0xff)); // 设置背景色为蓝色

BitBlt(hMaskDC, 0, 0, nWidthDest, nHeightDest, hImageDC, 0, 0, SRCCOPY); // 拷贝到hMaskDC

这样足球位图中蓝色区域在掩码位图中成了白色,其它区域为黑色。

为什么这样做之后就会“足球位图中蓝色区域在掩码位图中成了白色,其它区域为黑色”呢???

 

你可能感兴趣的:(windows,null,图形)