超级版主
注册日期: 04-03
帖子: 18592
精华: 36
现金: 249466 标准币
资产: 1080358888 标准币
|
回复: 在vc环境中,如何将一附图嵌入到另一幅图中
在介绍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;
}
上面介绍的只是几种简单的图象合成知识。直接修改DIB位图数据制作合成图象,基本方法就是按照一定的算法来从新组合位图的光栅数据,形成不同的图象效果。写这篇文章,也就是希望能给大家起到一个抛砖引玉的作用,给大家一个提示,帮助大家做出更好的图形特效。
__________________
借用达朗贝尔的名言:前进吧,你会得到信心!
[url="http://www.dimcax.com"]几何尺寸与公差标准[/url]
|