您的位置:首页 > 编程语言 > C语言/C++

VC++图片透明技术原理

2016-05-21 09:40 337 查看
透明效果
由于所有的图文件都是以矩形来储存的,我们也许会需要把一张易拉罐图片贴到窗口的背景图上,而这种情况下如果直接进行贴图,结果如下图:


这似乎不是我们想要的结果。
为了得到透明效果,我们需要运用到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"

//全局变量声明

HINSTANCE hInst;

HBITMAP bg,sprite; //声明两个位图对象,分别存储背景图与前景易拉罐

HDC mdc; //声明一个内存DC"mdc",用来暂存位图

//全局函数声明

ATOM MyRegisterClass(HINSTANCE hInstance);

BOOL InitInstance(HINSTANCE, int);

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

void MyPaint(HDC hdc);

////****Winmain函数,程序入口点函数**************************************

int APIENTRY WinMain(HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPSTR lpCmdLine,

int nCmdShow)

{

MSG msg;

MyRegisterClass(hInstance);

if (!InitInstance (hInstance, nCmdShow))

{

return FALSE;

}

//消息循环

while (GetMessage(&msg, NULL, 0, 0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

//****设计一个窗口类,类似填空题,使用窗口结构体*************************

ATOM MyRegisterClass(HINSTANCE hInstance)

{

WNDCLASSEX wcex;

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;

return RegisterClassEx(&wcex);

}

//****初始化函数*************************************

// 1.建立与窗口DC兼容的内存DC

// 2.从文件加载背景图与恐龙图

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)

{

HWND hWnd;

HDC hdc;

hInst = hInstance;

hWnd = CreateWindow("canvas", "绘图窗口" , WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

if (!hWnd)

{

return FALSE;

}

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);

return TRUE;

}

//****自定义绘图函数*********************************

//透明贴图

void MyPaint(HDC hdc)

{

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。

}

//****消息处理函数**********************************

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

PAINTSTRUCT ps;

HDC hdc;

switch (message)

{

case WM_PAINT: //窗口重绘消息

hdc = BeginPaint(hWnd, &ps);

MyPaint(hdc);

EndPaint(hWnd, &ps);

break;

case WM_DESTROY: //窗口结束消息

DeleteDC(mdc);

DeleteObject(bg);

DeleteObject(sprite);

PostQuitMessage(0);

break;

default: //其他消息

return DefWindowProc(hWnd, message, wParam, lParam);

}

return 0;

}

最后程序的运行结果为:


通过BitBlt()贴图函数及Raster运算值的设定,很简单地就做出了想要的透明效果,这种方法在设计2D游戏的一些画面内容时使用相当频繁。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  技术 图片 透明