简体   繁体   English

使用C ++在微控制器上显示位图图形

[英]Display bitmap graphics on a microcontroller using C++

I'm using a bitmap 888 to 565 format in hex format. 我正在使用十六进制格式的888到565格式的位图。 So I'm trying to display the bitmap on a simulator that uses SDL, with frame buffer resoultion is 16bit. 因此,我试图在使用SDL的模拟器上显示位图,帧缓冲区的重定为16位。

one of the bitmap data ( first row ) looks like that 一个位图数据(第一行)看起来像这样

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, 

Now I'm trying to draw that bitmap using C++ on SDL, but I get garbage image with scan lines, looks like the pitch is not calculated correctly. 现在,我试图在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;
}

在此处输入图片说明

0x42, 0x4D

The first 2 bytes are B and M , that's just the bitmap file header which is 54 bytes in total. 前2个字节是BM ,仅是位图文件头,总共54个字节。 It's not part of the first row. 它不是第一行的一部分。

The size is 0x7B x 0x5A pixels 大小为0x7B x 0x5A像素

Towards the end you have 0x18 0x00 which is 24, for 24-bit bitmap, not 16-bit 到最后,您有0x18 0x00 ,它是24,用于24位位图,而不是16位

So you have to skip 54 byte, and read as 24-bit 因此,您必须跳过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);
    }
}

If the device is expecting 16-bit bitmap, then try to obtain 16-bit bitmap in the first place. 如果设备期望使用16位位图,则首先尝试获取16位位图。 For example when taking screen shot, Windows allows 16-bit format. 例如,在进行屏幕截图时,Windows允许使用16位格式。

SDL supports SDL_PIXELFORMAT_RGB565 as well. SDL也支持SDL_PIXELFORMAT_RGB565 GDI+ is another option if you are coding in Windows. 如果您在Windows中进行编码,则GDI +是另一种选择。

If your source bitmap is 24-bit, and you want to convert to 16-bit 565 format, write the formula based on the MCVE below 如果您的源位图是24位,并且您想要转换为16位565格式,请根据以下MCVE编写公式

24-bit bitmap has color range from 0-255, whereas 16-bit has color range from 0-31 (0-63 for green in the case of 565 format). 24位位图的颜色范围为0-255,而16位位图的颜色范围为0-31(对于565格式,绿色为0-63)。 You have to normalize the color, for example by multiplying the red value by 31/255. 您必须对颜色进行规范化,例如将红色值乘以31/255。 And then shift the values to put in 16-bit integer. 然后将值移位以放入16位整数。

16-bit bitmap format expects 3 colors (a total of 12 bytes) before the pixels start. 16位位图格式在像素开始之前需要3种颜色(总共12个字节)。 These colors contain information about 565 format. 这些颜色包含有关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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM