在C ++中使用Gdiplus创建透明位图

时间:2018-07-27 09:59:01

标签: c++ winapi gdi+ gdi

在C ++中,我想用Gdiplus创建一个简单的透明图像并将其另存为png。我有以下代码:

    // These variables are class members and got initialized and are used elsewhere
    BITMAPINFO bmi;
    HDC hdc;
    void* pvBits;

    ZeroMemory(&bmi, sizeof(BITMAPINFO));
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = some_width;
    bmi.bmiHeader.biHeight = some_height;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32;
    bmi.bmiHeader.biCompression = BI_RGB;
    bmi.bmiHeader.biSizeImage = ((((bmi.bmiHeader.biWidth * bmi.bmiHeader.biBitCount) + 31) & ~31) >> 3) * bmi.bmiHeader.biHeight;

    HBITMAP hBM = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, &pvBits, NULL, 0x0);
    FillMemory(pvBits, bmi.bmiHeader.biSizeImage, 255);

    HGDIOBJ oldObj = SelectObject(hDC, hBM);
    ReleaseDC(NULL, hDC);

    GdiFlush();

    GdiPlusBitmap* bitmap = new Gdiplus::Bitmap(&bmi, pvBits);

当我将图像保存为png时,我可以看到有一个alpha通道,但是它设置为0,所以没有透明(RGB全部设置)。我还尝试将255更改为0,但这只给了我黑色图像而没有透汗感。为什么Fillmemory呼叫未填充alpha通道,还是我错过了其他内容?

3 个答案:

答案 0 :(得分:1)

您的代码遭受与previous question中相同的hdc问题。用0填充图像应该可以得到完全透明的黑色图像。

但是我认为创建直接指定尺寸和像素格式并稍后设置内容的位图会更简单:

GdiPlusBitmap* bitmap = new Gdiplus::Bitmap(width, height, Gdiplus::PixelFormat32bppARGB);

答案 1 :(得分:1)

FillMemory(pvBits, bmi.bmiHeader.biSizeImage, 255)将用纯白色填充内存。如果使用GDI功能覆盖图像,则alpha值保持不变。即使文件支持,您也不会看到任何透明度。

要创建32位图像,您只需要Gdiplus::Bitmap(w, h, PixelFormat32bppARGB)。不需要BITMAPINFOCreateDIBSection

如果将GDI +与GDI功能混合使用,则可能需要在使用GDI功能编写后重置Alpha。例如:

void test()
{
    int w = 100;
    int h = 100;
    int bitcount = 32;

    int size = ((((w * bitcount) + 31) & ~31) >> 3) * h;

    BITMAPINFO bmi = { 0 };
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = w;
    bmi.bmiHeader.biHeight = -h;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = bitcount;
    bmi.bmiHeader.biCompression = BI_RGB;
    bmi.bmiHeader.biSizeImage = size;

    HDC hdc = GetDC(0);
    BYTE* pvBits = NULL;
    HBITMAP hbitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS,
             (void**)&pvBits, NULL, 0x0);
    FillMemory(pvBits, size, 0);

    auto memdc = CreateCompatibleDC(hdc);
    auto oldbmp = SelectObject(memdc, hbitmap);
    SetBkColor(memdc, RGB(255, 0, 0));
    TextOut(memdc, 0, 0, L"123", 3);

    //GDI cleanup, don't delete hbitmap yet
    SelectObject(memdc, oldbmp);
    DeleteDC(memdc);
    ReleaseDC(0, hdc);

    //make the non-zero colors transparent:
    for(int i = 0; i < size; i += 4)
    {
        int n = *(int*)(pvBits + i);
        if (n != 0)
            pvBits[i + 3] = 255;
    }

    CLSID clsid_png;
    CLSIDFromString(L"{557cf406-1a04-11d3-9a73-0000f81ef32e}", &clsid_png);

    Gdiplus::Bitmap* bitmap = new Gdiplus::Bitmap(w, h, PixelFormat32bppARGB);
    Gdiplus::BitmapData data;
    bitmap->LockBits(&Gdiplus::Rect(0, 0, w, h), 
        Gdiplus::ImageLockModeWrite, PixelFormat32bppARGB, &data);
    memcpy(data.Scan0, pvBits, size);
    bitmap->UnlockBits(&data);

    //safe to delete hbitmap
    DeleteObject(hbitmap);

    bitmap->Save(L"test.png", &clsid_png);

    delete bitmap;
}

答案 2 :(得分:-1)

在透明图像中,值0表示“完全透明”,而值255表示 “完全不透明”。