关于图象淡入淡出的问题

caio0 2005-11-10 12:48:24
小弟的同学要做一个图像淡入淡出的问题,
我在网上找了一段代码
如下:
但是,我运行出来的结果有问题
请大家帮忙解决。

动画法:
这种方法是利用直接操作位图的数据来实现的,可以实现像素颜色的平滑变化,视觉效果可以做的很好,因此,这种方法在屏保中的应用非常多。
首先,我们必须了解bmp图形的结构。一个bmp图形由两个部分组成,即文件头和数据区,文件头存放bmp图形的大小、格式等信息,数据区存放bmp图形各个像素的颜色信息。对于24位真彩色的bmp来说,文件头的大小为54个字节,前14个字节对应VC中定义的BITMAPFILEINFO结构,后40个字节对应BITMAPINFOHEADER结构。我们把bmp数据区的数据读出,经过一定的运算,再利用WIN32API::StretchDIBits(...)函数直接输出到显示DC上,就可以实现一些特技效果。
下面让我们分步去实现一个全屏幕的演示程序:
1:生成一个基于对话框的项目,命名为F1:
2:删除F1Dlg.h、F1Dlg.h和F1.cpp中与其相关的所有代码。
3:在项目中添加一个基类为generic Cwnd的新类,命名为CW.
4:为CW类添加如下私有成员变量:
//////////////////////
UINT y_offset;
UINT x_offset;
UINT stage;
BYTE* p3;
BYTE * p2;
BYTE * p1;
BITMAPINFOHEADER header;
HGLOBAL hlb1;
HGLOBAL hlb2;
HGLOBAL hlb3;
UINT start;
UINT counter;
////////////////////////
并在W.h的顶部加入宏定义 #define BMP_SIZE 192000
5:为CW添加Create(...)虚函数,WM_CREATE,WM_TIMER,WM_PAINT,WM_DESTORY,WM_LBUTTONDOWN的消息句柄,接受缺省的函数名称。
6:删除CW::Create(...)中的原有代码,用以下代码替换:
/////////////////////////
LPCTSTR m_lpszCN;
m_lpszCN = AfxRegisterWndClass(CS_BYTEALIGNCLIENT,
::LoadCursor(AfxGetResourceHandle(),
MAKEINTRESOURCE(IDC_NULLCORSOR)));
return CWnd::CreateEx(WS_EX_TOPMOST,m_lpszCN, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);
//////////////////////////
7: 删除CF1App:: InitInstance()中#endif以后的所有代码,用以下代码代替:
///////////////////////////
int cx=GetSystemMetrics(SM_CXSCREEN);
int cy=GetSystemMetrics(SM_CYSCREEN);
CRect rectDefault(0,0,cx,cy);
m_pMainWnd=new CW();
m_pMainWnd->Create(NULL, _T("Hello World!"), WS_VISIBLE|WS_POPUP, rectDefault,NULL,NULL);
return TRUE;
///////////////////////////
8:在CW::OnCreate(...)函数中加入如下代码:
/////////////////////////////
counter=0;
int cx=GetSystemMetrics(SM_CXSCREEN);
int cy=GetSystemMetrics(SM_CYSCREEN);
x_offset=(cx-640)/2;
y_offset=(cy-400)/2;
/////////////////////////////
9: 在CW::OnDestroy()函数中加入如下代码:
////////////////////////////////
KillTimer(1);
GlobalFree(hlb1);
GlobalFree(hlb2);
GlobalFree(hlb3);
/////////////////////////////
10: 在CW:: OnLButtonDown(...)函数中加入如下代码:
//////////////////////////////
SendMessage(WM_CLOSE);
//////////////////////////////
11: 在CW:: OnLButtonDown(...)函数中加入如下代码:
/////////////////////////////
CPaintDC dc(this);
dc.FillSolidRect(0,0,800,600,RGB(0,0,0));
dc.SetTextColor(RGB(200,0,0));
if(!start) return;
CFile f1,f2;
f1.Open("bmp1.bmp",CFile::modeRead);
f2.Open("bmp2.bmp",CFile::modeRead);
f1.Seek(14,CFile::begin);
f1.Read(&header,40);
f2.Seek(54,CFile::begin);
hlb1=GlobalAlloc(GMEM_MOVEABLE,BMP_SIZE);
p1=(BYTE*)GlobalLock(hlb1);
p1=(BYTE*)malloc(BMP_SIZE);
f1.ReadHuge(p1,BMP_SIZE);
GlobalUnlock(hlb1);
hlb2=GlobalAlloc(GMEM_MOVEABLE,BMP_SIZE);
p2=(BYTE*)GlobalLock(hlb2);
f2.ReadHuge(p2,BMP_SIZE);
GlobalUnlock(hlb2);
hlb3=GlobalAlloc(GMEM_MOVEABLE,BMP_SIZE);
p3=(BYTE*)GlobalLock(hlb3);
GlobalUnlock(hlb3);
f1.Close();
f2.Close();
stage=1;
SetTimer(1,100,NULL);
start=0;
///////////////////////////
12: 在CW:: OnTimer(...)函数中加入如下代码:
///////////////////////////
if(stage==1)
{
if(counter++>63)
{
stage=2;
counter=0;
return;
}
for(int i=0;i<BMP_SIZE;i++)
p3[i]=counter*p1[i]/64;
::StretchDIBits(GetDC()->m_hDC,x_offset,y_offset,640,400,0,0,320,200,p3,
((BITMAPINFO*)(&header)),NULL,SRCCOPY);
}
if(stage==2)
{
if(counter++>63)
{
stage=3;
counter=0;
return;
}
for(int i=0;i<BMP_SIZE;i++)
p3[i]=(64-counter)*p1[i]/64+counter*p2[i]/64;
::StretchDIBits(GetDC()->m_hDC,x_offset,y_offset,640,400,0,0,320,200,p3,
((BITMAPINFO*)(&header)),NULL,SRCCOPY);
}
if(stage==3)
{
if(counter++>63)
{
KillTimer(1);
SendMessage(WM_CLOSE);
return;
}
for(int i=0;i<BMP_SIZE;i++)
p3[i]=(64-counter)*p2[i]/64;
::StretchDIBits(GetDC()->m_hDC,x_offset,y_offset,640,400,0,0,320,200,p3,
((BITMAPINFO*)(&header)),NULL,SRCCOPY);
}
//////////////////////////////////
13:最后,将两个分辨率为320*200的24bitBMP拷入工程所在的目录中,分别命名为1.bmp和2.bmp. 编译运行程序,可以看到在黑色的背景中,第一幅图象(1.bmp)由暗渐渐变亮,当它完全出现后,第二幅图象(2.bmp)从第一幅图象中慢慢的浮现出来。当第二幅图象完全取代第一幅后,它的亮度又逐渐减小,最终消失在黑色的背景中。与模式画刷法不同,这些过渡非常平滑。
...全文
355 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
caio0 2005-11-12
  • 打赏
  • 举报
回复
ok
caio0 2005-11-10
  • 打赏
  • 举报
回复
第二步我删除了F1Dlg.h、F1Dlg.cpp,以及在F1中的代码, 删除了 .clw文件
又新建了.clw文件
在W.cpp添了#include"resoure.h"
在F1.cpp添了#include"W.h"
又添加了光标IDC_NULLCORSOR

这时候编译,提示F1Dlg.cpp 不能编译,我在project settings 我把F1Dlg.cpp exclude file from build
这下编译通过,
运行只能看到光标

请各位指教

还有
第三步,在项目中添加一个基类为generic Cwnd的新类,命名为CW
5:为CW添加Create(...)虚函数,WM_CREATE,WM_TIMER,WM_PAINT,WM_DESTORY,WM_LBUTTONDOWN的消息句柄,接受缺省的函数名称

应该怎么做,谢谢
caio0 2005-11-10
  • 打赏
  • 举报
回复
高手请知点一下
qinqin73 2005-11-10
  • 打赏
  • 举报
回复
学习
yoogle 2005-11-10
  • 打赏
  • 举报
回复
上面你的问题,我不好回答你。用alphablend可以实现淡入淡出的效果,还是比较方便的。你看看下面的文章。
在介绍Alpha通道之前,先来看一个如何利用Alpha值合成两张图片的效果。


Image1 Image2 合成图象

Alpha图象合成

Alpha图象合成的方法:合成图象的各点像素值是由用来制作合成图的两张图片的相应点的像素值按一定比例混合而成的,这个比例由Alpha值决定,具体算式见下:

newPixeValR= (pixel1ValR*(255-Alpha)+pixel2ValR*Alpha)/255; // Alpha取值范围从0到255
newPixeValG= (pixel1ValG*(255-Alpha)+pixel2ValG*Alpha)/255; // Alpha取值范围从0到255
newPixeValB= (pixel1ValB*(255-Alpha)+pixel2ValB*Alpha)/255; // Alpha取值范围从0到255

从上面的算式可以看出,只要修改Alpha的值,就可以改变合成后的图象中用来合成的两张图片各自所占的比值,改变合成后的显示效果。利用这个方法,我们就可以很轻易的制作出生动的淡入淡出效果和图片间的平滑过度特效。下面给出一个制作合成图的具体源码:

BOOL CompoundDIB(HANDLE hDIB,HANDLE hDIBSrc,int alpha) { LPVOID lpvBuf=NULL; // 目标图象数据指针
LPVOID lpvBufSrc=NULL; // 源图数据指针

// // 源图象信息 //
LPBITMAPINFO lpbmif=(LPBITMAPINFO)hDIBSrc; LPBITMAPINFOHEADER lpbmifh=(LPBITMAPINFOHEADER)lpbmif;
// 计算图象数据偏移量
UINT nColors=lpbmifh->biClrUsed ? lpbmifh->biClrUsed : 1<<lpbmifh->biBitCount; if ( nColors >256 ) nColors=0; // 如果颜色数大于256色,则没有调色板
lpvBufSrc=(LPVOID)((LPBYTE)lpbmif->bmiColors+nColors*sizeof(RGBQUAD));
int cxSrc=lpbmifh->biWidth; // 源图象宽度
int cySrc=lpbmifh->biHeight; // 源图象高度
// 计算图象每行的字节数(图象位数 x 图象宽度,如果不能被2整除则在每行后面添加一个0字节)
int nBytesPerLineSrc=((cxSrc*lpbmifh->biBitCount+31)&~31)/8;

// // 目标图象信息 //
lpbmif=(LPBITMAPINFO)hDIB;
lpbmifh=(LPBITMAPINFOHEADER)lpbmif;
nColors=lpbmifh->biClrUsed ? lpbmifh->biClrUsed : 1<<lpbmifh->biBitCount; if ( nColors >256 ) nColors=0; lpvBuf=(LPVOID)((LPBYTE)lpbmif->bmiColors+nColors*sizeof(RGBQUAD));
int cx=lpbmifh->biWidth;
int cy=lpbmifh->biHeight;
int nBytesPerLine=((cx*lpbmifh->biBitCount+31)&~31)/8;

LPBYTE lpbPnt=NULL;
LPBYTE lpbPntSrc=NULL;
// // 通过alpha值合并两张图象的像素值 //
// 这里假设是24位真彩色图象,其他深度的图象处理方法可以以次类推
for ( int y=(cy<cySrc ? cy : cySrc); y>0 ;y-- ) { lpbPnt=(LPBYTE)lpvBuf+nBytesPerLine*(y-1);
lpbPntSrc=(LPBYTE)lpvBufSrc+nBytesPerLineSrc*(y-1);
for ( int x=0; x<(cx<cxSrc ? cx : cxSrc); x++ ) { for ( int i=0 ;i<3 ;i++ ) *lpbPnt++=(*lpbPnt*(255-alpha)+*(lpbPntSrc++)*alpha)/255;
}
}
return TRUE;
}

回到刚才讨论的问题,如何避免画出的透明图有一个明显的轮廓?想一想刚才介绍的利用Alpha值合成图象方法,如果我们在合成的过程中动态修改Alpha值,使它的轮廓部分从(背景的)0慢慢过度到(前景的)255,这样不就可以使前景逐步地渗透到背景里面了。下面来看看具体做法吧!

Alpha通道

上面所说的动态修改的Alpha值,一般是使用一张256级的灰度图来实现的(这张灰度图就称为Alpha通道),灰度图的各点值对应着前景图片相应点的Alpha值。灰度图的黑色部分是透明的(Alpha值为0),白色部分为不透明部分(Alpha值为255),灰度部分就是前景和背景的融合部分。看一看合成效果吧!



Alpha通道 前景图

背景图 合成图

可以看出,利用Alpha通道,合成后的图象前景和背景非常完美的融合在一起了。
Alpha通道合成图象代码:

BOOL CompoundDIB(int left,int top,HANDLE hDIB,HANDLE hDIBSrc,HANDLE hDIBAlpha) {
LPVOID lpvBuf=NULL; // 目标图象数据指针(背景)
LPVOID lpvBufSrc=NULL; // 源图数据指针(前景)
LPVOID lpvBufAlpha=NULL; // Alpha通道数据指针

// // 源图象信息 //
LPBITMAPINFO lpbmif=(LPBITMAPINFO)hDIBSrc;
LPBITMAPINFOHEADER lpbmifh=(LPBITMAPINFOHEADER)lpbmif;
// 计算图象数据偏移量
UINT nColors=lpbmifh->biClrUsed ? lpbmifh->biClrUsed : 1<<lpbmifh->biBitCount;
if ( nColors >256 )
nColors=0; // 如果颜色数大于256色,则没有调色板
lpvBufSrc=lpbmif->bmiColors+nColors;
int cxSrc=lpbmifh->biWidth; // 源图象宽度
int cySrc=lpbmifh->biHeight; // 源图象高度
// 计算图象每行的字节数(图象位数 x 图象宽度,如果不能被2整除则在每行后面添加一个0字节)
int nBytesPerLineSrc=((cxSrc*lpbmifh->biBitCount+31)&~31)/8;

// // 目标图象信息 //
lpbmif=(LPBITMAPINFO)hDIB;
lpbmifh=(LPBITMAPINFOHEADER)lpbmif;
nColors=lpbmifh->biClrUsed ? lpbmifh->biClrUsed : 1<<lpbmifh->biBitCount;
if ( nColors >256 )
nColors=0;
lpvBuf=lpbmif->bmiColors+nColors;
int cx=lpbmifh->biWidth;
int cy=lpbmifh->biHeight;
int nBytesPerLine=((cx*lpbmifh->biBitCount+31)&~31)/8;

// // Alpha通道信息 //
lpbmif=(LPBITMAPINFO)hDIBAlpha;
lpbmifh=(LPBITMAPINFOHEADER)hDIBAlpha;
ASSERT(lpbmifh->biWidth==cxSrc && lpbmifh->biHeight==cySrc &&
lpbmifh->biBitCount==8 );
nColors=lpbmifh->biClrUsed ? lpbmifh->biClrUsed : 256;
lpvBufAlpha=lpbmif->bmiColors+nColors;
int nBytesPerLineAlpha=((cxSrc*8+31)&~31)/8;

// // 用来读取颜色值的指针 //
LPBYTE lpbPnt=NULL;
LPBYTE lpbPntSrc=NULL;
LPBYTE lpbPntAlpha=NULL;
// // 通过alpha值合并两张图象的像素值 //
// 这里假设是24位真彩色图象,其他深度的图象处理方法可以以次类推
for ( int y=cySrc; y>0 ;y-- )
{
lpbPnt=(LPBYTE)lpvBuf+nBytesPerLine*(cy-top-cySrc+y-1)+left*3;
lpbPntSrc=(LPBYTE)lpvBufSrc+nBytesPerLineSrc*(y-1);
lpbPntAlpha=(LPBYTE)lpvBufAlpha+nBytesPerLineAlpha*(y-1);
for ( int x=0; x<cxSrc; x++ )
{
int alpha=*lpbPntAlpha++;
for ( int i=0 ;i<3 ;i++ )
*lpbPnt++=(*lpbPnt*(255-alpha)+*(lpbPntSrc++)*alpha)/255;
}
}
return TRUE;

}

菜牛 2005-11-10
  • 打赏
  • 举报
回复
你的问题在哪里?

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧