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

标签 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 channel ,但它设置为 0,因此没有任何透明内容(RGB 均已设置)。我也尝试将 255 更改为 0,但这只会给我一个黑色图像,没有蒸腾效果。为什么 Fillmemory 调用没有填充 Alpha channel ,还是我遗漏了其他内容?

最佳答案

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;
}

关于c++ - 在 C++ 中使用 Gdiplus 创建透明位图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51555487/

相关文章:

C++ 自定义模板 LinkedList 崩溃添加 std::string

winapi - 我使用 UpdateLayeredWindow 的代码不起作用

c++ - 使用 GDI+ 绘制文本

c++ - 使用 Microsoft Detours - 一堆未定义的

c# - DrawPath 和 DrawRectangle 的区别

c++ - C++ 中的模板和继承

C++如何在不调用构造函数的情况下分配对象

c++ - QTime->addSecs 导致段错误

用于分离辅助监视器的 C++ 应用程序

c# - 算术运算导致溢出 c#