使用winapi加载渲染位图问题

问题描述 投票:1回答:1

我试图加载一个位图文件,并在Windows上的C++程序中显示图像。它看起来几乎没有问题,但由于某些原因,它似乎有点水平挤压,并且在图像的右端开始重复。

另外,如果是黑白色,颜色看起来很好,但如果是红色,它就会出现各种不同颜色的条纹,所以看起来我没有正确处理RGBA值,因为它们是正确的,但我不确定它们是如何布局的。

以下是我程序中图像的一些截图(它们是扑克牌图像)。

黑白:

8 of spades

红色:

2 of hearts

这是红心2的源码文件。

enter image description here

这是我的代码,如果要我猜的话,我想问题出在了这里 debug_render_bitmap 功能或 debug_load_bitmap 函数。(注意:我使用CPU将窗口位图渲染到屏幕上,存储在一个全局缓冲区中)。

#include <windows.h>
#include <stdint.h>

struct win32_offscreen_buffer {
    BITMAPINFO info;
    void *memory;
    int width;
    int height;
    int bytes_per_pixel;
    int pitch;
};

struct read_file_result {
    unsigned int contents_size;
    void *contents;
};

struct bitmap_result {
    BITMAPFILEHEADER *file_header;
    BITMAPINFOHEADER *info_header;
    unsigned int *pixels;
    unsigned int stride;
};

win32_offscreen_buffer global_buffer;
bool should_quit = false;

uint32_t safe_truncate_uint64(uint64_t value) {
    uint32_t result = (uint32_t)value;
    return result;
}

void free_file_memory(void *memory) {
    if (memory) {
        VirtualFree(memory, 0, MEM_RELEASE);
    }
}

read_file_result read_entire_file(LPCSTR filename) {
    read_file_result result = {};
    
    HANDLE file_handle = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
    
    if (file_handle != INVALID_HANDLE_VALUE) {
        LARGE_INTEGER file_size;
        if(GetFileSizeEx(file_handle, &file_size)) {
            uint32_t file_size32 = safe_truncate_uint64(file_size.QuadPart);
            result.contents = VirtualAlloc(0, file_size32, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
            
            if (result.contents) {
                DWORD bytes_read;
                if (ReadFile(file_handle, result.contents, file_size32, &bytes_read, 0) && (file_size32 == bytes_read)) {
                    // File read successfully.
                    result.contents_size = file_size32;
                } else {
                    // TODO: Logging
                    free_file_memory(result.contents);
                    result.contents = 0;
                }
            } else {
                // TODO: Logging
            }
        } else {
            // TODO: Logging
        }
        
        CloseHandle(file_handle);
    } else {
        // TODO: Logging
    }
    
    return result;
}

bitmap_result debug_load_bitmap(char* filename) {
    bitmap_result bmp_result = {};

    read_file_result file_result = read_entire_file(filename);
    unsigned char *contents = (unsigned char *)file_result.contents;

    bmp_result.file_header = (BITMAPFILEHEADER *)contents;
    bmp_result.info_header = (BITMAPINFOHEADER *)(contents + 14);
    bmp_result.pixels = (unsigned int *)(contents + bmp_result.file_header->bfOffBits);
    bmp_result.stride = ((((bmp_result.info_header->biWidth * bmp_result.info_header->biBitCount) + 31) & ~31) >> 3);

    return bmp_result;
}

void debug_render_bitmap(bitmap_result bmp) {
    int width = bmp.info_header->biWidth;
    int height = bmp.info_header->biHeight;

    unsigned char *dest_row = (unsigned char *)global_buffer.memory;
    unsigned char *source_row = (unsigned char *)(bmp.pixels + ((bmp.stride / 4) * (height - 1)));

    for (int y = 0; y < height; y++) {
        unsigned int *dest = (unsigned int *)dest_row;
        unsigned int *source = (unsigned int *)source_row;

        for (int x = 0; x < width; x++) {
            *dest = *source;
            dest++;
            source++;
        }

        dest_row += global_buffer.pitch;
        source_row -= bmp.stride;
    }
}

如果有帮助的话,这里是位图信息头值的截图。

enter image description here

如果有人能告诉我这里发生了什么,那将是非常感激的。

c++ winapi bitmap
1个回答
0
投票

对于绘制位图,有更简单的方法。你不需要自己去解析.bmp文件。给两个例子如下,你可以试试。

第一个方法使用 LoadImage 功能. 参考 "如何在窗口上绘制图像?"

case WM_CREATE:
{
    hBitmap = (HBITMAP)LoadImage(hInst, L"C:\\projects\\native_poker\\card-BMPs\\c08.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
}
break;
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;

第二种方法使用GDI+。 参考 "加载和显示位图".

#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment (lib,"Gdiplus.lib")

//...

VOID OnPaint(HDC hdc)
{
    Graphics graphics(hdc);
    Image *image = Image::FromFile(L"C:\\projects\\native_poker\\card-BMPs\\c08.bmp");
    graphics.DrawImage(image, 10, 10);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);
        OnPaint(hdc);
        EndPaint(hWnd, &ps);
    }
    break;

//...

}
© www.soinside.com 2019 - 2024. All rights reserved.