Reputation: 1291
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
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
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
Reputation: 24
In transparent images, the value 0 means "full transparent" and 255 means "full opaque".
Upvotes: -1