您的位置:首页 > 其它

使用CImage显示透明的PNG图片

2011-11-25 17:39 369 查看
CImage 的AlphaBlend
函数可以显示半透明或透明的图片,
但是当使用这个函数显示PNG
图片时,
经常会发现PNG
图片的背景没有透明,
而是被显示为白色.
在网上多处搜索都没有找到原因,
只能自己动手了.

通过调试代码可以发现,CImage
的AlphaBlend
函数内部调用的是全局的Window API
函数:

AlphaBlend(HDC hdcDest,

int nXOriginDest,

int nYOriginDest,

int nWidthDest,

int hHeightDest,

HDC hdcSrc,

int nXOriginSrc,

int nYOriginSrc,

int nWidthSrc,

int nHeightSrc,

BLENDFUNCTION blendFunction)


CImage
类在调用这个函数时,
将自己的内部DC
传递给hdcSrc,
将目标DC
传递给hdcDest.MSDN
详细描述这个函数的最后一个参数BLENDFUNCTION blendFunction.

BLENDFUNCTION
定义如下:

typedef struct _BLENDFUNCTION {

BYTE
BlendOp;

BYTE
BlendFlags;

BYTE
SourceConstantAlpha;

BYTE
AlphaFormat;

}BLENDFUNCTION, *PBLENDFUNCTION, *LPBLENDFUNCTION;

BlendOp 总是为AC_SRC_OVER;BlendFlags
为保留项,
必须为0;SourceConstantAlpha
是图片整体的不透明度,
如果要使用图片像素自身的Alpha
值,
则要将这个参数设置为255;
最后一个参数,
如果使用SourceConstantAlpha
作为描画图片的整体不透明度,
则为设置为0,
如果使用图片像素自身的Alpha
值,
则设置为AC_SRC_ALPHA.
我们在描画带有透明效果的PNG
图片时,
要使用图片像素自身的Alpha
值,
所以要将SourceConstantAlpha
设置为255,
将AlphaFormat
设置为AC_SRC_ALPHA.MSDN
对这种情况下颜色混合的计算方法作了描述,
如下:

Dst.Red

= Src.Red

+ (1 - Src.Alpha) * Dst.Red

Dst.Green

= Src.Green

+ (1 - Src.Alpha) * Dst.Green

Dst.Blue

= Src.Blue

+ (1 - Src.Alpha) * Dst.Blue

Src 是指我们要描画的图片,Dst
是指目标DC
的上下文,Src.Alpha
应该不是像素的Alpha
值,
而应该是Alpha/255;
按照这个公式,
我们可以举个例子计算一下:Src
上一个像素为RGB(255, 255, 255),Alpha
值为0,
与之混合的Dst
上相应像素为RGB(128, 128, 128),
混合后得出的结果为:

R = 255 + (1 - 0 / 255) * 128;

G = 255 + (1 - 0 / 255) * 128;

B = 255 + (1 - 0 / 255) * 128;

计算结果大于255,函数内部自动将其设置为255,最后为RGB(255, 255, 255),
仍然为白色.
而当Src
中像素的颜色为RGB(0, 0, 0),
则结果为Dst
的颜色RGB(128, 128, 128),
实现了透明效果.
按照这个公式计算,
很多颜色的半透明或透明效果都无法实现.

参考MSDN
上在SourceConstantAlpha
不等于255
时的混合计算公式,
我们可以将公式修改为

Dst.Red

= Src.Red * Src.Alpha

+ (1 - Src.Alpha) * Dst.Red

Dst.Green

= Src.Green * Src.Alpha

+ (1 - Src.Alpha) * Dst.Green

Dst.Blue

= Src.Blue * Src.Alpha

+ (1 - Src.Alpha) * Dst.Blue

按照这个公式计算,
我们上面例子的结果为RGB(128, 128, 128),
可以实现透明效果.

根据以上分析,
我们只用修改CImage
中像素的颜色,
就可以实现透明与半透明的效果了,
代码如下:

void CSample::Draw(CDC* pDC, int iX, int iY)

{

//m_stImage 为CImage
的对象

for(int i = 0; i < m_stImage.GetWidth(); ++i)

{

for(int j = 0; j < m_stImage.GetHeight(); ++j

{

unsigned char* pucColor = m_stImage.GetPixelAddress(i , j);

pucColor[0] = pucColor[0] * pucColor[3] / 255;

pucColor[1] = pucColor[1] * pucColor[3] / 255;

pucColor[2] = pucColor[2] * pucColor[3] / 255;

}

}

m_stImage.AlphaBlend(pDC->m_hDC, iX, iY);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: