Создание HBITMAP из буфера памяти - PullRequest
11 голосов
/ 05 января 2011

У меня есть приложение, которое загружает некоторые двоичные данные из базы данных, которые могут представлять отформатированные в png или необработанные двоичные данные для различных растровых изображений и значков. Это хранится в std::vector<unsigned char>

Я использую CImageList объекты для отображения различных изображений в древовидных представлениях, изображениях панелей инструментов и т. Д., Но проблема заключается в создании растровых изображений из данных в памяти, которые выглядят нечеткими, как будто отсутствуют пиксели при выполнении чего-то подобного ниже:

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

Чтобы обойти эту проблему сейчас, я просто записываю 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>?

Ответы [ 2 ]

5 голосов
/ 05 января 2011

Я бы использовал CreateCompatibleBitmap, а затем позвонил бы SetDIBits, чтобы заполнить его вашими данными.Это функции, которые я видел в работе, и SetDIBits довольно гибок, хотя и многословен.

В годы моей МФЦ CreateBitmap удалось избежать из-за подозрений в производительности.

3 голосов
/ 06 января 2011

Используя 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();
}

Редактировать: Изменено за Джегатиши

...