给位图添加 Alpha 通道或将位图转换为 32 位。

4

解决方案: 当前代码示例:

HBITMAP TwoBitmap(HDC &hdc, RECT &rc)
{
    HDC hdcmem = CreateCompatibleDC(hdc);
    HBITMAP hbitmap = CreateCompatibleBitmap(hdc, rc.right-rc.left, rc.bottom-rc.top);
    SelectObject(hdcmem, hbitmap);

    HBRUSH hBrush = GetSysColorBrush(2);
    FillRect(hdcmem, &rc, hBrush);
    DeleteObject((HBRUSH)hBrush);

    DeleteDC(hdcmem);

    return hbitmap;
}

void CreateTransparentBitmap(HBITMAP &hBitmap)
{
    BITMAP TemporaryBitmap;
    GetObject(hBitmap, sizeof(BITMAP), &TemporaryBitmap);

    HDC MemoryDC = CreateCompatibleDC(NULL);

    BITMAPINFO BitmapInfo;
    ZeroMemory(&BitmapInfo,sizeof(BITMAPINFO));
    BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    BitmapInfo.bmiHeader.biWidth = TemporaryBitmap.bmWidth;
    BitmapInfo.bmiHeader.biHeight = TemporaryBitmap.bmHeight;
    BitmapInfo.bmiHeader.biPlanes = 1;
    BitmapInfo.bmiHeader.biBitCount = 32;
    BitmapInfo.bmiHeader.biCompression = BI_RGB;

    RGBQUAD* pArgb = NULL;
    HBITMAP hTemporaryBitmap = CreateDIBSection(MemoryDC, &BitmapInfo, DIB_RGB_COLORS, (void**)&pArgb, NULL, 0);

    GetDIBits(MemoryDC, hBitmap, 0, BitmapInfo.bmiHeader.biHeight, pArgb, &BitmapInfo, DIB_RGB_COLORS);

    for (int i = 0; i < BitmapInfo.bmiHeader.biWidth * BitmapInfo.bmiHeader.biHeight; i++)
        pArgb[i].rgbReserved = 255;

    DeleteDC(MemoryDC);

    DeleteObject(hBitmap);
    hBitmap = hTemporaryBitmap;
}

case WM_PAINT:
    {
        PAINTSTRUCT p;
        HDC hDC = BeginPaint(hWnd, &p);
        HDC hdcmem = CreateCompatibleDC(hDC);

        HBITMAP hImage = TwoBitmap(hDC, p.rcPaint);

        CreateTransparentBitmap(hImage);

        SelectObject(hdcmem, hImage);

        BLENDFUNCTION bfn;
        bfn.BlendOp = AC_SRC_OVER;
        bfn.BlendFlags = 0;
        bfn.SourceConstantAlpha = 10;
        bfn.AlphaFormat = AC_SRC_ALPHA;

        AlphaBlend(hDC, 0, 0, 100, 64, hdcmem, 0, 0, 100, 64, bfn);

        bfn.SourceConstantAlpha = 80;
        AlphaBlend(hDC, 200, 0, 100, 64, hdcmem, 0, 0, 100, 64, bfn);

        bfn.SourceConstantAlpha = 255;
        AlphaBlend(hDC, 400, 0, 100, 64, hdcmem, 0, 0, 100, 64, bfn);

        BitBlt(hDC, 0, 100, 100, 64, hdcmem, 0, 0, SRCCOPY);

        DeleteDC(hdcmem);

        DeleteObject(hImage);

        EndPaint(hWnd, &p);
    }
    break;

为了举例说明,我使用CreateCompatibleBitmap()创建了一个简单的位图:
HBITMAP TwoBitmap(HDC &hdc, RECT &rc)
{
    HDC hdcmem = CreateCompatibleDC(hdc);
    HBITMAP hbitmap = CreateCompatibleBitmap(hdc, rc.right-rc.left, 
                                             rc.bottom-rc.top);
    SelectObject(hdcmem, hbitmap);

    HBRUSH hBrush = GetSysColorBrush(3);
    FillRect(hdcmem, &rc, hBrush);
    DeleteObject((HBRUSH)hBrush);

    DeleteDC(hdcmem);

    return hbitmap;
}

现在,我想要实现的是给这个位图添加 alpha 通道(如果它还没有)。使用下面的代码,我尝试创建一个32位的位图,然后将旧位图复制到这个新位图中。最后,我使用 AlphaBlend() 和 BitBlt() 函数将新位图打印到屏幕上,并像往常一样得到了单色 alpha 混合图像和完美的 BitBlt 图像。
所以我的问题在于 - 我缺少什么,做错了什么?我很迷茫。我的代码(不要注意 GDI 泄漏):
编辑:
感谢 PhoenixX_2,我成功解决了这个谜团,我所需要做的就是将 Alpha 位设置为 255。以下是我的代码,请注意,它并不是无泄漏的。
PAINTSTRUCT p;
HDC hDC = BeginPaint(hWnd, &p);

HDC BufferDC = CreateCompatibleDC(NULL);

BITMAPINFO BufferInfo;
ZeroMemory(&BufferInfo,sizeof(BITMAPINFO));
BufferInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
BufferInfo.bmiHeader.biWidth = p.rcPaint.right-p.rcPaint.left;
BufferInfo.bmiHeader.biHeight = p.rcPaint.bottom-p.rcPaint.top;
BufferInfo.bmiHeader.biPlanes = 1;
BufferInfo.bmiHeader.biBitCount = 32;
BufferInfo.bmiHeader.biCompression = BI_RGB;
RGBQUAD* pArgb;
HBITMAP BufferBitmap = CreateDIBSection(BufferDC, &BufferInfo, DIB_RGB_COLORS,
                                       (void**)&pArgb, NULL, 0);

HBITMAP hImage  =  TwoBitmap(hDC, p.rcPaint);

GetDIBits(BufferDC, hImage, 0, BufferInfo.bmiHeader.biHeight, pArgb, 
          &BufferInfo, DIB_RGB_COLORS);

//----------------------------------the part I was missing
for (int i = 0; i < BufferInfo.bmiHeader.biWidth 
     * BufferInfo.bmiHeader.biHeight; i++)
pArgb[i].rgbReserved = 255;
//----------------------------------

SelectObject(BufferDC, BufferBitmap);

BLENDFUNCTION bfn;
bfn.BlendOp = AC_SRC_OVER;
bfn.BlendFlags = 0;
bfn.SourceConstantAlpha = 10;
bfn.AlphaFormat = AC_SRC_ALPHA;

AlphaBlend(hDC, 0, 0, 100, 64, BufferDC, 0, 0, 100, 64, bfn);

bfn.SourceConstantAlpha = 80;
AlphaBlend(hDC, 200, 0, 100, 64, BufferDC, 0, 0, 100, 64, bfn);

bfn.SourceConstantAlpha = 255;
AlphaBlend(hDC, 400, 0, 100, 64, BufferDC, 0, 0, 100, 64, bfn);

BitBlt(hDC, 0, 100, 100, 64, BufferDC, 0, 0, SRCCOPY);

DeleteDC(BufferDC);

DeleteObject((HBITMAP)BufferBitmap);

EndPaint(hWnd, &p);

它看起来很相似 https://dev59.com/emTWa4cB1Zd3GeqPG9L8 - ColdCat
它很相似,但我有一个位图需要添加 alpha 通道,而这个已经在现场创建了它。 - FrogTheFrog
1个回答

3
我强烈建议您使用像FreeImage这样的库。除了它相当轻量级和非常开放的许可证之外,该库的好处是它可以轻松处理所有图像类型。然后将任何格式(包括不同的位图格式)转换为32位是微不足道的。渲染和其他任务也是如此。
除此之外,如果您不想使用库,则只需自己操作像素数据。使用两个点和类型转换从24位转换为32位相当简单。像这样的东西应该可以做到:
uint8_t* pArgb;
uint8_t* pRgb;

GetDIBits(BufferDC, hImage, 0, BufferInfo.bmiHeader.biHeight, pRgb, &BufferInfo, DIB_RGB_COLORS);

pArgb = (uint8_t*)malloc(4 * BufferInfo.bmiHeader.biWidth * BufferInfo.bmiHeader.biHeight);
for (int i = 0; i < BufferInfo.bmiHeader.biWidth * BufferInfo.bmiHeader.biHeight; ++i) {
    *(int*)pArgb = 0xff000000 | (*(int*)(pRgb) >> 8);
    pArgb += 4;
    pRgb += 3;
}

我不想使用其他库,你能否给一个适当转换的例子? - FrogTheFrog
我想我找到了我的问题,只是一个快速的问题。Alpha位必须是255吗? - FrogTheFrog
如果你想让它不透明,没问题 :)。 - Mike Weir

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