Question

I have an application which loads some blob data out of a database which can represent png formatted or raw binary data for various bitmaps and icons. This is being stored in a std::vector<unsigned char>

I'm using CImageList objects to display various images in tree views, toolbar images, etc but the problem is creating bitmaps from the data in memory are coming out fuzzy as if it's missing pixels when doing something like below:

std::vector<unsigned char> bits;
HBITMAP hbitmap = CreateBitmap(16, 16, 1, 32, bits.data());

To work around this issue for now I am simply writing out the data() in the vector to a temporary file and then using LoadImage to read it back in and creating the HBITMAP from that. This works perfectly however that is admittedly a shameless hack and should be completely unnecessary I would hope.

I've looked around online but haven't found any really good examples of how to "properly" create hbitmaps from memory. I would like to be able to create these bitmaps to be added to the image list without any file i/o and limited amounts of copying the data around if possible.

Looking for the best way to do this and obviously windows specific code is fine.

UPDATE:

Based on jdv's answer I began playing with CreateCompatibleBitmap, CreateDIBitmap, and finally CreateDIBSection. All of these ended up creating lovely black bitmaps instead of the previous fuzzy bitmaps so I must be doing something wrong again and my guess is since this bitmap creation is being done in an object that has no concept of the screen dc or window that using GetDC(NULL) and CreateCompatibleDC(NULL) are no good. Sample code:

    BITMAPINFO bmi;
    ZeroMemory(&bmi, sizeof(BITMAPINFO));
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biBitCount = 32;
    bmi.bmiHeader.biHeight = 16;
    bmi.bmiHeader.biWidth = 16;
    bmi.bmiHeader.biPlanes = 1;

    HDC dc = CreateCompatibleDC(NULL);
    HBITMAP hbitmap = CreateDIBSection(dc, &bmi, DIB_RGB_COLORS, (void**)blobData.GetMember<FILEDATAFIELD_DATA>().data(), NULL, 0);

I am now of course thinking there has got to be a simpler way to go about this perhaps by avoiding the HBITMAP altogether and working directly with CBitmap class? When it comes down to adding the image to the CImageList I'm using CBitmap::FromHandle(HBITMAP hbitmap, COLORREF mask) anyway. Does anyone know a simple way to initialize a CBitmap object from a std::vector<unsigned char>?

Was it helpful?

Solution 2

Using GdiPlus I got something that works pretty well and doesn't involve pulling any teeth!

Gdiplus::Bitmap* pBitmap = NULL;
IStream* pStream = NULL;

HRESULT hResult = ::CreateStreamOnHGlobal( NULL, TRUE, &pStream );
if(hResult == S_OK && pStream)
{
    hResult = pStream->Write(&bits[0], ULONG(bits.size()), NULL);
    if(hResult == S_OK)
        pBitmap = Gdiplus::Bitmap::FromStream(pStream);
    pStream->Release();
}

Edit: Changed per Jegatheesh

OTHER TIPS

I'd use CreateCompatibleBitmap, and then call SetDIBits to fill it with your data. These are functions I have seen to work, and SetDIBits is quite flexible, although verbose.

In my MFC years, CreateBitmap was avoided due to suspected performance issues.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top