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
相关产品推荐
相关产品推荐

