C ++在给定像素数据数组的形式上绘制矩形

时间:2019-07-15 16:50:30

标签: c++ winapi

我正在读取RGB数据的多维数组形式的图像数据,并希望将其绘制在WM_PAINT中某个位置的表单上

我知道如何从文件中读取整个位图并将其绘制在某个位置:

    case WM_PAINT:
        PAINTSTRUCT     ps;
        HDC             hdc;
        BITMAP          bitmap;
        HDC             hdcMem;
        HGDIOBJ         oldBitmap;

        hdc = BeginPaint(hwnd, &ps);

        hdcMem = CreateCompatibleDC(hdc);
        oldBitmap = SelectObject(hdcMem, hBitmap);

        GetObject(hBitmap, sizeof(bitmap), &bitmap);
        BitBlt(hdc, 0, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY);

        SelectObject(hdcMem, oldBitmap);
        DeleteDC(hdcMem);

        EndPaint(hwnd, &ps);
        break;

但不是如何处理特定像素数据作为表单上的位图的问题。我一直在寻找真实的日子。

任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:4)

基本上,使用CreateDibSection(...)

下面的最小用法示例:

#include <windows.h>

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{

    MSG msg = { 0 };
    WNDCLASS wc = { 0 };
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
    wc.lpszClassName = L"createdibsection_example";
    if (!RegisterClass(&wc))
        return 1;

    if (!CreateWindow(wc.lpszClassName,
        L"createdibsection example",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        0, 0, 640, 480, 0, 0, hInstance, NULL))
        return 2;

    while (GetMessage(&msg, NULL, 0, 0) > 0)
        DispatchMessage(&msg);

    return 0;
}

HBITMAP CreateBitmapAndFillPtrToItsData(unsigned char** ptr_data, int wd, int hgt)
{
    HDC hdcScreen = GetDC(NULL);

    BITMAPINFO bmi;
    memset(&bmi, 0, sizeof(BITMAPINFO));
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = wd;
    bmi.bmiHeader.biHeight = -hgt; // top-down
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32;
    bmi.bmiHeader.biCompression = BI_RGB;

    auto bmp = CreateDIBSection(hdcScreen, &bmi, DIB_RGB_COLORS, (void**) ptr_data, NULL, NULL);

    ReleaseDC(NULL, hdcScreen);
    return bmp;
}

void CopyInPixelData(unsigned char* ptr_data, int wd, int hgt)
{
    // this is just an example for tutorial purposes ... generate a red circle
    // in a white field ... real code would load from a file, etc.

    int c_x = wd / 2;
    int c_y = hgt / 2;
    int radius = c_x;
    int i = 0;
    for (int y = 0; y < hgt; y++) {
        for (int x = 0; x < wd; x++) {
            if ((x-c_x)*(x-c_x) + (y-c_y)*(y-c_y) <= radius*radius) {
                ptr_data[i++] = 0;
                ptr_data[i++] = 0;
                ptr_data[i++] = 255;
                ptr_data[i++] = 0;
            } else {
                ptr_data[i++] = 255;
                ptr_data[i++] = 255;
                ptr_data[i++] = 255;
                ptr_data[i++] = 0;
            }
        }
    }
}

HBITMAP CreateBitmapFromPixelDataExample(int wd, int hgt)
{
    // create a bitmap such that we get a pointer to where its data is stored
    unsigned char* ptr_data;
    auto bitmap = CreateBitmapAndFillPtrToItsData( &ptr_data, wd, hgt );

    // fill in some pixel data...
    CopyInPixelData( ptr_data, wd, hgt );

    return bitmap;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static HBITMAP bitmap;

    switch (message)
    {
    case WM_CREATE: {
        bitmap = CreateBitmapFromPixelDataExample(85, 85);
    } break;

    case WM_CLOSE:
        PostQuitMessage(0);
        break;

    case WM_PAINT: {
        RECT r;
        GetClientRect(hWnd, &r);

        auto hdc_bitmap = CreateCompatibleDC(NULL);
        auto hbm_old = (HBITMAP)SelectObject(hdc_bitmap, bitmap);

        PAINTSTRUCT ps;
        auto hdc = BeginPaint(hWnd, &ps);
        // clear bkgd
        FillRect(hdc, &r, (HBRUSH)GetStockObject(WHITE_BRUSH));
        // paint in the bitmap we generated from pixel data...
        BitBlt(hdc, 10, 10, 85, 85, hdc_bitmap, 0, 0, SRCCOPY);
        EndPaint(hWnd, &ps);

        SelectObject(hdc_bitmap, hbm_old);
        DeleteDC(hdc_bitmap);

    } break;

    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}