您的位置:首页 > 其它

使用CImage显示透明的PNG图片

2013-07-25 10:44 337 查看
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 = (unsigned char*)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);      

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