AlphaBlend返回“false”的原因可能是什么?

5

我正在尝试拉伸带有alpha通道的HBITMAP并将其绘制到另一个hdc上。

我正在使用StretchDIBits,然后是AlphaBlend,如下所示的代码。

问题在于AlphaBlend失败并返回false。
1. 有人知道可能的原因吗? 2. 是否有更好的方法可以拉伸和绘制透明图像?

void AnimationManager::Draw(HDC hBBDC, Instance sInstance,RECT sClientRect)
{
    // sClientRect is the hwnd rect

    int nID = GetId(sInstance.nAnemationId);
    int nFrameindex = sInstance.nFrameIndexs;

    HDC hdcScreen = GetDC(NULL);
    HDC hdcMem = CreateCompatibleDC(hdcScreen);

    BITMAP bmp;
    PBITMAPINFO pbmi;
    WORD cClrBits;

    ///******************* create PBITMAPINFO *********************///

    GetObject(m_pAnimations[nID]->m_pFramesArray[nFrameindex]->hBmp, sizeof(bmp), &bmp);
    cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
    if(cClrBits == 1)
        cClrBits = 1;
    else if(cClrBits <= 4)
            cClrBits = 4;
    else if(cClrBits <= 8)
            cClrBits = 8;
    else if(cClrBits <= 24)
            cClrBits = 24;
    else cClrBits = 32;

    if(cClrBits != 24)
        pbmi = (PBITMAPINFO)LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*(1<<cClrBits));
    else
        pbmi = (PBITMAPINFO)LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER));

    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    pbmi->bmiHeader.biWidth = bmp.bmWidth;
    pbmi->bmiHeader.biHeight = bmp.bmHeight;
    pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
    pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
    if(cClrBits < 24)
        pbmi->bmiHeader.biClrUsed = (1<<cClrBits);

    pbmi->bmiHeader.biCompression = BI_RGB;

    pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits + 31)& ~31)/8 * pbmi->bmiHeader.biHeight;
    pbmi->bmiHeader.biClrImportant = 0;


    ///**************************end PBITMAPINFO creation *****************************************///


    // I checked the code to this point and it seems to be fine. The problem stasrts here:

    ///create a pointer to the image bits
    LPVOID lpvBits = (LPVOID)LocalAlloc(GPTR,pbmi->bmiHeader.biSizeImage);
    GetBitmapBits(m_pAnimations[nID]->m_pFramesArray[nFrameindex]->hBmp, pbmi->bmiHeader.biSizeImage, lpvBits);

    ///stretch
    bool test = StretchDIBits(hdcMem,0,sClientRect.bottom,sClientRect.right, -1*sClientRect.bottom,0,0,pbmi->bmiHeader.biWidth,pbmi->bmiHeader.biHeight, lpvBits,pbmi,DIB_RGB_COLORS, SRCCOPY);

    ///blend
    test = AlphaBlend(hBBDC,0,0,sClientRect.right, sClientRect.bottom,hdcMem,0,0,sClientRect.right,sClientRect.bottom,m_sBlendfunc);


    test = DeleteDC(hdcMem);  // after CreateCompatibleDC
    test = ReleaseDC(NULL, hdcScreen); // after GetDC

    LocalFree(pbmi);
    LocalFree(lpvBits);
}

3
直到你让Windows告诉你,你才会知道。使用GetLastError()函数。 - Hans Passant
1
不幸的是,GetLastError 没有什么用处,总是返回代码 87,表示参数无效。 - Graham Asher
没有调用SelectObject。我认为你需要使用SelectObject将位图选择到兼容的DC中。请参见下面我的答案中的示例代码。 - Graham Asher
2个回答

0

如果AlphaBlend也可以拉伸,为什么要使用StretchDIBits呢?


0

我无法确切地说明代码为什么失败,但是我从最近的经验中知道AlphaBlend非常挑剔它接受的位图格式。幸运的是,我可以提供一些工作代码,这些代码应该适用于其他情况。

static void DrawBitmapWithAlpha(HDC aDeviceContext,const CartoType::TBitmap* aBitmap,const CartoType::TRect& aDestRect,const CartoType::TRect& aSourceRect)
{
HDC hdc = CreateCompatibleDC(aDeviceContext);
BITMAPINFOHEADER bitmap_header;
memset(&bitmap_header,0,sizeof(bitmap_header));
bitmap_header.biSize = sizeof(BITMAPINFOHEADER);
bitmap_header.biWidth = aBitmap->Width();
bitmap_header.biHeight = aBitmap->Height();
bitmap_header.biPlanes = 1;
bitmap_header.biBitCount = 32;
bitmap_header.biCompression = BI_RGB;
bitmap_header.biSizeImage = 0;
bitmap_header.biXPelsPerMeter = 1000;
bitmap_header.biYPelsPerMeter = 1000;
bitmap_header.biClrUsed = 0;
bitmap_header.biClrImportant = 0;

void* bitmap_data = NULL;
HBITMAP hbitmap = CreateDIBSection(hdc,(const BITMAPINFO*)&bitmap_header,DIB_RGB_COLORS,&bitmap_data,NULL,0);

// Reflect the data vertically and change from ABGR to BGRA.
unsigned char* dest_row = (unsigned char*)bitmap_data;
const unsigned char* source_row = aBitmap->Data() + (aBitmap->Height() - 1) * aBitmap->RowBytes();
for (int y = 0; y < aBitmap->Height(); y++, dest_row += aBitmap->RowBytes(), source_row -= aBitmap->RowBytes())
    {
    const unsigned char* p = source_row;
    unsigned char* q = dest_row;
    unsigned char* end = q + aBitmap->RowBytes();
    while (q < end)
        {
        *q++ = p[1];
        *q++ = p[2];
        *q++ = p[3];
        *q++ = p[0];
        p += 4;
        }
    }
SelectObject(hdc,hbitmap);

BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 0xFF;
bf.AlphaFormat = AC_SRC_ALPHA;

AlphaBlend(aDeviceContext,aDestRect.Left(),aDestRect.Top(),aDestRect.Width(),aDestRect.Height(),
           hdc,aSourceRect.Left(),aSourceRect.Top(),aSourceRect.Width(),aSourceRect.Height(),
           bf);

DeleteObject(hbitmap);
DeleteDC(hdc);
}

从“垂直反映数据”开始的部分可以轻松更改,以执行将位图数据复制到通过CreateDIBSection创建的位图所需的任何操作。

我的位图格式与Windows兼容,因为它的行字节数始终相同; 如果您的位图格式没有此属性,则需要更改代码以相应地复制数据。

另一个有用的提示:我无法使用位域使其正常工作; 我进一步怀疑您必须提供压缩设置为BI_RGB的32bpp位图。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接