无法获取BITMAPINFOHEADER数据以正确显示奇数宽度的bmp图像

时间:2017-04-04 17:47:47

标签: winapi bitmap

我正在尝试使用标准的Win32 API调用来显示具有奇数宽度的24位未压缩位图,但似乎我有一个跨步问题。

根据msdn:

https://msdn.microsoft.com/en-us/library/windows/desktop/dd318229%28v=vs.85%29.aspx

"对于未压缩的RGB格式,最小步幅始终是以字节为单位的图像宽度,向上舍入为最接近的DWORD。您可以使用以下公式计算步幅:

stride =((((biWidth * biBitCount)+ 31)& ~31)>>> 3)"

但这对我来说根本不起作用,下面是代码:

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;

图片看起来有些偏差,下面显示了差异:

enter image description here

如果我按照msdn传递步幅,那么没有任何内容显示,因为步幅太大。

任何线索?谢谢!

1 个答案:

答案 0 :(得分:1)

感谢Jonathan的解决方案。我需要逐行复制,并为奇数宽度图像提供适当的填充。或多或少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;