Winapi 无法获取BitMapInfo标头数据以正确显示奇数宽度bmp图像
我正在尝试使用标准Win32 API调用显示奇数宽度的24位未压缩位图,但似乎我遇到了步幅问题 根据msdn: 对于未压缩的RGB格式,最小跨距始终是以字节为单位的图像宽度,四舍五入到最接近的DWORD。可以使用以下公式计算步幅: 步幅=双宽*双比特计数+31&~31>>3 但这对我来说根本不起作用,下面是代码:Winapi 无法获取BitMapInfo标头数据以正确显示奇数宽度bmp图像,winapi,bitmap,Winapi,Bitmap,我正在尝试使用标准Win32 API调用显示奇数宽度的24位未压缩位图,但似乎我遇到了步幅问题 根据msdn: 对于未压缩的RGB格式,最小跨距始终是以字节为单位的图像宽度,四舍五入到最接近的DWORD。可以使用以下公式计算步幅: 步幅=双宽*双比特计数+31&~31>>3 但这对我来说根本不起作用,下面是代码: void Init() { pImage = ReadBMP("data\\bird.bmp"); size_t imgSize = pImage->width
void Init()
{
pImage = ReadBMP("data\\bird.bmp");
size_t imgSize = pImage->width * pImage->height * 3;
BITMAPINFOHEADER bmih;
bmih.biSize = sizeof(BITMAPINFOHEADER);
bmih.biBitCount = 24;
// This is probably where the bug is
LONG stride = ((((pImage->width * bmih.biBitCount) + 31) & ~31) >> 3);
//bmih.biWidth = pImage->width;
bmih.biWidth = stride;
bmih.biHeight = -((LONG)pImage->height);
bmih.biPlanes = 1;
bmih.biCompression = BI_RGB;
bmih.biSizeImage = 0;
bmih.biXPelsPerMeter = 1;
bmih.biYPelsPerMeter = 1;
bmih.biClrUsed = 0;
bmih.biClrImportant = 0;
BITMAPINFO dbmi;
ZeroMemory(&dbmi, sizeof(dbmi));
dbmi.bmiHeader = bmih;
dbmi.bmiColors->rgbBlue = 0;
dbmi.bmiColors->rgbGreen = 0;
dbmi.bmiColors->rgbRed = 0;
dbmi.bmiColors->rgbReserved = 0;
HDC hdc = ::GetDC(NULL);
mTestBMP = CreateDIBitmap(hdc,
&bmih,
CBM_INIT,
pImage->pSrc,
&dbmi,
DIB_RGB_COLORS);
hdc = ::GetDC(NULL);
}
这里是绘图功能
RawBMP *pImage;
HBITMAP mTestBMP;
void UpdateScreen(HDC srcHDC)
{
if (pImage != nullptr && mTestBMP != 0x00)
{
HDC hdc = CreateCompatibleDC(srcHDC);
SelectObject(hdc, mTestBMP);
BitBlt(srcHDC,
0, // x
0, // y
// I tried passing the stride here and it did not work either
pImage->width, // width of the image
pImage->height, // height
hdc,
0, // x and
0, // y of upper left corner
SRCCOPY);
DeleteDC(hdc);
}
}
如果我传递原始图像宽度奇数,而不是跨步
LONG stride = ((((pImage->width * bmih.biBitCount) + 31) & ~31) >> 3);
//bmih.biWidth = stride;
bmih.biWidth = pImage->width;
图片看起来有点歪斜,下面显示了不同之处:
如果我根据msdn通过步幅,那么什么也不会显示,因为步幅太大了
有什么线索吗?谢谢大家! 谢谢乔纳森的解决方案。对于奇数宽度的图像,我需要使用适当的填充来逐行复制。大约24位未压缩图像的代码:
const uint32_t bitCount = 24;
LONG strideInBytes;
// if the width is odd, then we need to add padding
if (width & 0x1)
{
strideInBytes = ((((width * bitCount) + 31) & ~31) >> 3);
}
else
{
strideInBytes = width * 3;
}
// allocate the new buffer
unsigned char *pBuffer = new unsigned char[strideInBytes * height];
memset(pBuffer, 0xaa, strideInBytes * height);
// Copy row by row
for (uint32_t yy = 0; yy < height; yy++)
{
uint32_t rowSizeInBytes = width * 3;
unsigned char *pDest = &pBuffer[yy * strideInBytes];
unsigned char *pSrc = &pData[yy * rowSizeInBytes];
memcpy(pDest, pSrc, rowSizeInBytes);
}
rawBMP->pSrc = pBuffer;
rawBMP->width = width;
rawBMP->height = height;
rawBMP->stride = strideInBytes;
已经有一段时间了,但正如我所记得的,只有当您直接访问位图位时,步幅才会发挥作用。BitMapInfo Header.biWidth字段是像素数,而不是每个扫描行的字节数。我建议设置bmih.biWidth=pImage->width;,并使用pImage->width调用BitBlt。@JimMischel我最初设置了biWith和BitBlt的图像宽度(以像素为单位),但这正是鸟图在上面显示的方式,即倾斜到一边。你确定pImage->pSrc有正确的填充字节吗?这就是CreateDiBitmap获取数据以填充图像的地方。如果没有正确的填充,事情就不会发生。@JimMischel我不明白pImage->pSrc只是指向原始的24位数据。图像的宽度是奇数。应该用额外的字节填充原始数据吗?我认为原始图像上没有任何填充。我不希望我必须填充原始数据。biWidth不需要向上取整,您为位图分配的缓冲区大小需要向上取整。每个扫描行从行*开始,跨步字节进入缓冲区。如果您有未填充到DWORD对齐行的原始24位数据,则需要分配一个新的缓冲区并分别复制每一行。