VC++图片透明技术原理
透明效果
由于所有的图文件都是以矩形来储存的,我们也许会需要把一张易拉罐图片贴到窗口的背景图上,而这种情况下如果直接进行贴图,结果如下图:
这似乎不是我们想要的结果。
为了得到透明效果,我们需要运用到BitBlt()贴图函数以及其参数Raster的值来将图片中不必要的部分去掉(又称去背),使得图中的主题可以与背景完美融合。
制作透明效果有很多种方法,但是基本上都是利用贴图时不同的Raster运算,通过转换而产生相同的透明效果。在这里先来介绍一种透明运算的方法。
我们以图中的易拉罐为例子,首先准备一张位图,如下图。
图中的左边的图是要去背并贴到背景上的前景图。右边的黑白图称为“屏蔽图”,在透明的过程中会用到它。要把去背的位图与屏蔽图合并成同一张图,透明的时候再按照需要来进行裁切。可以把它分成两张图,但是这样程序必须运行两次图文件加载的操作。
有了屏蔽图就可以利用贴图函数来产生透明效果了,所需的贴图步骤如下:
<1>将屏蔽图与背景图做"AND"运算,Raster值为SRCAND,贴到目的地DC中。
<2>将前景图与背景图做"OR"运算,Raster值为SRCPAINT,贴到目的地DC中。
为什么经过上面两个操作就能产生透明的效果呢?看下图就理解了:
下面具体说明上面两个步骤所产生的图点色彩的变化。
1.屏蔽图与背景图做"AND"运算
<1>屏蔽图中的黑色部分与背景图做"AND"运算:
<2>屏蔽图中的白色部分与背景图做"AND"运算:
进过这一运算所产生的结果如下图
2.前景图与背景图做"OR"运算
<1>前景图中的彩色部分与图第一步得到的“黑色易拉罐”图做"OR"运算:
<2>前景图中的黑色部分与第一步得到的“黑色易拉罐”图做"OR"运算:
经过这一运算后所显示的画面就是所需的透明图了,如下图所示:
下面我们来看看实现上述透明贴图效果的源代码
[cpp]view plaincopy
#include"stdafx.h"
//全局变量声明
HINSTANCEhInst;
HBITMAPbg,sprite;//声明两个位图对象,分别存储背景图与前景易拉罐
HDCmdc;//声明一个内存DC"mdc",用来暂存位图
//全局函数声明
ATOMMyRegisterClass(HINSTANCEhInstance);
BOOLInitInstance(HINSTANCE,int);
LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);
voidMyPaint(HDChdc);
////****Winmain函数,程序入口点函数**************************************
intAPIENTRYWinMain(HINSTANCEhInstance,
HINSTANCEhPrevInstance,
LPSTRlpCmdLine,
intnCmdShow)
{
MSGmsg;
MyRegisterClass(hInstance);
if(!InitInstance(hInstance,nCmdShow))
{
returnFALSE;
}
//消息循环
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
returnmsg.wParam;
}
//****设计一个窗口类,类似填空题,使用窗口结构体*************************
ATOMMyRegisterClass(HINSTANCEhInstance)
{
WNDCLASSEXwcex;
wcex.cbSize=sizeof(WNDCLASSEX);
wcex.style=CS_HREDRAW|CS_VREDRAW;
wcex.lpfnWndProc=(WNDPROC)WndProc;
wcex.cbClsExtra=0;
wcex.cbWndExtra=0;
wcex.hInstance=hInstance;
wcex.hIcon=NULL;
wcex.hCursor=NULL;
wcex.hCursor=LoadCursor(NULL,IDC_ARROW);
wcex.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName=NULL;
wcex.lpszClassName="canvas";
wcex.hIconSm=NULL;
returnRegisterClassEx(&wcex);
}
//****初始化函数*************************************
//1.建立与窗口DC兼容的内存DC
//2.从文件加载背景图与恐龙图
BOOLInitInstance(HINSTANCEhInstance,intnCmdShow)
{
HWNDhWnd;
HDChdc;
hInst=hInstance;
hWnd=CreateWindow("canvas","绘图窗口",WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,0,CW_USEDEFAULT,0,NULL,NULL,hInstance,NULL);
if(!hWnd)
{
returnFALSE;
}
MoveWindow(hWnd,10,10,600,450,true);
ShowWindow(hWnd,nCmdShow);
UpdateWindow(hWnd);
hdc=GetDC(hWnd);//获得窗口DC
mdc=CreateCompatibleDC(hdc);//创建与窗口兼容的内存DC(mdc)
bg=(HBITMAP)LoadImage(NULL,"bg.bmp",IMAGE_BITMAP,600,450,LR_LOADFROMFILE);
//J加载背景图到bg中
sprite =(HBITMAP)LoadImage(NULL,"sprite.bmp",IMAGE_BITMAP,170,99,LR_LOADFROMFILE);
//加载易拉罐图到sprite中
MyPaint(hdc);
ReleaseDC(hWnd,hdc);
returnTRUE;
}
//****自定义绘图函数*********************************
//透明贴图
voidMyPaint(HDChdc)
{
SelectObject(mdc,bg);
BitBlt(hdc,0,0,600,450,mdc,0,0,SRCCOPY);//先将背景图贴到显示窗口中
SelectObject(mdc,sprite);//选用易拉罐图到"mdc"中
BitBlt(hdc,50,50,225,225,mdc,225,0,SRCAND);//进行制作贴图的第一步骤,即将屏蔽图与背景图做"AND"运算,屏蔽图在整张易拉罐图中,最左上角起始位置点得坐标为(225,0),BitBlt()函数中最后一个Raster参数值设置为SRCAND。
BitBlt(hdc,50,50,225,225,mdc,0,0,SRCPAINT);//进行制作透明贴图的第二步骤,即将前景图与背景图做"OR"运算,前景图在整张易拉罐图中,最左上角起始位置的坐标为(0,0),BitBlt()函数最后一个参数值设置为SRCPAINT。
}
//****消息处理函数**********************************
LRESULTCALLBACKWndProc(HWNDhWnd,UINTmessage,WPARAMwParam,LPARAMlParam)
{
PAINTSTRUCTps;
HDChdc;
switch(message)
{
caseWM_PAINT://窗口重绘消息
hdc=BeginPaint(hWnd,&ps);
MyPaint(hdc);
EndPaint(hWnd,&ps);
break;
caseWM_DESTROY://窗口结束消息
DeleteDC(mdc);
DeleteObject(bg);
DeleteObject(sprite);
PostQuitMessage(0);
break;
default://其他消息
returnDefWindowProc(hWnd,message,wParam,lParam);
}
return0;
}
最后程序的运行结果为:
通过BitBlt()贴图函数及Raster运算值的设定,很简单地就做出了想要的透明效果,这种方法在设计2D游戏的一些画面内容时使用相当频繁。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。