c++ - 使用 C++ 在微 Controller 上显示位图图形

标签 c++ bitmap sdl

我使用的是 888 到 565 格式的十六进制位图。 所以我试图在使用 SDL 的模拟器上显示位图,帧缓冲区分辨率为 16 位。

其中一个位图数据(第一行)看起来像这样

0x42, 0x4D, 0xFE, 0x82, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x36, 0x0, 0x0, 0x0, 0x28, 0x0, 0x0, 0x0, 0x7B, 0x0, 0x0, 0x0, 0x5A, 0x0, 0x0, 0x0, 0x1, 0x0, 0x18, 0x0, 0x0, 0x0, 

现在我尝试在 SDL 上使用 C++ 绘制该位图,但我得到带有扫描线的垃圾图像,看起来间距计算不正确。

void Rasterizer::DrawBitmap(int w, int h, int x, int y, int transparent)
{
    if (!bitmap)
        return;

    const uint8_t bytesPerPixel = 2;
    uint16_t bytesPerRow = (bytesPerPixel * h ); // bytes Per Row including padding to 4 byte row boundary
    uint16_t paddingSize = bytesPerRow - (bytesPerPixel * w); // paddingSize for each row
    uint16_t pixel;
    uint16_t row, column;


    for (row = 0; row < h; row++) {
        for (column = 0; column < w; column++) {
            pixel = bitmap[row + column* bytesPerRow]<<8;
            pixel |= bitmap[1+row + column* bytesPerRow] & 0xFF;
            SetPixel(x+column, y+row, pixel);
        }
    }

}



void Rasterizer::SetPixel(int x, int y, uint16_t color)
{
    m_FrameBuffer[y * m_Width + x] = color;
}

enter image description here

最佳答案

0x42, 0x4D

前2个字节是BM,就是位图文件头,共54字节。它不是第一行的一部分。

大小为0x7B x 0x5A 像素

最后你有 0x18 0x00 是 24,对于 24 位位图,而不是 16 位位图

所以你必须跳过 54 字节,并读取为 24 位

int width_in_bytes = ((width * 24 + 31) / 32) * 4 * height;
for(int row = height - 1; row >= 0; row--)
{
    for(int col = 0; col < width; col++)
    {
        int i = row * width_in_bytes + col * 3;
        unsigned char blu = bitmap[54 + i + 0];
        unsigned char grn = bitmap[54 + i + 1];
        unsigned char red = bitmap[54 + i + 2];
        int pixel = red | ((uint16_t)grn << 8) | ((uint32_t)blu << 16);
        SetPixel(row, col, pixel);
    }
}

如果设备需要 16 位位图,则首先尝试获取 16 位位图。例如,在截屏时,Windows 允许使用 16 位格式。

SDL 也支持 SDL_PIXELFORMAT_RGB565。如果您在 Windows 中编写代码,GDI+ 是另一种选择。

如果你的源位图是24位的,你想转换成16位的565格式,根据下面的MCVE写出公式

24 位位图的颜色范围为 0-255,而 16 位位图的颜色范围为 0-31(在 565 格式的情况下,绿色为 0-63)。您必须标准化颜色,例如将红色值乘以 31/255。然后将值移位以放入 16 位整数。

16 位位图格式在像素开始之前需要 3 种颜色(总共 12 个字节)。这些颜色包含有关 565 格式的信息。

#include <Windows.h>
#include <stdint.h>
#include <iostream>
#include <fstream>
#include <vector>

int main()
{
    HBITMAP hbitmap = (HBITMAP)LoadImage(NULL, "24bit.bmp",
        IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
    if(!hbitmap)
        return 0;

    BITMAP bm;
    GetObject(hbitmap, sizeof(bm), &bm);
    if(bm.bmBitsPixel != 24)
    {
        DeleteObject(hbitmap);
        std::cout << "Expecting 24-bit bitmap\n";
        return 0;
    }

    BYTE *source = (BYTE*)bm.bmBits;
    int w = bm.bmWidth;
    int h = bm.bmHeight;

    //calculate width in bytes (wb) for source and destination
    DWORD wb_src = ((w * 24 + 31) / 32) * 4;
    DWORD wb_dst = ((w * 16 + 31) / 32) * 4;

    int size = wb_dst * h;
    std::vector<BYTE> dest(size);
    for(int r = 0; r < h; r++)
    {
        for(int c = 0; c < w; c++)
        {
            int src = r * wb_src + c * 3;
            int dst = r * wb_dst + c * 2;

            uint16_t blu = (uint16_t)(source[src + 0] * 31.f / 255.f);
            uint16_t grn = (uint16_t)(source[src + 1] * 63.f / 255.f);
            uint16_t red = (uint16_t)(source[src + 2] * 31.f / 255.f);

            uint16_t res = (red) | (grn << 5) | (blu << 11);
            memcpy(&dest[dst], &res, 2);
        }
    }

    //prepare header files for 16-bit file
    BITMAPINFOHEADER bi = { sizeof(bi), w, h, 1, 16, BI_BITFIELDS };
    BITMAPFILEHEADER bf = { (WORD)'MB', 54 + 12 + wb_dst * h, 0, 0, 54 };

    std::ofstream of("16bit.bmp", std::ios::binary);
    if(of)
    {
        //add file header
        of.write((char*)&bf, sizeof(bf));
        of.write((char*)&bi, sizeof(bi));

        //color table
        COLORREF c1 = 31;
        COLORREF c2 = 63 << 5;
        COLORREF c3 = 31 << 11;
        of.write((char*)&c1, 4);
        of.write((char*)&c2, 4);
        of.write((char*)&c3, 4);

        //add pixels
        of.write((char*)&dest[0], dest.size());
    }

    DeleteObject(hbitmap);

    return 0;
}

关于c++ - 使用 C++ 在微 Controller 上显示位图图形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50594912/

相关文章:

ubuntu - 使用 SDL 时腻子中的 "Init kbd"

c++ - 声明 SDL_Rect 数据成员在启动时崩溃,找不到原因

c++ - 如何在 Qt 中为 qmake 指定一个库文件依赖?

c++ - SDL 卡住但继续运行

android - 从sql表中查看图像

go - OpenGL 和 SDL2 无法打开窗口

c++ - 拆分 STL 列表?

c++ - 在另一个文件中初始化的外部数组中的 undefined reference

android - 如何在没有标签的情况下获取当前 View 寻呼机 View ?

c++ - diceroll 的位图