12

さまざまなビットマップやアイコンのpng形式または生のバイナリデータを表すことができるデータベースからいくつかのblobデータをロードするアプリケーションがあります。これはに保存されていますstd::vector<unsigned char>

オブジェクトを使用CImageListしてツリービューやツールバー画像などにさまざまな画像を表示していますが、問題は、メモリ内のデータからビットマップを作成すると、次のような操作を行うとピクセルが欠落しているようにぼやけてしまうことです。

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

今のところこの問題を回避するために、ベクター内のdata()を一時ファイルに書き出し、LoadImageを使用してそれを読み戻し、そこからHBITMAPを作成しています。これは完全に機能しますが、それは確かに恥知らずなハックであり、私が望むのは完全に不要なはずです。

私はオンラインで調べましたが、メモリからhbitmapを「適切に」作成する方法の本当に良い例は見つかりませんでした。これらのビットマップを作成して、ファイルI / Oを使用せずに、可能であればデータを限られた量だけコピーして、画像リストに追加できるようにしたいと思います。

これを行うための最良の方法を探しており、明らかにWindows固有のコードで問題ありません。

アップデート:

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>ますか?

4

3 に答える 3

6

を使用CreateCompatibleBitmapしてから、を呼び出しSetDIBitsてデータを入力します。これらは私が機能するのを見た関数であり、SetDIBitsは冗長ですが、非常に柔軟性があります。

私のMFC時代にCreateBitmapは、パフォーマンスの問題が疑われるために回避されました。

于 2011-01-04T22:22:44.660 に答える
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ごとに変更

于 2011-01-06T15:13:28.743 に答える
1

の代わりにSHCreateMemStreamを使用する、 AJG85によって提供される回答のわずかなバリエーション。Windows VistaでパブリックAPIとして導入され、メモリ内の既存の領域を超えて作成するという利点があり、追加のメモリ割り当てを回避できます。CreateStreamOnHGlobalSHCreateMemStreamIStream

#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

関数が戻ると、メモリバッファを安全に解放できます。返されたものは呼び出し元が所有しており、 DeleteObjectHBITMAPを呼び出して解放する必要があります。

于 2020-07-06T10:03:04.443 に答える