AlphaBlend
函数功能:该函数用来显示具有指定透明度的图像。
函数原型:AlphaBlend(HDC hdcDest,int nXOriginDest,int nYOriginDest,int nWidthDest,int hHeightDest,HDC hdcSrc,int nXOriginSrc,int nYOriginSrc,int nWidthSrc,int nHeightSrc,BLENDFUNCTION blendFunction);
参数:
hdcDest:指向目标设备环境的句柄。
nXoriginDest:指定目标矩形区域左上角的X轴坐标,按逻辑单位。
nYOriginDest:指定目标矩形区域左上角的Y轴坐标,按逻辑单位。
nWidthDest:指定目标矩形区域的宽度,按逻辑单位。
hHeghtdest:指向目标矩形区域高度的句柄,按逻辑单位。
hdcSrc:指向源设备环境的句柄。
nXOriginSrc:指定源矩形区域左上角的X轴坐标,按逻辑单位。
nYOriginSrc:指定源矩形区域左上角的Y轴坐标,按逻辑单位。
nWidthSrc:指定源矩形
区域的宽度,按逻辑单位。
nHeightSrc:指定源矩形区域的高度,按逻辑单位。
blendFunction:指定用于源位图和目标位图使用的alpha混合功能,用于整个源位图的全局alpha值和格式信息。源和目标混合功能当前只限为AC_SRC_OVER。
最后一个参数blendFunction是一个BLENDFUNCTION结构。BLENDFUNCTION结构控制源和目标位图的混合方式,它的BlendOp字段指明了源混合操作,但只支持AC_SRC_OVER,即根据源alpha值把源图像叠加到目标图像上。OpenGL的alpha混合还支持其他的方式,如常量颜色源。下一个字段BlendFalgs必须是0,也是为以后的应用保留的。最后一个字段AlphaFormat有两个选择:0表示常量alpha值,AC_SRC_ALPHA表示每个像素有各自的alpha通道。
如果AlphaFormat字段为0,源位图中的所有像素使用同样的常量alpha值,即SourceConstantAlpha字段中的值,该值实际上是0和255,而不是0和1。这里0表示完全透明,255表示完全不透明。目标像素以255-SourceConstantAlpha值作为alpha值。
如果AlphaFormat字段的值是AC_SRC_ALPHA,源设备表面的每个像素必须有各自的alpha通道。即,必须是32-bpp的物理设备上下文,或是选中了32-bpp DDB和DIB段的内存设备上下文。这些情况下,每个源像素有4个8位通道:红、绿、蓝和alpha。每个像素的alpha通道和SourceConstantAlpha字段一起用于把源和目标混合起来。
BLENDFUNCTION
这个结构体不太明白。
至于颜色的绘制,就需要一个重要的函数了,这就是AlphaBlend。在Windows2000之后,微软的GDI+逐渐兴起,其中最重要的就是支持了 AlphaBlend。这是一个可以让鼠标透明有阴影,让图标支持消除锯齿的增强型Icon格式,让窗口半透明的函数。微软在GDI+的计划中添加了这一 API,硬件厂商也跟着支持,所有的厂家都加入到这个新的游戏中来。其实,Photoshop早在1.0版本的时候,就有这个功能了,毕竟软件和系统的考虑和出发点不一样,微软支持的要晚些,因为他要考虑到整个系统的性能和内存占用情况。
使用AlphaBlend,就必须将RGB格式的Canvas升级为ARGB的透明格式。比如,我们将黑色看成是RGB都为0的颜色,计算机的表达式为 0x000000,每两个0表示16进制的1个字节,而ARGB格式则为0xFF000000,其中最高字节的0xFF就是16进制的255,也就是说这个黑色是全部显示的。注意,计算机的术语和我们平时理解的百分比不一样,一般都以256为100%的概念,这也和RGB的取值范围一样。比如,一个半透明的黑色,就是0x80000000,0x80正好是16进制的128。AlphaBlend除了要考虑画布上原来的颜色,还要考虑到叠加颜色的RGB值和透明度,这一公式较复杂,而且也是技术核心,这里就不再罗列了,有兴趣的可以参考很多关于Photoshop实现原理的软件。
使用AlphaBlend,我们可以将一个单位的黑色,分配到邻近的4个点上,将0x25000000这样的颜色,也就是半透明的黑色,叠加到原来白色的区域上。不过,这一区域也可能有其他的颜色,所以,一个区域如果不停的叠加黑色,也就会越来越黑。
郊果图:
代码:
void DrawAlphaBlend (HWND hWnd, HDC hdcwnd)
{
HDC hdc; // handle of the DC we will create
BLENDFUNCTION bf; // structure for alpha blending
HBITMAP hbitmap; // bitmap handle
BITMAPINFO bmi; // bitmap header
VOID *pvBits; // pointer to DIB section
ULONG ulWindowWidth, ulWindowHeight; // window width/height
ULONG ulBitmapWidth, ulBitmapHeight; // bitmap width/height
RECT rt; // used for getting window dimensions
UINT32 x,y; // stepping variables
UCHAR ubAlpha; // used for doing transparent gradient
UCHAR ubRed;
UCHAR ubGreen;
UCHAR ubBlue;
float fAlphaFactor; // used to do premultiply
// get window dimensions
GetClientRect(hWnd, &rt);
// calculate window width/height
ulWindowWidth = rt.right - rt.left;
ulWindowHeight = rt.bottom - rt.top;
// make sure we have at least some window size
if ((!ulWindowWidth) || (!ulWindowHeight))
return;
// divide the window into 3 horizontal areas
ulWindowHeight = ulWindowHeight / 3;
// create a DC for our bitmap -- the source DC for AlphaBlend
hdc = CreateCompatibleDC(hdcwnd);
// zero the memory for the bitmap info
ZeroMemory(&bmi, sizeof(BITMAPINFO));
// setup bitmap info
// set the bitmap width and height to 60% of the width and height of each of the three horizontal areas. Later on, the blending will occur in the center of each of the three areas.
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = ulBitmapWidth = ulWindowWidth - (ulWindowWidth/5)*2;
bmi.bmiHeader.biHeight = ulBitmapHeight = ulWindowHeight - (ulWindowHeight/5)*2;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32; // four 8-bit components
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = ulBitmapWidth * ulBitmapHeight * 4;
// create our DIB section and select the bitmap into the dc
hbitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pvBits, NULL, 0x0);
SelectObject(hdc, hbitmap);
// in top window area, constant alpha = 50%, but no source alpha
// the color format for each pixel is 0xaarrggbb
// set all pixels to blue and set source alpha to zero
for (y = 0; y < ulBitmapHeight; y++)
for (x = 0; x < ulBitmapWidth; x++)
((UINT32 *)pvBits)[x + y * ulBitmapWidth] = 0x000000ff;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 0x7f; // half of 0xff = 50% transparency
bf.AlphaFormat = 0; // ignore source alpha channel
if (!AlphaBlend(hdcwnd, ulWindowWidth/5, ulWindowHeight/5,
ulBitmapWidth, ulBitmapHeight,
hdc, 0, 0, ulBitmapWidth, ulBitmapHeight, bf))
return; // alpha blend failed
// in middle window area, constant alpha = 100% (disabled), source
// alpha is 0 in middle of bitmap and opaque in rest of bitmap
for (y = 0; y < ulBitmapHeight; y++)
{
for (x = 0; x < ulBitmapWidth; x++)
{
if ((x > (int)(ulBitmapWidth/5)) && (x < (ulBitmapWidth-ulBitmapWidth/5)) &&
(y > (int)(ulBitmapHeight/5)) && (y < (ulBitmapHeight-ulBitmapHeight/5)))
//in middle of bitmap: source alpha = 0 (transparent).
// This means multiply each color component by 0x00.
// Thus, after AlphaBlend, we have a, 0x00 * r,
// 0x00 * g,and 0x00 * b (which is 0x00000000)
// for now, set all pixels to red
((UINT32 *)pvBits)[x + y * ulBitmapWidth] = 0x00ff0000;
else
// in the rest of bitmap, source alpha = 0xff (opaque)
// and set all pixels to blue
((UINT32 *)pvBits)[x + y * ulBitmapWidth] = 0xff0000ff;
}
}
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.AlphaFormat = AC_SRC_ALPHA; // use source alpha
bf.SourceConstantAlpha = 0xff; // opaque (disable constant alpha)
if (!AlphaBlend(hdcwnd, ulWindowWidth/5, ulWindowHeight/5+ulWindowHeight, ulBitmapWidth, ulBitmapHeight, hdc, 0, 0, ulBitmapWidth, ulBitmapHeight, bf))
return;
// bottom window area, use constant alpha = 75% and a changing
// source alpha. Create a gradient effect using source alpha, and
// then fade it even more with constant alpha
ubRed = 0x00;
ubGreen = 0x00;
ubBlue = 0xff;
for (y = 0; y < ulBitmapHeight; y++)
for (x = 0; x < ulBitmapWidth; x++)
{
// for a simple gradient, base the alpha value on the x
// value of the pixel
ubAlpha = (UCHAR)((float)x / (float)ulBitmapWidth * 255);
//calculate the factor by which we multiply each component
fAlphaFactor = (float)ubAlpha / (float)0xff;
// multiply each pixel by fAlphaFactor, so each component
// is less than or equal to the alpha value.
((UINT32 *)pvBits)[x + y * ulBitmapWidth]
= (ubAlpha << 24) | //0xaa000000
((UCHAR)(ubRed * fAlphaFactor) << 16) | //0x00rr0000
((UCHAR)(ubGreen * fAlphaFactor) << 8) | //0x0000gg00
((UCHAR)(ubBlue * fAlphaFactor)); //0x000000bb
}
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.AlphaFormat = AC_SRC_ALPHA; // use source alpha
bf.SourceConstantAlpha = 0xbf; // use constant alpha, with
// 75% opaqueness
AlphaBlend(hdcwnd, ulWindowWidth/5,
ulWindowHeight/5+2*ulWindowHeight, ulBitmapWidth,
ulBitmapHeight, hdc, 0, 0, ulBitmapWidth,
ulBitmapHeight, bf);
// do cleanup
DeleteObject(hbitmap);
DeleteDC(hdc);
}