MFC CImage alpha 混合出错
MFC CImage alpha blending gone wrong
我必须在由两个 PNG 文件组成的图片控件上显示图像,其中顶部图像的某些位置具有透明像素。
结果应该是plotter.png
和bar.png
重叠在其顶部显示为(注意栏上奇怪的白色轮廓):
但应该是:
我为它编写的代码很简单
CImage image;
if (FAILED(image.Load(L"plotter.png")))
return false;
CImage imageBar;
if (FAILED(imageBar.Load(L"bar.png")))
return false;
imageBar.AlphaBlend(image.GetDC(), CPoint());
image.ReleaseDC();
((CStatic*)GetDlgItem(IDC_PICTURE))->SetBitmap(image);
我已经阅读了关于 Alpha Blending a Bitmap and BLENDFUNCTION structure 的 MSDN 文档并做了一些实验。一个细节让我盯着我引用的文字:
This flag is set when the bitmap has an Alpha channel (that is,
per-pixel alpha). Note that the APIs use premultiplied alpha, which
means that the red, green and blue channel values in the bitmap must
be premultiplied with the alpha channel value. For example, if the
alpha channel value is x, the red, green and blue channels must be
multiplied by x and divided by 0xff prior to the call.
Alphablend
使用 预乘 alpha,这意味着加载后我必须转到位图并将每个像素乘以它自己的 alpha。所以我尝试了
for (int i = 0; i < imageBar.GetWidth(); i++)
{
for (int j = 0; j < imageBar.GetHeight(); j++)
{
BYTE* ptr = (BYTE*) imageBar.GetPixelAddress(i, j);
ptr[0] = (ptr[0] * ptr[3]) / 255;
ptr[1] = (ptr[1] * ptr[3]) / 255;
ptr[2] = (ptr[2] * ptr[3]) / 255;
}
}
在 AlphaBlend
行之前,我得到的仍然不令人满意:(
那么,我怎样才能得到正确构图的图像呢?
经过几天几夜的绝望,我终于找到了 http://forums.codeguru.com/showthread.php?420631-setting-CImage-alpha-values&p=1560260#post1560260 与我尝试过的类似的解决方案,但 添加了 127到每个像素,这是一个有用的东西,但我当时不理解,也没有做出任何努力来理解它。所以在 AlphaBlend
行之前现在有:
for (int i = 0; i < imageBar.GetWidth(); i++)
{
for (int j = 0; j < imageBar.GetHeight(); j++)
{
BYTE* ptr = (BYTE*)imageBar.GetPixelAddress(i, j);
ptr[0] = ((ptr[0] * ptr[3]) + 127) / 255;
ptr[1] = ((ptr[1] * ptr[3]) + 127) / 255;
ptr[2] = ((ptr[2] * ptr[3]) + 127) / 255;
}
}
现在显示的图像已经合成好了。
我遇到了同样的问题,通过在创建背景图片时设置 dwFlags = 0
解决了这个问题。
background->Create(100, 100, 32, 0);
我必须在由两个 PNG 文件组成的图片控件上显示图像,其中顶部图像的某些位置具有透明像素。
结果应该是plotter.png
和bar.png
重叠在其顶部显示为(注意栏上奇怪的白色轮廓):
但应该是:
我为它编写的代码很简单
CImage image;
if (FAILED(image.Load(L"plotter.png")))
return false;
CImage imageBar;
if (FAILED(imageBar.Load(L"bar.png")))
return false;
imageBar.AlphaBlend(image.GetDC(), CPoint());
image.ReleaseDC();
((CStatic*)GetDlgItem(IDC_PICTURE))->SetBitmap(image);
我已经阅读了关于 Alpha Blending a Bitmap and BLENDFUNCTION structure 的 MSDN 文档并做了一些实验。一个细节让我盯着我引用的文字:
This flag is set when the bitmap has an Alpha channel (that is, per-pixel alpha). Note that the APIs use premultiplied alpha, which means that the red, green and blue channel values in the bitmap must be premultiplied with the alpha channel value. For example, if the alpha channel value is x, the red, green and blue channels must be multiplied by x and divided by 0xff prior to the call.
Alphablend
使用 预乘 alpha,这意味着加载后我必须转到位图并将每个像素乘以它自己的 alpha。所以我尝试了
for (int i = 0; i < imageBar.GetWidth(); i++)
{
for (int j = 0; j < imageBar.GetHeight(); j++)
{
BYTE* ptr = (BYTE*) imageBar.GetPixelAddress(i, j);
ptr[0] = (ptr[0] * ptr[3]) / 255;
ptr[1] = (ptr[1] * ptr[3]) / 255;
ptr[2] = (ptr[2] * ptr[3]) / 255;
}
}
在 AlphaBlend
行之前,我得到的仍然不令人满意:(
那么,我怎样才能得到正确构图的图像呢?
经过几天几夜的绝望,我终于找到了 http://forums.codeguru.com/showthread.php?420631-setting-CImage-alpha-values&p=1560260#post1560260 与我尝试过的类似的解决方案,但 添加了 127到每个像素,这是一个有用的东西,但我当时不理解,也没有做出任何努力来理解它。所以在 AlphaBlend
行之前现在有:
for (int i = 0; i < imageBar.GetWidth(); i++)
{
for (int j = 0; j < imageBar.GetHeight(); j++)
{
BYTE* ptr = (BYTE*)imageBar.GetPixelAddress(i, j);
ptr[0] = ((ptr[0] * ptr[3]) + 127) / 255;
ptr[1] = ((ptr[1] * ptr[3]) + 127) / 255;
ptr[2] = ((ptr[2] * ptr[3]) + 127) / 255;
}
}
现在显示的图像已经合成好了。
我遇到了同样的问题,通过在创建背景图片时设置 dwFlags = 0
解决了这个问题。
background->Create(100, 100, 32, 0);