从内存缓冲区创建HBITMAP

时间:2011-01-04 21:56:52

标签: c++ mfc bitmap gdi hbitmap

我有一个应用程序可以从数据库中加载一些blob数据,这些数据可以代表各种位图和图标的png格式或原始二进制数据。这存储在std::vector<unsigned char>

我正在使用CImageList个对象在树视图,工具栏图像等中显示各种图像,但问题是从内存中的数据创建位图模糊,好像它在执行下面的操作时缺少像素:

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

要解决此问题,我现在只需将向量中的data()写入临时文件,然后使用LoadImage将其读回并从中创建HBITMAP。这完全有效,然而这无疑是一个无耻的黑客,我希望完全没必要。

我在网上看过,但没有找到任何关于如何“正确”从内存创建hbitmaps的好例子。我希望能够创建这些位图,以便在没有任何文件i / o的情况下添加到图像列表中,并在可能的情况下复制数据的数量有限。

寻找最好的方法来实现这一点,显然Windows专用代码很好。

更新:

根据jdv的回答,我开始玩CreateCompatibleBitmap,CreateDIBitmap,最后是CreateDIBSection。所有这些最终都创建了可爱的黑色位图,而不是之前的模糊位图,所以我必须再次做错了我的猜测是因为这个位图创建是在一个没有屏幕dc或窗口概念的对象中完成的{ {1}}和GetDC(NULL)并不好。示例代码:

CreateCompatibleDC(NULL)

我现在当然认为必须有一个更简单的方法可以通过完全避免HBITMAP并直接与 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); 类一起工作?当我将图像添加到CBitmap时,无论如何我都在使用CImageList。有没有人知道从CBitmap::FromHandle(HBITMAP hbitmap, COLORREF mask)初始化CBitmap对象的简单方法?

3 个答案:

答案 0 :(得分:5)

我使用CreateCompatibleBitmap,然后致电SetDIBits以填充您的数据。这些是我见过的功能,而且SetDIBits非常灵活,虽然冗长。

在我的MFC年代,由于涉嫌性能问题而避免CreateBitmap

答案 1 :(得分:3)

使用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 :(得分:0)

answer提供的AJG85的细微变化,它使用SHCreateMemStream代替CreateStreamOnHGlobalSHCreateMemStream作为Windows Vista中的公共API引入,它的好处是可以在内存中的现有区域上创建IStream,从而避免了额外的内存分配:

#include <Shlwapi.h>
#include <atlimage.h>
#include <comdef.h>
#include <comip.h>

#include <vector>

#pragma comment(lib, "Shlwapi.lib")
#if defined(_DEBUG)
#    pragma comment(lib, "comsuppwd.lib")
#else
#    pragma comment(lib, "comsuppw.lib")
#endif


HBITMAP from_data(std::vector<unsigned char> const& data)
{
    if (data.empty())
    {
        _com_issue_error(E_INVALIDARG);
    }

    auto const stream { ::SHCreateMemStream(&data[0], static_cast<UINT>(data.size())) };
    if (!stream)
    {
        _com_issue_error(E_OUTOFMEMORY);
    }
    _COM_SMARTPTR_TYPEDEF(IStream, __uuidof(IStream));
    IStreamPtr sp_stream { stream, false };

    CImage img {};
    _com_util::CheckError(img.Load(sp_stream));

    return img.Detach();
}

此实现要么抛出_com_error,要么返回引用由内存数据构造的图像的HBITMAP

函数返回时,可以安全地释放内存缓冲区。返回的HBITMAP由调用方所有,并且需要通过调用DeleteObject来释放。