Создание HBITMAP из буфера памяти
У меня есть приложение, которое загружает некоторые данные blob из базы данных, которые могут представлять png отформатированные или необработанные двоичные данные для различных растровых изображений и значков. Это сохраняется в std::vector<unsigned char>
Я использую объекты CImageList
для отображения различных изображений в древовидных структурах, изображениях на панели инструментов и т.д., но проблема в создании растровых изображений из данных в памяти выходит нечеткой, как если бы она отсутствовала при выполнении следующих действий:
std::vector<unsigned char> bits;
HBITMAP hbitmap = CreateBitmap(16, 16, 1, 32, bits.data());
Чтобы обойти эту проблему, я просто записываю данные() в векторе во временный файл, а затем используя LoadImage, чтобы прочитать его обратно и создать HBITMAP из этого. Это прекрасно работает, однако, это, по общему признанию, бесстыдный хак, и я должен был быть совершенно ненужным.
Я посмотрел онлайн, но не нашел действительно хороших примеров того, как "правильно" создавать hbitmaps из памяти. Я хотел бы иметь возможность создавать эти растровые изображения, которые будут добавлены в список изображений без ввода файлов и ограниченных копий данных, если это возможно.
Ищите лучший способ сделать это, и, очевидно, код, специфичный для Windows, хорош.
UPDATE:
На основе ответа jdv я начал играть с CreateCompatibleBitmap, CreateDIBitmap и, наконец, с CreateDIBSection. Все это привело к созданию прекрасных черных растровых изображений вместо предыдущих нечетких растровых изображений, поэтому я должен повторить что-то неправильно, и я предполагаю, что это создание растрового изображения выполняется в объекте, который не имеет представления о экране dc или окне, использующем GetDC(NULL)
и CreateCompatibleDC(NULL)
не подходят. Пример кода:
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);
Теперь я, конечно, думаю, что есть более простой способ сделать это, возможно, вообще избегая HBITMAP и работая непосредственно с классом CBitmap
? Когда дело доходит до добавления изображения в CImageList
, я все равно использую CBitmap::FromHandle(HBITMAP hbitmap, COLORREF mask)
. Кто-нибудь знает простой способ инициализировать объект CBitmap
из std::vector<unsigned char>
?
Ответы
Ответ 1
Использование GdiPlus У меня есть что-то, что работает очень хорошо и не требует вытягивания зубов!
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();
}
Изменить: Изменено для Jegatheesh
Ответ 2
Я бы использовал CreateCompatibleBitmap
, а затем позвонил SetDIBits
, чтобы заполнить его вашими данными. Это функции, которые я видел для работы, и SetDIBits довольно гибкий, хотя и подробный.
В мои годы MFC, CreateBitmap
было предотвращено из-за подозрительных проблем с производительностью.