You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Win32环境下极简加载绘制BMP位图的方法咨询

WIN32极简加载绘制位图方案(无GDI+)

一、最直接的极简方案:LoadBitmapA + BitBlt

如果只是单纯实现加载并绘制位图,这是最轻量化的方式,无需处理DIB,直接用基础GDI函数完成:

核心步骤

  • 加载位图:通过LoadBitmapA从程序资源中加载位图,返回HBITMAP句柄(需确保位图已添加到.rc资源文件)。
  • 内存DC中转:创建与窗口DC兼容的内存DC,用来暂存位图数据(GDI无法直接将HBITMAP绘制到窗口DC)。
  • 复制绘制:用BitBlt将内存DC中的位图直接复制到窗口DC,完成绘制。
  • 资源清理:恢复内存DC的原始对象,删除临时DC和HBITMAP,避免内存泄漏。

窗口过程示例(处理WM_PAINT消息)

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            
            // 1. 加载资源位图(替换IDB_MYBITMAP为你的资源ID)
            HBITMAP hBitmap = LoadBitmapA(GetModuleHandle(NULL), MAKEINTRESOURCEA(IDB_MYBITMAP));
            if (!hBitmap) { EndPaint(hWnd, &ps); return 0; }
            
            // 2. 创建兼容内存DC
            HDC hdcMem = CreateCompatibleDC(hdc);
            if (!hdcMem) { DeleteObject(hBitmap); EndPaint(hWnd, &ps); return 0; }
            
            // 3. 将位图选入内存DC,保存原DC对象以便恢复
            HBITMAP hOldBmp = (HBITMAP)SelectObject(hdcMem, hBitmap);
            
            // 4. 获取位图尺寸
            BITMAP bmpInfo;
            GetObjectA(hBitmap, sizeof(BITMAP), &bmpInfo);
            
            // 5. 绘制到窗口左上角(可调整坐标和尺寸参数)
            BitBlt(hdc, 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, hdcMem, 0, 0, SRCCOPY);
            
            // 6. 清理资源
            SelectObject(hdcMem, hOldBmp);
            DeleteDC(hdcMem);
            DeleteObject(hBitmap);
            
            EndPaint(hWnd, &ps);
            break;
        }
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProcA(hWnd, msg, wParam, lParam);
    }
    return 0;
}

二、关于DIB与SetDIBitsToDevice的说明

DIB(设备无关位图)方案仅适合需要直接操作像素数据的场景(比如修改位图内容、跨设备传输),单纯绘制无需使用。若确实需要从HBITMAP转换为BITMAPINFO,步骤如下:

转换与绘制步骤

  1. 获取基础位图信息:用GetObjectA从HBITMAP读取BITMAP结构,包含宽、高、位深等数据。
  2. 构建BITMAPINFO:根据位深分配内存(位深≤8时需额外颜色表),填充BITMAPINFOHEADER字段。
  3. 提取像素数据:用GetDIBits将HBITMAP的像素数据读取到缓冲区。
  4. 绘制DIB:调用SetDIBitsToDevice直接将像素数据绘制到窗口DC。

代码片段示例

// 从HBITMAP生成BITMAPINFO并绘制
BITMAP bmp;
GetObjectA(hBitmap, sizeof(BITMAP), &bmp);

// 计算BITMAPINFO所需内存(含颜色表)
int colorTableSize = (bmp.bmBitsPixel <= 8) ? (1 << bmp.bmBitsPixel) * sizeof(RGBQUAD) : 0;
BITMAPINFO* pBI = (BITMAPINFO*)LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER) + colorTableSize);

// 填充BITMAPINFOHEADER
pBI->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pBI->bmiHeader.biWidth = bmp.bmWidth;
pBI->bmiHeader.biHeight = bmp.bmHeight;
pBI->bmiHeader.biPlanes = 1;
pBI->bmiHeader.biBitCount = bmp.bmBitsPixel;
pBI->bmiHeader.biCompression = BI_RGB;
pBI->bmiHeader.biSizeImage = 0;
pBI->bmiHeader.biXPelsPerMeter = 0;
pBI->bmiHeader.biYPelsPerMeter = 0;
pBI->bmiHeader.biClrUsed = 0;
pBI->bmiHeader.biClrImportant = 0;

// 分配像素缓冲区并读取数据
BYTE* pPixelData = (BYTE*)LocalAlloc(LPTR, bmp.bmWidthBytes * bmp.bmHeight);
GetDIBits(hdc, hBitmap, 0, bmp.bmHeight, pPixelData, pBI, DIB_RGB_COLORS);

// 绘制DIB到窗口
SetDIBitsToDevice(hdc, 0, 0, bmp.bmWidth, bmp.bmHeight, 0, 0, 0, bmp.bmHeight, pPixelData, pBI, DIB_RGB_COLORS);

// 清理资源
LocalFree(pPixelData);
LocalFree(pBI);

总结

  • 仅需加载绘制时,优先用LoadBitmapA+BitBlt,代码简洁、性能高,完全满足极简需求。
  • DIB方案属于进阶场景,无需在单纯绘制时使用,避免不必要的复杂度。

内容的提问来源于stack exchange,提问作者Joymaker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 13:10:10