You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SDL模拟器中C++显示RGB888转RGB565位图异常排查

问题诊断与修复方案

先从你提供的BMP文件头数据解析出关键参数,确认图像基础信息:

  • 图像宽度:0x7B → 123像素
  • 图像高度:0x5A → 90像素
  • 位深:0x18 → 24位(RGB888),和你描述的一致

接下来直接说代码里导致乱码和扫描线的核心问题,以及修复方案:

1. 行间距(Pitch)计算完全错误

你当前代码里的行间距计算逻辑完全颠倒了:

uint16_t bytesPerRow = (bytesPerPixel * h ); // 这里的错误是核心!

行间距是单像素行的总字节数(含对齐填充),和图像高度h没有任何关系!正确的计算逻辑分两种场景:

  • 如果处理的是原始RGB888格式的BMP数据:每行原始字节数是 w * 3,再向上对齐到4的倍数,公式为 ((w * 3) + 3) & ~3
  • 如果是已经转成RGB565的像素数据(2字节/像素):每行对齐后的字节数为 ((w * 2) + 3) & ~3

你用高度来计算行间距,直接导致像素寻址完全错乱,这就是扫描线乱码的根源。

2. 像素遍历的寻址逻辑错误

你当前的像素寻址是列优先,但不管是BMP原始数据还是转后的RGB565数据,都是行优先存储的!正确的行优先寻址公式应该是 行索引 * 行间距 + 列索引 * 单像素字节数,而不是反过来。

另外要注意:BMP文件的像素数据默认是从下到上存储的(当高度字段为正值时),如果你的帧缓冲是从上到下绘制的,需要反转行索引来修正图像上下颠倒的问题。

修复后的代码示例

场景1:bitmap是已经转好的RGB565格式数据

void Rasterizer::DrawBitmap(int w, int h, int x, int y, int transparent) {
    if (!bitmap) return;
    const uint8_t bytesPerPixel = 2;
    // 计算正确的行间距:对齐到4字节边界
    uint16_t bytesPerRow = ((w * bytesPerPixel) + 3) & ~3; 
    uint16_t pixel;
    int row, column;
    
    for (row = 0; row < h; row++) {
        // 修正BMP倒序存储的问题,取倒数第row行
        int bmpRowIndex = h - 1 - row;
        for (column = 0; column < w; column++) {
            // 行优先寻址:行偏移 + 列偏移
            int dataOffset = bmpRowIndex * bytesPerRow + column * bytesPerPixel;
            pixel = (bitmap[dataOffset] << 8) | (bitmap[dataOffset + 1] & 0xFF);
            SetPixel(x + column, y + row, pixel);
        }
    }
}

void Rasterizer::SetPixel(int x, int y, uint16_t color) {
    // 增加边界检查,避免帧缓冲越界
    if (x < 0 || x >= m_Width || y < 0 || y >= m_Height) return;
    m_FrameBuffer[y * m_Width + x] = color;
}

场景2:bitmap是原始RGB888格式的BMP像素数据

void Rasterizer::DrawBitmap(int w, int h, int x, int y, int transparent) {
    if (!bitmap) return;
    const uint8_t bytesPerPixelRGB888 = 3;
    // 计算RGB888格式的行间距,对齐到4字节边界
    uint16_t bytesPerRow = ((w * bytesPerPixelRGB888) + 3) & ~3; 
    uint16_t pixelRGB565;
    int row, column;
    
    for (row = 0; row < h; row++) {
        int bmpRowIndex = h - 1 - row;
        for (column = 0; column < w; column++) {
            int dataOffset = bmpRowIndex * bytesPerRow + column * bytesPerPixelRGB888;
            // BMP存储是BGR顺序,注意分量提取顺序!
            uint8_t r = bitmap[dataOffset + 2];
            uint8_t g = bitmap[dataOffset + 1];
            uint8_t b = bitmap[dataOffset];
            // 转换RGB888到RGB565:R取高5位,G取高6位,B取高5位
            pixelRGB565 = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
            SetPixel(x + column, y + row, pixelRGB565);
        }
    }
}

额外注意事项

  • BMP文件的像素是BGR顺序存储的,不是RGB!如果直接按RGB提取会导致颜色错乱,这是很容易踩的坑。
  • 确保bitmap指针指向的是BMP文件头之后的像素数据区域(也就是文件头偏移0x36之后的部分),不要把文件头数据当成像素数据处理。

内容的提问来源于stack exchange,提问作者andre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:07:50