S.l.e!ep.¢%

像打了激速一样,以四倍的速度运转,开心的工作
简单、开放、平等的公司文化;尊重个性、自由与个人价值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

AlphaBlend

Posted on 2010-09-07 14:40 S.l.e!ep.¢% 阅读(1566) 评论(0)  编辑 收藏 引用 所属分类: DirectUI

AlphaBlend

  函数功能:该函数用来显示具有指定透明度的图像。
  函数原型:AlphaBlend(HDC hdcDest,int nXOriginDest,int nYOriginDest,int nWidthDest,int hHeightDest,HDC hdcSrc,int nXOriginSrc,int nYOriginSrc,int nWidthSrc,int nHeightSrc,BLENDFUNCTION blendFunction);
  参数:
  hdcDest:指向目标设备环境的句柄。
  nXoriginDest:指定目标矩形区域左上角的X轴坐标,按逻辑单位。
  nYOriginDest:指定目标矩形区域左上角的Y轴坐标,按逻辑单位。
  nWidthDest:指定目标矩形区域的宽度,按逻辑单位。
  hHeghtdest:指向目标矩形区域高度的句柄,按逻辑单位。
  hdcSrc:指向源设备环境的句柄。
  nXOriginSrc:指定源矩形区域左上角的X轴坐标,按逻辑单位。
  nYOriginSrc:指定源矩形区域左上角的Y轴坐标,按逻辑单位。
  nWidthSrc:指定源矩形粗体区域的宽度,按逻辑单位。
  nHeightSrc:指定源矩形区域的高度,按逻辑单位。
  blendFunction:指定用于源位图和目标位图使用的alpha混合功能,用于整个源位图的全局alpha值和格式信息。源和目标混合功能当前只限为AC_SRC_OVER。
  最后一个参数blendFunction是一个BLENDFUNCTION结构。BLENDFUNCTION结构控制源和目标位图的混合方式,它的BlendOp字段指明了源混合操作,但只支持AC_SRC_OVER,即根据源alpha值把源图像叠加到目标图像上。OpenGL的alpha混合还支持其他的方式,如常量颜色源。下一个字段BlendFalgs必须是0,也是为以后的应用保留的。最后一个字段AlphaFormat有两个选择:0表示常量alpha值,AC_SRC_ALPHA表示每个像素有各自的alpha通道。
  如果AlphaFormat字段为0,源位图中的所有像素使用同样的常量alpha值,即SourceConstantAlpha字段中的值,该值实际上是0和255,而不是0和1。这里0表示完全透明,255表示完全不透明。目标像素以255-SourceConstantAlpha值作为alpha值。
  如果AlphaFormat字段的值是AC_SRC_ALPHA,源设备表面的每个像素必须有各自的alpha通道。即,必须是32-bpp的物理设备上下文,或是选中了32-bpp DDB和DIB段的内存设备上下文。这些情况下,每个源像素有4个8位通道:红、绿、蓝和alpha。每个像素的alpha通道和SourceConstantAlpha字段一起用于把源和目标混合起来。
 
BLENDFUNCTION
   这个结构体不太明白。
 
至于颜色的绘制,就需要一个重要的函数了,这就是AlphaBlend。在Windows2000之后,微软的GDI+逐渐兴起,其中最重要的就是支持了 AlphaBlend。这是一个可以让鼠标透明有阴影,让图标支持消除锯齿的增强型Icon格式,让窗口半透明的函数。微软在GDI+的计划中添加了这一 API,硬件厂商也跟着支持,所有的厂家都加入到这个新的游戏中来。其实,Photoshop早在1.0版本的时候,就有这个功能了,毕竟软件和系统的考虑和出发点不一样,微软支持的要晚些,因为他要考虑到整个系统的性能和内存占用情况。

    使用AlphaBlend,就必须将RGB格式的Canvas升级为ARGB的透明格式。比如,我们将黑色看成是RGB都为0的颜色,计算机的表达式为 0x000000,每两个0表示16进制的1个字节,而ARGB格式则为0xFF000000,其中最高字节的0xFF就是16进制的255,也就是说这个黑色是全部显示的。注意,计算机的术语和我们平时理解的百分比不一样,一般都以256为100%的概念,这也和RGB的取值范围一样。比如,一个半透明的黑色,就是0x80000000,0x80正好是16进制的128。AlphaBlend除了要考虑画布上原来的颜色,还要考虑到叠加颜色的RGB值和透明度,这一公式较复杂,而且也是技术核心,这里就不再罗列了,有兴趣的可以参考很多关于Photoshop实现原理的软件。

    使用AlphaBlend,我们可以将一个单位的黑色,分配到邻近的4个点上,将0x25000000这样的颜色,也就是半透明的黑色,叠加到原来白色的区域上。不过,这一区域也可能有其他的颜色,所以,一个区域如果不停的叠加黑色,也就会越来越黑。

郊果图:

查看更多精彩图片

代码:

void DrawAlphaBlend (HWND hWnd, HDC hdcwnd)
{
    HDC hdc;               // handle of the DC we will create
    BLENDFUNCTION bf;      // structure for alpha blending
    HBITMAP hbitmap;       // bitmap handle
    BITMAPINFO bmi;        // bitmap header
    VOID *pvBits;          // pointer to DIB section
    ULONG   ulWindowWidth, ulWindowHeight;      // window width/height
    ULONG   ulBitmapWidth, ulBitmapHeight;      // bitmap width/height
    RECT    rt;            // used for getting window dimensions
    UINT32   x,y;          // stepping variables
    UCHAR ubAlpha;         // used for doing transparent gradient
    UCHAR ubRed;       
    UCHAR ubGreen;
    UCHAR ubBlue;
    float fAlphaFactor;    // used to do premultiply
           
    // get window dimensions
    GetClientRect(hWnd, &rt);
   
    // calculate window width/height
    ulWindowWidth = rt.right - rt.left; 
    ulWindowHeight = rt.bottom - rt.top; 

    // make sure we have at least some window size
    if ((!ulWindowWidth) || (!ulWindowHeight))
        return;

    // divide the window into 3 horizontal areas
    ulWindowHeight = ulWindowHeight / 3;

    // create a DC for our bitmap -- the source DC for AlphaBlend
    hdc = CreateCompatibleDC(hdcwnd);
   
    // zero the memory for the bitmap info
    ZeroMemory(&bmi, sizeof(BITMAPINFO));

    // setup bitmap info
    // set the bitmap width and height to 60% of the width and height of each of the three horizontal areas. Later on, the blending will occur in the center of each of the three areas.
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = ulBitmapWidth = ulWindowWidth - (ulWindowWidth/5)*2;
    bmi.bmiHeader.biHeight = ulBitmapHeight = ulWindowHeight - (ulWindowHeight/5)*2;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32;         // four 8-bit components
    bmi.bmiHeader.biCompression = BI_RGB;
    bmi.bmiHeader.biSizeImage = ulBitmapWidth * ulBitmapHeight * 4;

    // create our DIB section and select the bitmap into the dc
    hbitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pvBits, NULL, 0x0);
    SelectObject(hdc, hbitmap);

    // in top window area, constant alpha = 50%, but no source alpha
    // the color format for each pixel is 0xaarrggbb
    // set all pixels to blue and set source alpha to zero
    for (y = 0; y < ulBitmapHeight; y++)
        for (x = 0; x < ulBitmapWidth; x++)
            ((UINT32 *)pvBits)[x + y * ulBitmapWidth] = 0x000000ff;

    bf.BlendOp = AC_SRC_OVER;
    bf.BlendFlags = 0;
    bf.SourceConstantAlpha = 0x7f;  // half of 0xff = 50% transparency
    bf.AlphaFormat = 0;             // ignore source alpha channel

    if (!AlphaBlend(hdcwnd, ulWindowWidth/5, ulWindowHeight/5,
                    ulBitmapWidth, ulBitmapHeight,
                    hdc, 0, 0, ulBitmapWidth, ulBitmapHeight, bf))
        return;                     // alpha blend failed
   
    // in middle window area, constant alpha = 100% (disabled), source
    // alpha is 0 in middle of bitmap and opaque in rest of bitmap
    for (y = 0; y < ulBitmapHeight; y++)
    {   
  for (x = 0; x < ulBitmapWidth; x++)
  {
   if ((x > (int)(ulBitmapWidth/5)) && (x < (ulBitmapWidth-ulBitmapWidth/5)) &&
                (y > (int)(ulBitmapHeight/5)) && (y < (ulBitmapHeight-ulBitmapHeight/5)))
                //in middle of bitmap: source alpha = 0 (transparent).
                // This means multiply each color component by 0x00.
                // Thus, after AlphaBlend, we have a, 0x00 * r,
                // 0x00 * g,and 0x00 * b (which is 0x00000000)
                // for now, set all pixels to red
                ((UINT32 *)pvBits)[x + y * ulBitmapWidth] = 0x00ff0000;
            else
                // in the rest of bitmap, source alpha = 0xff (opaque)
                // and set all pixels to blue
                ((UINT32 *)pvBits)[x + y * ulBitmapWidth] = 0xff0000ff;
  }
 }
   
    bf.BlendOp = AC_SRC_OVER;
    bf.BlendFlags = 0;
    bf.AlphaFormat = AC_SRC_ALPHA;  // use source alpha
    bf.SourceConstantAlpha = 0xff;  // opaque (disable constant alpha)
  
    if (!AlphaBlend(hdcwnd, ulWindowWidth/5, ulWindowHeight/5+ulWindowHeight, ulBitmapWidth, ulBitmapHeight, hdc, 0, 0, ulBitmapWidth, ulBitmapHeight, bf))
        return;

    // bottom window area, use constant alpha = 75% and a changing
    // source alpha. Create a gradient effect using source alpha, and
    // then fade it even more with constant alpha
    ubRed = 0x00;
    ubGreen = 0x00;
    ubBlue = 0xff;
   
    for (y = 0; y < ulBitmapHeight; y++)
        for (x = 0; x < ulBitmapWidth; x++)
        {
            // for a simple gradient, base the alpha value on the x
            // value of the pixel
            ubAlpha = (UCHAR)((float)x / (float)ulBitmapWidth * 255);
            //calculate the factor by which we multiply each component
            fAlphaFactor = (float)ubAlpha / (float)0xff;
            // multiply each pixel by fAlphaFactor, so each component
            // is less than or equal to the alpha value.
            ((UINT32 *)pvBits)[x + y * ulBitmapWidth]
                = (ubAlpha << 24) |                       //0xaa000000
                 ((UCHAR)(ubRed * fAlphaFactor) << 16) |  //0x00rr0000
                 ((UCHAR)(ubGreen * fAlphaFactor) << 8) | //0x0000gg00
                 ((UCHAR)(ubBlue   * fAlphaFactor));      //0x000000bb
        }

    bf.BlendOp = AC_SRC_OVER;
    bf.BlendFlags = 0;
    bf.AlphaFormat = AC_SRC_ALPHA;   // use source alpha
    bf.SourceConstantAlpha = 0xbf;   // use constant alpha, with
                                     // 75% opaqueness

    AlphaBlend(hdcwnd, ulWindowWidth/5,
               ulWindowHeight/5+2*ulWindowHeight, ulBitmapWidth,
               ulBitmapHeight, hdc, 0, 0, ulBitmapWidth,
               ulBitmapHeight, bf);

    // do cleanup
    DeleteObject(hbitmap);
    DeleteDC(hdc);
 
}


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理