Kackao
Kackao

Reputation: 1291

Create transparent bitmap with Gdiplus in C++

In C++, I want to create a simple transparent image with Gdiplus and save it as a png. I have the following code:

    // 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);

When I save the image to png, I can see that there is an alpha channel, but its set to 0, so nothing transparent (RGB is all set). I also tried changing the 255 to 0, but that only gives me a black image with no transpirancy. Why is the Fillmemory call not filling the alpha channel, or am I missing something else?

Upvotes: 2

Views: 3263

Answers (3)

user7860670
user7860670

Reputation: 37588

Your code suffers from the same hdc problems as in previous question. A filling image with 0 should give a completely transparent black image as expected.

But I think it would be simpler to create bitmap directly specifying dimensions and pixel format and set content later:

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

Upvotes: 2

Barmak Shemirani
Barmak Shemirani

Reputation: 31639

FillMemory(pvBits, bmi.bmiHeader.biSizeImage, 255) will fill the memory with solid white color. If you write over the image with GDI functions, the alpha values remain unchanged. You won't see any transparency even if the file supports it.

To create 32-bit image you only need Gdiplus::Bitmap(w, h, PixelFormat32bppARGB). There is no need for BITMAPINFO and CreateDIBSection

If you mix GDI+ with GDI functions, you may want to reset alpha after writing with GDI functions. For example:

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

Upvotes: 2

Martin Steen
Martin Steen

Reputation: 24

In transparent images, the value 0 means "full transparent" and 255 means "full opaque".

Upvotes: -1

Related Questions