Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Winapi 无法获取BitMapInfo标头数据以正确显示奇数宽度bmp图像_Winapi_Bitmap - Fatal编程技术网

Winapi 无法获取BitMapInfo标头数据以正确显示奇数宽度bmp图像

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

我正在尝试使用标准Win32 API调用显示奇数宽度的24位未压缩位图,但似乎我遇到了步幅问题

根据msdn:

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

步幅=双宽*双比特计数+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;
图片看起来有点歪斜,下面显示了不同之处:

如果我根据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位数据,则需要分配一个新的缓冲区并分别复制每一行。