-2

I'm struggling to find the way to increase pixel sizes in a win32 bitmap. Is there any way to do it?

I made a small win32 program below. When you run it, you should get a window with a very tiny red dot in the center. You can use up, down, left, and right arrow keys to control the dot.

/* compile: gcc test.c -o test -lgdi32 -Wl,-subsystem,windows */
// TODO fast way to update? resize pixel size? best coding practices?

#include <windows.h>

#define WND_WIDTH 500
#define WND_HEIGHT 500

#define ID_TIMER 1

void DrawBitmap(HDC hdc, RECT *rect, BITMAPINFO info, void *bmpMem)
{
    int width = rect->right - rect->left;
    int height = rect->bottom - rect->top;
    
    StretchDIBits(hdc,
                  0,
                  0,
                  info.bmiHeader.biWidth,
                  info.bmiHeader.biHeight,
                  0,
                  0,
                  width,
                  height,
                  bmpMem,
                  &info,
                  DIB_RGB_COLORS,
                  SRCCOPY);
}

void UpdateBitmap(BITMAPINFO info, void *bmpMem, POINT pix)
{
    int width = info.bmiHeader.biWidth;
    int height = info.bmiHeader.biHeight;
    
    BYTE *pixel = (BYTE *) bmpMem;
    
    for (int y = 0; y < height; y++)
    {
        for (int x = 0; x < width; x++)
        {
            if (x == pix.x && y == pix.y)
            {
                *pixel++ = 0;   /* blue */
                *pixel++ = 0;   /* green */
                *pixel++ = 255; /* red */
                *pixel++ = 255; /* alpha */
            }
            else
            {
                *pixel++ = 0;   /* blue */
                *pixel++ = 0;   /* green */
                *pixel++ = 0;   /* red */
                *pixel++ = 255; /* alpha */
            }
        }
    }
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static BITMAPINFO info;
    static void *bmpMem;
    static POINT pixel;
    
    switch (msg)
    {
    case WM_CREATE:
    {
        RECT rcClient;
        
        GetClientRect(hWnd, &rcClient);
        
        int width = rcClient.right - rcClient.left;
        int height = rcClient.bottom - rcClient.top;
        
        info.bmiHeader.biSize = sizeof(info.bmiHeader);
        info.bmiHeader.biWidth = width;
        info.bmiHeader.biHeight = height;
        info.bmiHeader.biPlanes = 1;
        info.bmiHeader.biBitCount = 32;
        info.bmiHeader.biCompression = BI_RGB;
        info.bmiHeader.biSizeImage = 0;
        info.bmiHeader.biXPelsPerMeter = 0;
        info.bmiHeader.biYPelsPerMeter = 0;
        info.bmiHeader.biClrUsed = 0;
        info.bmiHeader.biClrImportant = 0;
        
        bmpMem = VirtualAlloc(0, width * height * 4, MEM_COMMIT, PAGE_READWRITE);
        
        pixel.x = width / 2;
        pixel.y = height / 2;
        
        if(!SetTimer(hWnd, ID_TIMER, 50, NULL))
        {
            MessageBox(hWnd, "Could not SetTimer()!", "Error", MB_OK | MB_ICONEXCLAMATION);
            PostQuitMessage(1);
        }
        
        break;
    }/*
    case WM_PAINT:
    {
        RECT rcClient;
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);
        
        GetClientRect(hWnd, &rcClient);
        DrawBitmap(hdc, &rcClient, info, bmpMem);
        
        EndPaint(hWnd, &ps);
        break;
    }*/
    case WM_TIMER:
    {
        RECT rcClient;
        HDC hdc = GetDC(hWnd);
        
        GetClientRect(hWnd, &rcClient);
        UpdateBitmap(info, bmpMem, pixel);
        DrawBitmap(hdc, &rcClient, info, bmpMem);
        
        ReleaseDC(hWnd, hdc);
        break;
    }
    case WM_KEYDOWN:
    {
        switch (wParam)
        {
        case VK_LEFT: pixel.x -= 1; break;
        case VK_RIGHT: pixel.x += 1; break;
        case VK_UP: pixel.y += 1; break;
        case VK_DOWN: pixel.y -= 1; break;
        }
        break;
    }
    case WM_CLOSE:
        DestroyWindow(hWnd);
        break;
    case WM_DESTROY:
        KillTimer(hWnd, ID_TIMER);
        VirtualFree(bmpMem, 0, MEM_RELEASE);
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, msg, wParam, lParam);
    }
    
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    const TCHAR szClassName[] = TEXT("MyClass");
    
    WNDCLASS wc;
    HWND hWnd;
    MSG msg;
    
    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = szClassName;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    
    if (!RegisterClass(&wc))
    {
        MessageBox(NULL, TEXT("Window Registration Failed!"), TEXT("Error!"),
            MB_ICONEXCLAMATION | MB_OK);
        return 1;
    }
    
    hWnd = CreateWindow(szClassName,
                        TEXT("Title"),
                        WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, /* this window style prevents window resizing */
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        WND_WIDTH,
                        WND_HEIGHT,
                        NULL,
                        NULL,
                        hInstance,
                        NULL);
    
    if (hWnd == NULL)
    {
        MessageBox(NULL, TEXT("Window Creation Failed!"), TEXT("Error!"),
            MB_ICONEXCLAMATION | MB_OK);
        return 1;
    }
    
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
    
    while (GetMessage(&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    
    return (int) msg.wParam;
}

I want to increase the size of the tiny red dot and all other pixels in the bitmap. I tried to decrease the width and height like this

    switch (msg)
    {
    case WM_CREATE:
    {
        //RECT rcClient;

        //GetClientRect(hWnd, &rcClient);

        int width = 30;
        int height = 30;

I expected to see a big red dot at the center but I got the white screen instead. How can I edit the code to display bigger pixels?

Ray Siplao
  • 199
  • 8
  • 1
    I like to [search the internet](https://www.google.com/search?q=magnify+bitmap+winapi&rlz=1C1GCEB_enUS935US935&oq=magnify+bitmap+winapi&aqs=chrome..69i57.8314j0j15&sourceid=chrome&ie=UTF-8) before posting because its usually faster than waiting for a reply. – Thomas Matthews Jun 21 '21 at 20:32

1 Answers1

1

You are creating a single red pixel in your UpdateBitmap:

if (x == pix.x && y == pix.y)
{
    *pixel++ = 0;   /* blue */
    *pixel++ = 0;   /* green */
    *pixel++ = 255; /* red */
    *pixel++ = 255; /* alpha */
}

If you want a bigger "dot" - define a radius somewhere:

int r = 17;

and change your condition to

if ((x - pix.x)* (x - pix.x) + (y - pix.y)* (y - pix.y) <= r*r)

To scale the entire bitmap, modify DrawBitmap:

void DrawBitmap(HDC hdc, RECT* rect, BITMAPINFO info, void* bmpMem)
{
    int width = rect->right - rect->left;
    int height = rect->bottom - rect->top;
    int scale = 7;
    StretchDIBits(hdc,
        -(info.bmiHeader.biWidth * scale - width) / 2,
        -(info.bmiHeader.biHeight * scale - height) / 2,
        info.bmiHeader.biWidth * scale,
        info.bmiHeader.biHeight * scale,
        0,
        0,
        width,
        height,
        bmpMem,
        &info,
        DIB_RGB_COLORS,
        SRCCOPY);
}

StretchDIBits will stretch (or shrink) the area of the source (specified by 0, 0, width, height) into some are of the destination. In this example, I magnified the size of the destination by the factor of scale - so the image will stretch. The negative offset is to "center" the image over destination; you can use 0,0 to keep the top-left anchor.

Vlad Feinstein
  • 10,960
  • 1
  • 12
  • 27