如何绘制 32 位 Alpha 通道位图?
我需要创建一个自定义控件来显示带有 Alpha 通道的 BMP 图像。 背景可以用不同的颜色绘制,并且图像有阴影,所以我需要真正“绘制”Alpha 通道。
有人知道该怎么做吗?
我还希望如果可能的话,使用 alpha 通道信息创建一个蒙版,以了解鼠标是否单击了图像或透明区域。
任何形式的帮助将不胜感激!
谢谢。
编辑(JDePedro):正如你们中的一些人所建议的,我一直在尝试使用 alpha 混合来绘制带有 alpha 通道的位图。 这只是我实现的一个测试,我从资源加载 32 位位图,并尝试使用 AlphaBlend 函数绘制它:
void CAlphaDlg::OnPaint()
{
CClientDC dc(this);
CDC dcMem;
dcMem.CreateCompatibleDC(&dc);
CBitmap bitmap;
bitmap.LoadBitmap(IDB_BITMAP);
BITMAP BitMap;
bitmap.GetBitmap(&BitMap);
int nWidth = BitMap.bmWidth;
int nHeight = BitMap.bmHeight;
CBitmap *pOldBitmap = dcMem.SelectObject(&bitmap);
BLENDFUNCTION m_bf;
m_bf.BlendOp = AC_SRC_OVER;
m_bf.BlendFlags = 0;
m_bf.SourceConstantAlpha = 255;
m_bf.AlphaFormat = AC_SRC_ALPHA;
AlphaBlend(dc.GetSafeHdc(), 100, 100, nWidth, nHeight, dcMem.GetSafeHdc(), 0, 0,nWidth, nHeight,m_bf);
dcMem.SelectObject(pOldBitmap);
CDialog::OnPaint();
}
这只是一个测试,所以我将代码放在对话框的 OnPaint 中(我还尝试了 AlphaBlend CDC 对象的函数)。
非透明区域已正确绘制,但位图应该透明的地方却变成白色。
有什么帮助吗???
这是一个屏幕截图..不太容易看到,但蓝色圆圈周围有一个白色矩形: 替代文本 http://img385.imageshack.us/img385/7965/alphamh8.png
好的。 我得到了它! 我必须预乘每个像素的 alpha 值。 有人可以建议优化的方法吗?
I need to create a custom control to display bmp images with alpha channel. The background can be painted in different colors and the images have shadows so I need to truly "paint" the alpha channel.
Does anybody know how to do it?
I also want if possible to create a mask using the alpha channel information to know whether the mouse has been click on the image or on the transparent area.
Any kind of help will be appreciated!
Thanks.
Edited(JDePedro): As some of you have suggested I've been trying to use alpha blend to paint the bitmap with alpha channel. This just a test I've implemented where I load a 32-bit bitmap from resources and I try to paint it using AlphaBlend function:
void CAlphaDlg::OnPaint()
{
CClientDC dc(this);
CDC dcMem;
dcMem.CreateCompatibleDC(&dc);
CBitmap bitmap;
bitmap.LoadBitmap(IDB_BITMAP);
BITMAP BitMap;
bitmap.GetBitmap(&BitMap);
int nWidth = BitMap.bmWidth;
int nHeight = BitMap.bmHeight;
CBitmap *pOldBitmap = dcMem.SelectObject(&bitmap);
BLENDFUNCTION m_bf;
m_bf.BlendOp = AC_SRC_OVER;
m_bf.BlendFlags = 0;
m_bf.SourceConstantAlpha = 255;
m_bf.AlphaFormat = AC_SRC_ALPHA;
AlphaBlend(dc.GetSafeHdc(), 100, 100, nWidth, nHeight, dcMem.GetSafeHdc(), 0, 0,nWidth, nHeight,m_bf);
dcMem.SelectObject(pOldBitmap);
CDialog::OnPaint();
}
This is just a test so I put the code in the OnPaint of the dialog (I also tried the AlphaBlend function of the CDC object).
The non-transparent areas are being painted correctly but I get white where the bitmap should be transparent.
Any help???
This is a screenshot..it's not easy to see but there is a white rectangle around the blue circle:
alt text http://img385.imageshack.us/img385/7965/alphamh8.png
Ok. I got it! I have to pre-multiply every pixel for the alpha value. Someone can suggest the optimized way to do that?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
对于未来的谷歌用户,这里有一个有效的预乘函数。 请注意,这是取自 http://www.viksoe.dk/code/alphatut1.htm。
那么你的 OnPaint 就变成了:
以及图像的加载(在控件的构造函数中):
For future google users, here is a working pre-multiply function. Note that this was taken from http://www.viksoe.dk/code/alphatut1.htm .
So then your OnPaint becomes:
And the loading of the image (in the constructor of your control):
我通常这样做的方法是通过 DIBSection - 一个与设备无关的位图,您可以直接修改其像素。 不幸的是,MFC 不支持 DIBSections:您必须使用 Win32 函数 CreateDIBSection() 才能使用它。
首先将位图加载为 32 位 RGBA(即每个像素四个字节:一个红色、一个绿色、一个蓝色和一个用于 Alpha 通道)。 在控件中,创建一个适当大小的 DIBSection。 然后,在绘制例程中将
您可以简单地通过查看 Alpha 通道值来创建给定原始位图数据的蒙版 - 我不确定您在这里问什么。
The way I usually do this is via a DIBSection - a device independent bitmap that you can modify the pixels of directly. Unfortunately there isn't any MFC support for DIBSections: you have to use the Win32 function CreateDIBSection() to use it.
Start by loading the bitmap as 32-bit RGBA (that is, four bytes per pixel: one red, one green, one blue and one for the alpha channel). In the control, create a suitably sized DIBSection. Then, in the paint routine
You can create a mask given the raw bitmap data simply by looking at the alpha channel values - I'm not sure what you're asking here.
您需要与背景颜色进行 alpha 混合,然后取出 alpha 通道进行绘制它到控件。
Alpha 通道应该仅位于图像的每 4 个字节中。 您可以直接将其用于掩码,也可以将每 4 个字节复制到新的掩码图像中。
You need to do an alpha blend with your background color, then take out the alpha channel to paint it to the control.
The alpha channel should just be every 4th byte of your image. You can use that directly for your mask, or you can just copy every 4th byte to a new mask image.
使用 AlphaBlend 函数 绘制它非常容易。
至于你的面具,你需要 获取这些位位图的 并检查您感兴趣的每个像素的 Alpha 通道字节。
Painting it is very easy with the AlphaBlend function.
As for you mask, you'll need to get the bits of the bitmap and examine the alpha channel byte for each pixel you're interested in.
将 RGB 通道与 alpha 通道预乘的优化方法是设置一个包含计算乘法结果的 [256][256] 数组。 第一个维度是alpha值,第二个维度是R/G/B值,数组中的值是您需要的预乘值。
正确设置此数组后,您可以像这样计算所需的值:
An optimised way to pre-multiply the RGB channels with the alpha channel is to set up a [256][256] array containing the calculated multiplication results. The first dimension is the alpha value, the second is the R/G/B value, the values in the array are the pre-multiplied values you need.
With this array set up correctly, you can calculate the value you need like this:
您走在正确的轨道上,但需要解决两件事。
首先使用 ::LoadImage( .. LR_CREATEDIBSECTION ..) 而不是 CBitmap::LoadBitmap。 第二,您必须将位图中每个像素的 RGB 值“预乘”到它们各自的 A 值。 这是 AlphaBlend 函数的要求,请参阅 此 MSDN 页面。
lpng 有一个工作代码,可以对 DIB 数据进行预乘。
You are on the right track, but need to fix two things.
First use ::LoadImage( .. LR_CREATEDIBSECTION ..) instead of CBitmap::LoadBitmap. Two, you have to "pre-multiply" RGB values of every pixel in a bitmap to their respective A value. This is a requirement of AlphaBlend function, see AlphaFormat description on this MSDN page. T
The lpng has a working code that does the premultiplication of the DIB data.