我的程序使用alphablend函数将内存中创建的HDC叠加至屏幕时,在屏幕32位色的情况下正常,但当屏幕颜色改为16位色时程序就不显示了,请问是怎么回事,用Bitblt正常,是不是屏幕在16位色的情况下,alphablend函数无效?

解决方案 »

  1.   

    void DrawAlphaBlend_cpp(
      WORD * dstAddr, // 目标图的起始地址
      WORD * srcAddr, // 源图的起始地址
      DWORD cntX, // 横轴要处理的宽度
      DWORD cntY, // 纵轴要处理的高度
      DWORD dstSkipBytes, // 目标地址在处理完横向宽度最后一个点后要跳过多少个字节
      DWORD srcSkipBytes, // 源地址在处理完横向宽度最后一个点后要跳过多少个字节
      DWORD srcAlphaLevel )// Alpha级数 0 ~ 32
    {
      DWORD srcColor; // 源点颜色
      DWORD dstColor; // 目标点颜色
      // 此值要根据你所需要处理的像素格式而定,这里仅指 16 位色 555模式 RGB顺序
      DWORD Mask32 = 0x3E07C1F;
      WORD xCnt = cntX; // 暂存宽度值,以便循环运算
      for( ;cntY>0; --cntY, cntX = xCnt )
      {
        for( ; cntX>0; --cntX )
        {
          srcColor = *srcAddr | (*srcAddr<<16); //扩宽到32位
          srcColor &= Mask32; // 通过掩码得到正确的扩宽颜色值
          dstColor = *dstAddr | (*dstAddr<<16);
          dstColor &= Mask32;
          srcColor = (srcColor - dstColor) * srcAlphaLevel / 32 + dstColor;
          srcColor &= Mask32; // 通过掩码把结果的其它无用数据去掉
          // 还原到正确的16位颜色值
          srcColor = (srcColor & 0xffff0000)>>16 | (srcColor & 0x0000ffff );
          
          // 改变目标图的点为结果点,这样直接显示目标图即可知道整个结果
          *dstAddr = srcColor;
          ++dstAddr;
          ++srcAddr;
        }
        dstAddr = (WORD*)((BYTE*)dstAddr + dstSkipBytes);
        srcAddr = (WORD*)((BYTE*)srcAddr + srcSkipBytes);
      }
    }
      

  2.   

    详情请见:http://blog.csdn.net/starofrainnight/archive/2007/03/19/1533617.aspx
    16位色AlphaBlend深度探索
      

  3.   

    有效的,关键是看你创建这个位图用的API,一定要是CreateDIBSection,并且一定要指明32位,不能用CreateCompatibleBitmap或者CreateDIBitmap
      

  4.   

    to 各位:
       下面是我的delphi源码,用alphablend叠加带透明通道的图片,在屏幕色深32bits时正常,在此16位色时不显示,请帮我看看procedure TForm1.FormCreate(Sender: TObject);
    var GPImage: TGPImage;
    begin
      Self.DoubleBuffered := True;
      BorderStyle := bsNone;
      m_Blend.BlendOp := AC_SRC_OVER; 
      m_Blend.BlendFlags := 0;
      m_Blend.AlphaFormat := AC_SRC_ALPHA;
      m_Blend.SourceConstantAlpha := 255;
      GPImage := TGPImage.Create('backend.png');
      Width := GPImage.GetWidth;
      Height := GPImage.GetHeight;
      GPImage.Free;  ptWinPos.X := 20;
      ptWinPos.Y := 20;
      sizeWindow.cx := Width;
      sizeWindow.cy := Height;
      ptSrc.x := 0;
      ptSrc.y := 0;
      W;
      ReDraw;
    end;procedure Tform1.W;
    var GPGraph: TGPGraphics;
      hdcTemp: HDC;
      hBMP: HBITMAP;
      GPImage: TGPImage;
    begin
      hdcTemp := CreateDC('DISPLAY', nil, nil, nil);
      w_memory := CreateCompatibleDC(hdcTemp);
      hBMP := CreateCompatibleBitmap(hdcTemp, Width, Height);
      GPImage := TGPImage.Create('w\12.png');
      SelectObject(w_memory, hBMP);
      GPGraph := TGPGraphics.Create(w_memory);
      GPGraph.DrawImage(GPImage, 0, 0, GPImage.GetWidth(), GPImage.GetHeight());
      GPImage.Free;
      GPGraph.ReleaseHDC(w_memory);
      GPGraph.Free;
      DeleteObject(hBMP);
      ReleaseDC(0, hdcTemp);
      DeleteDC(hdcTemp);
    end;procedure Tform1.ReDraw;
    var hDC, hdcScreen, m_hdcMemory, hOldHandle: THandle;
      hBMP: HBITMAP;
      GPGraph: TGPGraphics;
      GPImage: TGPImage;
    begin
      hdc := GetDC(0);
      hdcScreen := GetDC(0);
      GPImage := TGPImage.Create('backend.png');
      m_hdcMemory := CreateCompatibleDC(hDC);
      hBMP := CreateCompatibleBitmap(hdc, Width, Height);
      hOldHandle := SelectObject(m_hdcMemory, hBMP);
      GPGraph := TGPGraphics.Create(m_hdcMemory);
      GPGraph.DrawImage(GPImage, 0, 0, GPImage.GetWidth, GPImage.GetHeight);
      DeleteObject(hBMP);  try
        Windows.AlphaBlend(m_hdcMemory, 0, 0, Width, Height, w_memory, 0, 0, Width, Height, m_Blend);
        SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED);
        UpdateLayeredWindow(Handle, hdcScreen, @ptWinPos, @sizeWindow, m_hdcMemory, @ptSrc, 0, @m_Blend, 2);
      finally
        GPImage.Free;
        GPGraph.ReleaseHDC(m_hdcMemory);
        GPGraph.Free;
        SelectObject(m_hdcMemory, hOldHandle);
        ReleaseDC(0, hDC);
        ReleaseDC(0, hdcScreen);
        DeleteDC(m_hdcMemory);
      end;
      OldStyle := GetWindowLong(Handle, GWL_EXSTYLE);
    end;
      

  5.   

    procedure Tform1.W;
    var GPGraph: TGPGraphics;
      hdcTemp: HDC;
      hBMP: HBITMAP;
      GPImage: TGPImage;
    begin
      hdcTemp := CreateDC('DISPLAY', nil, nil, nil);
      w_memory := CreateCompatibleDC(hdcTemp);
      hBMP := CreateCompatibleBitmap(hdcTemp, Width, Height);
      GPImage := TGPImage.Create('w\12.png');
      SelectObject(w_memory, hBMP);
      GPGraph := TGPGraphics.Create(w_memory);
      GPGraph.DrawImage(GPImage, 0, 0, GPImage.GetWidth(), GPImage.GetHeight());
      GPImage.Free;
      GPGraph.ReleaseHDC(w_memory);
      GPGraph.Free;
      DeleteObject(hBMP);
      ReleaseDC(0, hdcTemp);
      DeleteDC(hdcTemp);
    end;这个函数可能有问题,  w_memory := CreateCompatibleDC(hdcTemp);要改成w_memory := CreateCompatibleDC(0);否则位图可能选不进去。
    可能已经有人说过了,位图能否选进一个DC,是有规则的:
    1. 兼容DC只能选兼容位图,即位图格式和DC中的位图格式完全一样;
    2. 内存DC可以选入任何设备无关位图;
    hBMP := CreateCompatibleBitmap(hdcTemp, Width, Height);
    这也有问题,虽然这样创建是兼容了,但是在屏幕是16位色的情况下,你的位图也是16位的了,就没有alpha通道了。应当改成用CreateDIBSection函数来创建。
      

  6.   

    我想问问叠加后的结果输出成jpg图片