簡體   English   中英

從 bmp 文件數據創建 MFC CBitmap

[英]Create MFC CBitmap from bmp file data

我有一個指向從 *.bmp 文件中讀取的數據的 void 指針。 bmp 文件不再存在(現在有一個文件包含數百個這樣的 bitmap 文件數據集)。 如何使用此數據初始化 MFC CBitmap

我看到CBitmap::Create*函數(例如CreateBitmap()CreateCompatibleBitmap()等),但它們要求我知道位圖的高度和寬度,可以訪問數據位等。我可以寫入數據到磁盤,然后使用::LoadImage()CBitmap::Attach()加載 bitmap,但我想在 memory 中執行此操作以提高性能。

謝謝!

更新(#2):

這是我的代碼,正如 Constantine Georgiou 的評論和帖子(謝謝)所建議和簡化的那樣: CBitmap:,CreateBitmap() 不再失敗。 但 bitmap 顯示為黑色。

// Bitmap File Header
LPBITMAPFILEHEADER pFileHdr = (LPBITMAPFILEHEADER)pFileData;
// Bitmap Info Header
LPBITMAPINFOHEADER pBmpHdr = (LPBITMAPINFOHEADER)((PCHAR)pFileData + sizeof(BITMAPFILEHEADER));
// Image Data
LPVOID lpBits = (LPVOID)((PCHAR)pFileData + pFileHdr->bfOffBits);
if(!bitmap.CreateBitmap(pBmpHdr->biWidth, pBmpHdr->biHeight, pBmpHdr->biPlanes, pBmpHdr->biBitCount, lpBits))
    bool bummer = true;

這是將相同數據寫入文件然后使用::LoadImage() 加載 bitmap 的代碼。 這行得通。

CFile file;
if(file.Open(sFilename, CFile::modeCreate | CFile::modeReadWrite))
{
    file.Write(pFileData, dwFileBytes);
    file.Close();

    HBITMAP hBitmap = (HBITMAP)::LoadImage(NULL, sFilename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    if(hBitmap)
    {
        if(!bitmap.Attach(hBitmap))
            bool ahHeck = true;
    }
}

以下是有關上述內容的跟蹤消息。

在創建鏡像之前檢查 memory 中的文件數據:

  • dwFileBytes = 3128.
  • BMP HEADER:
  • biSize = 40
  • biWidth = 32
  • biHeight = 32
  • biPlans = 1
  • biBitCount = 24
  • biCompression = 0
  • biSizeImage = 3074

調用 CreateBitmap(32, 32, 1, 24, lpBits) 后檢查 BITMAP:

  • bmType = 0
  • bmWidth = 32
  • bmHeight = 32
  • bmPlanes= 1
  • bmWidthBytes = 96
  • bmBitsPixel = 24
  • bmBits = 0

(此 bitmap 顯示為黑色。)

寫入文件並調用 LoadImage() 后檢查 BITMAP:

  • bmType = 0
  • bmWidth = 32
  • bmHeight = 32
  • bmPlanes= 1
  • bmWidthBytes = 128
  • bmBitsPixel = 32
  • bmBits = 0

(此 bitmap 顯示正確。)

我意識到我正在深入了解細節。 道歉。 我難住了。

您的代碼是正確的,盡管我寧願將其簡化一點 - 無需復制這些結構,因為它們已經存在 - 只是一些類型轉換和指針算術。 例如:

// Bitmap File Header
LPBITMAPFILEHEADER pFileHdr = (LPBITMAPFILEHEADER)pFileData;

// Bitmap Info Header
LPBITMAPINFOHEADER pBmpHdr = (LPBITMAPINFOHEADER)((PCHAR)pFileData + sizeof(BITMAPFILEHEADER));

// Image Data
LPVOID lpBits = (LPVOID)((PCHAR)pFileData + pFileHdr->bfOffBits);

該文檔清楚地提到“位數”是每個像素的位數。 因此,電話將是:

if (!m_IconBitmap.CreateBitmap(pBmpHdr->biWidth, pBmpHdr->biHeight, pBmpHdr->biPlanes, 
    pBmpHdr->biBitCount, lpBits))
{
    // Handle the Error
}

(還沒有真正測試過這段代碼,但它應該可以工作)

我不得不提一下,圖像格式相當不尋常,即每像素 16 位可能是 BGR 5-5-5 格式(每個組件 5 位)。 每個像素兩個字節,圖像大小應該是 2048 字節(32 x 32 x 2)。 像這樣由 Microsoft 工具創建的 bitmap 文件將是 2102 字節,這是正確的(結構的 54 字節加上 bitmap 數據的 2048 字節 - 沒有調色板)。 也許您應該將數據存儲到文件中並使用十六進制編輯器檢查它們。

如果使用 GDI+ 是一個選項,您可以基本上使用此 answer從內存數據緩沖區構造HBITMAP ,最后將返回的HBITMAP附加到 MFC CBitmap 這是原始代碼:

#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();
}

這是一個關於如何將返回的HBITMAP附加到CBitmap的片段:

#include <afxwin.h>

// ...

CBitmap bitmap {};
bitmap.Attach(from_data(data));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM