(转)使用CImage显示透明的PNG图片

    CImage AlphaBlend 函数可以显示半透明或透明的图片, 但是当使用这个函数显示PNG 图片时, 经常会发现PNG 图片的背景没有透明, 而是被显示为白色. 在网上多处搜索都没有找到原因, 只能自己动手了.
    
通过调试代码可以发现,CImageAlphaBlend 函数内部调用的是全局的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);      
}

 

文章转自: http://blog.csdn.net/wormsun/archive/2008/11/13/3293741.aspx

你可能感兴趣的:(struct,api,byte,DST)