Abanoub
Abanoub

Reputation: 3809

while loading BMP the biSizeImage always 0

I'm trying to load a BMP image using this method :

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 
}

but the bmpInfo->biSizeImage always = 0 , so I have searched and found that I can find out the size in bytes of the bitmap data by multiplying the width by height by (bpp / 8), so I edit the function to be like this :

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 
}

now it's not reading the pixels , the variable pixels is always 0, what am doing wrong here?

EDIT: values of bmpInfo

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

Upvotes: 1

Views: 1310

Answers (2)

Logicrat
Logicrat

Reputation: 4468

The biSizeImage entry correctly may be left at zero for RGB bitmaps. Microsoft documents that behavior here. In that case, you would have to use a different calculation, using biWidth and biHeight.

So the bitmap you are testing with is not necessarily flawed, and a general purpose BMP reader should be prepared for this case.

Upvotes: 1

Chubosaurus Software
Chubosaurus Software

Reputation: 8161

Based on our conversion MixedCoder, I think that bitmap you're trying to load was not correctly saved. We can see that

bmpHeader.bfOffBits = 54;

that means if we subtract our fix size of 14 for the header. That leaves us 40 bytes for the bmpInfo which by definition is the size of the BITMAPINFOHEADER. So we can rule out some misalignment problem.

I would just saved that image again using Paint and load it that way.

Upvotes: 1

Related Questions