加载BMP时,biSizeImage始终为0

时间:2014-08-02 13:31:06

标签: c++ image bitmap pixels

我尝试使用此方法加载BMP图像:

int TextureManager::LoadBMP(std::string path, unsigned int &texture)
{
    unsigned char* datBuff[2] = { nullptr, nullptr }; // Header buffers

    unsigned char* pixels = nullptr; // Pixels

    BITMAPFILEHEADER* bmpHeader = nullptr; // Header
    BITMAPINFOHEADER* bmpInfo = nullptr; // Info 

    std::ifstream file(path, std::ios::binary);
    if (!file)
    {
        std::cout << "Failure to open bitmap file.\n";

        return 1;
    }

    // Allocate byte memory that will hold the two headers
    datBuff[0] = new unsigned char[sizeof(BITMAPFILEHEADER)];
    datBuff[1] = new unsigned char[sizeof(BITMAPINFOHEADER)];

    file.read((char*)datBuff[0], sizeof(BITMAPFILEHEADER));
    file.read((char*)datBuff[1], sizeof(BITMAPINFOHEADER));

    // Construct the values from the buffers
    bmpHeader = (BITMAPFILEHEADER*)datBuff[0];
    bmpInfo = (BITMAPINFOHEADER*)datBuff[1];

    // Check if the file is an actual BMP file
    if (bmpHeader->bfType != 0x4D42)
    {
        std::cout << "File \"" << path << "\" isn't a bitmap file\n";
        return 2;
    }

    // First allocate pixel memory
    pixels = new unsigned char[bmpInfo->biSizeImage];

    // Go to where image data starts, then read in image data
    file.seekg(bmpHeader->bfOffBits);
    file.read((char*)pixels, bmpInfo->biSizeImage);

    unsigned char tmpRGB = 0; // Swap buffer
    for (unsigned long i = 0; i < bmpInfo->biSizeImage; i += 3)
    {
        tmpRGB = pixels[i];
        pixels[i] = pixels[i + 2];
        pixels[i + 2] = tmpRGB;
    }

    // Set width and height to the values loaded from the file
    unsigned int w = bmpInfo->biWidth;
    unsigned int h = bmpInfo->biHeight;

    /TODO:***************GENERATING TEXTURES*******************/

    // Output a successful message
    std::cout << "Texture \"" << path << "\" successfully loaded.\n";

    // Delete the two buffers.
    delete[] datBuff[0];
    delete[] datBuff[1];
    delete[] pixels;

    return 0; // Return success code 
}

但是bmpInfo->biSizeImage总是= 0,所以我搜索并发现我可以通过将宽度乘以高度(bpp / 8)来找出位图数据的字节大小,所以我编辑了功能是这样的:

int TextureManager::LoadBMP(std::string path, unsigned int &texture)
{
    unsigned char* datBuff[2] = { nullptr, nullptr }; // Header buffers

    unsigned char* pixels = nullptr; // Pixels

    BITMAPFILEHEADER* bmpHeader = nullptr; // Header
    BITMAPINFOHEADER* bmpInfo = nullptr; // Info 

    std::ifstream file(path, std::ios::binary);
    if (!file)
    {
        std::cout << "Failure to open bitmap file.\n";

        return 1;
    }

    // Allocate byte memory that will hold the two headers
    datBuff[0] = new unsigned char[sizeof(BITMAPFILEHEADER)];
    datBuff[1] = new unsigned char[sizeof(BITMAPINFOHEADER)];

    file.read((char*)datBuff[0], sizeof(BITMAPFILEHEADER));
    file.read((char*)datBuff[1], sizeof(BITMAPINFOHEADER));

    // Construct the values from the buffers
    bmpHeader = (BITMAPFILEHEADER*)datBuff[0];
    bmpInfo = (BITMAPINFOHEADER*)datBuff[1];

    // Check if the file is an actual BMP file
    if (bmpHeader->bfType != 0x4D42)
    {
        std::cout << "File \"" << path << "\" isn't a bitmap file\n";
        return 2;
    }

    DWORD       FileDataSize;
    DWORD       ActualDataSize;
    LONG        AjustedWidth;
    LONG        WidthOver = 0;      

    if (((bmpInfo->biWidth * (bmpInfo->biBitCount / 8)) % 4) != 0)
    {
        WidthOver = 4 - ((bmpInfo->biWidth * (bmpInfo->biBitCount / 8)) % 4);
    }
    AjustedWidth = bmpInfo->biWidth + WidthOver;
    ActualDataSize = bmpInfo->biWidth * bmpInfo->biHeight * (bmpInfo->biBitCount / 8);
    FileDataSize = AjustedWidth * bmpInfo->biHeight * (bmpInfo->biBitCount / 8);


    // First allocate pixel memory
    pixels = new unsigned char[FileDataSize];

    // Go to where image data starts, then read in image data
    file.seekg(bmpHeader->bfOffBits);
    file.read((char*)pixels, FileDataSize);

    unsigned char tmpRGB = 0; // Swap buffer
    for (unsigned long i = 0; i < FileDataSize; i += 3)
    {
        tmpRGB = pixels[i];
        pixels[i] = pixels[i + 2];
        pixels[i + 2] = tmpRGB;
    }

    // Set width and height to the values loaded from the file
    unsigned int w = bmpInfo->biWidth;
    unsigned int h = bmpInfo->biHeight;

    /TODO:***************GENERATING TEXTURES*******************/

    // Output a successful message
    std::cout << "Texture \"" << path << "\" successfully loaded.\n";

    // Delete the two buffers.
    delete[] datBuff[0];
    delete[] datBuff[1];
    delete[] pixels;

    return 0; // Return success code 
}

现在它没有读取像素,可变像素总是0,这里做错了什么?

编辑:bmpInfo

的值
biSize  40  
biWidth 1024    
biHeight    1024    
biPlanes    1   
biBitCount  32  
biCompression   0
biSizeImage 0   
biXPelsPerMeter 0
biYPelsPerMeter 0
biClrUsed   0
biClrImportant  0

2 个答案:

答案 0 :(得分:1)

根据我们的转换MixedCoder,我认为您尝试加载的位图未正确保存。我们可以看到

bmpHeader.bfOffBits = 54;

这意味着如果我们将标题的修复大小减去14。这为bmpInfo留下了40个字节,根据定义,它是BITMAPINFOHEADER的大小。所以我们可以排除一些错位问题。

我只是使用Paint再次保存该图像并以此方式加载。

答案 1 :(得分:1)

对于RGB位图,正确的biSizeImage条目可以保留为零。 Microsoft记录了行为here。在这种情况下,您必须使用biWidth和biHeight使用不同的计算。

因此,您正在测试的位图不一定存在缺陷,应为此案例准备一个通用的BMP阅读器。