BLOB类型二进制数据转换成Bitmap类型数据,并显示成缩略图,类似手机相册的封面

class DemoDuilib : public WindowImplBase, public CButtonUI
{
public:
    DemoDuilib();
    ~DemoDuilib(); 
    void test();
    static std::vector<uint8_t> thumbData;//存储BLOB类型二进制数据
private:
    void PaintStatusImage(HDC hDC) override;//保持纵横比并裁剪
    HBITMAP CreateHBITMAPFromMemory(const std::vector<uint8_t>& data);//BLOB类型二进制数据转换成Bitmap类型数据
void DemoDuilib::SetNormalBitmap(HBITMAP hBitmap); ) void test(){ DemoDuilib* pButton = new DemoDuilib(); CDuiString strName; strName.Format(_T("btn_square_%d"), i + 1); pButton->SetName(strName); pButton->SetFixedHeight(BUTTONSIZE);//const int BUTTONSIZE = 85; pButton->SetFixedWidth(BUTTONSIZE); HBITMAP hBitmap = CreateHBITMAPFromMemory(thumbData); if (hBitmap) { pButton->SetNormalImage(hBitmap); } pButton->SetPadding(CDuiRect(10,0,0,0)); pButtonLayout->Add(pButton); }

void DemoDuilib::SetNormalBitmap(HBITMAP hBitmap)
{
    m_hNormalBitmap = hBitmap;
    Invalidate();
}
/*
  • 功能:设置控件的普通状态位图,并使控件无效以触发重绘。
  • 参数:HBITMAP hBitmap 是一个位图句柄。
  • 操作:
    • 将传入的位图句柄 hBitmap 赋值给成员变量 m_hNormalBitmap
    • 调用 Invalidate() 函数,使控件无效,从而触发重绘。
*/
void DemoDuilib::PaintStatusImage(HDC hDC)
{
    if (m_hNormalBitmap)
    {
        HDC hMemDC = CreateCompatibleDC(hDC);
        HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, m_hNormalBitmap);
        BITMAP bitmap;
        GetObject(m_hNormalBitmap, sizeof(bitmap), &bitmap);
        
        float aspectRatio = static_cast<float>(bitmap.bmWidth) / bitmap.bmHeight;
        int targetWidth = m_rcItem.right - m_rcItem.left;
        int targetHeight = m_rcItem.bottom - m_rcItem.top;
        int newWidth, newHeight;
        if (aspectRatio > 1.0f) {
            newWidth = targetWidth;
            newHeight = static_cast<int>(targetWidth / aspectRatio);
        } else {
            newHeight = targetHeight;
            newWidth = static_cast<int>(targetHeight * aspectRatio);
        }
        int offsetX = (targetWidth - newWidth) / 2;
        int offsetY = (targetHeight - newHeight) / 2;
        StretchBlt(hDC, m_rcItem.left, m_rcItem.top, targetWidth, targetHeight,
                   hMemDC, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);
        SelectObject(hMemDC, hOldBitmap);
        DeleteDC(hMemDC);
    } else {
        CButtonUI::PaintStatusImage(hDC);
    }
}
/*
  • 功能:绘制控件的状态图像。
  • 参数:HDC hDC 是设备上下文句柄,用于绘制图像。
  • 操作:
    • 检查 m_hNormalBitmap 是否有效。
    • 如果有效:
      • 创建一个兼容的内存设备上下文 hMemDC
      • 将 m_hNormalBitmap 选择到 hMemDC 中,并保存旧的位图句柄 hOldBitmap
      • 获取位图信息(宽度和高度)。
      • 计算位图的宽高比 aspectRatio
      • 计算目标区域的宽度 targetWidth 和高度 targetHeight
      • 根据宽高比调整新的宽度 newWidth 和高度 newHeight,以保持图像的比例。
      • 计算图像在目标区域中的偏移量 offsetX 和 offsetY
      • 使用 StretchBlt 函数将位图从内存设备上下文 hMemDC 绘制到目标设备上下文 hDC
      • 恢复旧的位图句柄并删除内存设备上下文 hMemDC
    • 如果 m_hNormalBitmap 无效,调用基类 CButtonUI 的 PaintStatusImage 函数。
*/
HBITMAP DemoDuilib::CreateHBITMAPFromMemory(const std::vector<uint8_t>& data)
{
    HBITMAP hBitmap = NULL;
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    IStream* pStream = SHCreateMemStream(data.data(), data.size());
    if (pStream)
    {
        Gdiplus::Bitmap* pBitmap = Gdiplus::Bitmap::FromStream(pStream);
        if (pBitmap)
        {
            pBitmap->GetHBITMAP(Gdiplus::Color(0, 0, 0), &hBitmap);
            delete pBitmap;
        }
        pStream->Release();
    }
    Gdiplus::GdiplusShutdown(gdiplusToken);
    return hBitmap;
}
/*
  • 功能:从内存中的字节数据创建一个 HBITMAP
  • 参数:const std::vector<uint8_t>& data 是包含位图数据的字节向量。
  • 操作:
    • 初始化 GDI+ 库。
    • 使用 SHCreateMemStream 函数从字节数据创建一个内存流 pStream
    • 如果内存流 pStream 有效:
      • 使用 Gdiplus::Bitmap::FromStream 函数从内存流创建一个 Gdiplus::Bitmap 对象 pBitmap
      • 如果 pBitmap 有效:
        • 使用 pBitmap->GetHBITMAP 函数获取 HBITMAP
        • 删除 pBitmap 对象。
      • 释放内存流 pStream
    • 关闭 GDI+ 库。
    • 返回创建的 HBITMAP
*/

 

posted @ 2024-07-18 12:06  素装写淡定  阅读(53)  评论(0)    收藏  举报