• Advertisement
Sign in to follow this  

reading 24 bit per pixel bitmaps issue

This topic is 1839 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm currently trying to read bitmaps without using an image library.

My current implementation can read bitmaps ,however, issues occur when both the width and height are not of base 2. 

To be more specific, when I tired to render a 922x910 bitmap ,the colors didn't come in correctly. Sometimes bitmaps of different resolutions turnout looking "stretched" and without the correct colors.  

To get my bitmaps I let microsoft paint convert png's, jpegs and other formats to .bmp.

The ultimate purpose for all of this is to implement the marching squares method so I can generate polygons from sprites.

How do I deal with this? 

 

My bitmap code so far:

#ifndef COLOR_VECTOR
#define COLOR_VECTOR
struct ColorVector{
    unsigned char r;
    unsigned char g;
    unsigned char b;
    unsigned char a;
};
#endif

 

class uBitmap{
    public:
        uBitmap(std::string path,BYTE redColorKey, BYTE greenColorKey,BYTE blueColorKey);
        ~uBitmap();
        unsigned int getWidth();
        unsigned int getHeight();
        long int getPixel(int x, int y);
        ColorVector getPixelVector(int x, int y);
        void resizeBuffer(unsigned int size);
        void clearBuffer();
        void putPixel(int x, int y, BYTE r, BYTE g, BYTE b);
        void saveBitmap(std::string filename);
        void renderImage();
    private:
        BITMAPFILEHEADER bitmapHeader_;
        BITMAPINFOHEADER bitmapInfoHeader_;
        BYTE* rgbPixelData_;
        BYTE* rgbaPixelData_;
        ColorVector colorKey_;
};

 

 

uBitmap::uBitmap(std::string path,BYTE redColorKey, BYTE greenColorKey,BYTE blueColorKey){
    BITMAPFILEHEADER& fileHeader = bitmapHeader_;
    BITMAPINFOHEADER& infoHeader = bitmapInfoHeader_;
    BYTE*& pixelData = rgbPixelData_;

    bitmapInfoHeader_.biWidth = 0;
    bitmapInfoHeader_.biHeight = 0;
    rgbPixelData_ = NULL;
    rgbaPixelData_ = NULL;

    std::ifstream file(path.data(),std::ios::binary);
    if(file.is_open()){
        file.read((char*)&bitmapHeader_    ,sizeof(BITMAPFILEHEADER));
        file.read((char*)&bitmapInfoHeader_,sizeof(BITMAPINFOHEADER));
        rgbPixelData_ = new BYTE[infoHeader.biSizeImage];
        file.read((char*)rgbPixelData_,infoHeader.biSizeImage);
    }
    file.close();
}

uBitmap::~uBitmap(){
    if(rgbPixelData_ != NULL){
        delete[] rgbPixelData_;
    }

    if(rgbaPixelData_ != NULL){
        delete[] rgbaPixelData_;
    }
}

unsigned int uBitmap::getWidth(){
    return bitmapInfoHeader_.biWidth;
}

unsigned int uBitmap::getHeight(){
    return bitmapInfoHeader_.biHeight;
}

/*long int uBitmap::getPixel(int x, int y){// attempting to pack color components into an integer
    ColorVector pix = getPixelVector(x,y);
    return  (pix.b << 24) | (pix.g << 16)  | (pix.r << 8) ;
}*/

ColorVector uBitmap::getPixelVector(int x, int y){
    ColorVector curElement;
    unsigned int firstComponent = (y*getWidth()+x)*3;//which is the blue color vector component
    curElement.b = *(rgbPixelData_+firstComponent);  //reading first component (blue)
    curElement.g = *(rgbPixelData_+firstComponent+1);//reading second component (green)
    curElement.r = *(rgbPixelData_+firstComponent+2);//reading third component (red)
    return curElement;
}

void uBitmap::renderImage(){
    glBegin(GL_POINTS);
    for(unsigned int y = 0; y < getHeight();y++){
        for(unsigned int x = 0; x < getWidth();x++){
            ColorVector c = getPixelVector(x,getHeight() - y);
            glColor3ub(c.r,c.g ,c.b);
            glVertex2i(x,y);
        }
    }
    glEnd();
}

Please note:I realize that using immediate mode to render a bitmap is a horrible idea,however, its more a debugging function than anything else. Just putting that out there. 

 

*EDIT*

I seemed to have fixed the problem. You guys were completely right about the padding. All I did was slightly modify the constructor to fix my problem:

uBitmap::uBitmap(std::string path,BYTE redColorKey, BYTE greenColorKey,BYTE blueColorKey{
    BITMAPFILEHEADER& fileHeader = bitmapHeader_;
    BITMAPINFOHEADER& infoHeader = bitmapInfoHeader_;
    BYTE*& pixelData = rgbPixelData_;
    bitmapInfoHeader_.biWidth = 0;
    bitmapInfoHeader_.biHeight = 0;
    rgbPixelData_ = NULL;
    rgbaPixelData_ = NULL;

    std::ifstream file(path.data(),std::ios::binary);
    if(file.is_open()){
        file.read((char*)&bitmapHeader_    ,sizeof(BITMAPFILEHEADER));
        file.read((char*)&bitmapInfoHeader_,sizeof(BITMAPINFOHEADER));
        
        int desiredRow = int(ceilf((((float)getWidth())*3.0f) / 4.0f) * 4.0f);
        int rowPadding = desiredRow - (getWidth()*3);
        rgbPixelData_ = new BYTE[ (getWidth()*getHeight()*3) + (rowPadding*getHeight());
        for(unsigned int I = 0; I < getHeight();I++){
            file.read(((char*)rgbPixelData_)+(I*getWidth()*3),desiredRow);
        }

    }
    file.close();
}
Edited by thecoast47

Share this post


Link to post
Share on other sites
Advertisement
I don't know the details of the bmp format, but you may want to check to see if it employs a stride in non-pow2 images, which would effect the offset of texels within the data. 'Stride' is essentially used for handling a 'padding' space at the end of each row which aligns the data to the next nearest pow2. The stride value should be either the width of the padding or else the width of a row with the padding included.

Can you post an image showing the kind of distortion you're getting? Edited by Khatharr

Share this post


Link to post
Share on other sites
I don't know the details of the bmp format, but you may want to check to see if it employs a stride in non-pow2 images, which would effect the offset of texels within the data. 'Stride' is essentially used for handling a 'padding' space at the end of each row which aligns the data to the next nearest pow2. The stride value should be either the width of the padding or else the width of a row with the padding included.

Can you post an image showing the kind of distortion you're getting?

This is what I get when i try to render a 305x298 bitmap 

Share this post


Link to post
Share on other sites
Bitmap images do have a padding. Every row of pixel data must be padded to a full multiple of 32 bit.<br /><br />So for your example, with 305 pixels, 305 * 3 (24bit) = 915 bytes per row. The next full multiple is at 916, so you have to read one extra padding byte.

Share this post


Link to post
Share on other sites

I remember struggling with this a few years ago. I wrote a class and demo that demonstrate specifically rendering to bitmaps. I think you will find the source code helpful for understanding bitmaps better.

 

Note that while the class supports working with 24-bit bitmaps, you will find the performance when working with 32-bit bitmaps much better.

Find the demo and blog post here: http://code-section.com/entry/20/gdi-memory-bitmap

I hope this helps.

Share this post


Link to post
Share on other sites
Once a few years ago I wanted to write bmp load and safe routines too. What I found out was that the format is a badly documented, actually 5+ different incompatible formats with one file extension and if you pick one to write your data out you depend on the mercy and undocumented quirks of the loading routine of some other program you try to get your data into, to support this exact format and actually recognize the version you used and reads all headerfields exactly in the way you wrote them out and not just ignore some and read data at some offset itself always uses for writing.
You better just get some tested image library that can handle better file formats like for example png than rolling your own quirky bmp loader that works on some files but silently garbles others. Or if you really want to load a bmp at least use some Windows function so you can have halfway compatible quirks in your loading routine. Edited by wintertime

Share this post


Link to post
Share on other sites
...snip...

Yeah, BMP is a bad format to use. Bloated, poorly documented, difficult to load, etc. I prefer TGA. There is tons of information on the format, it is easy to load and not protected by patents like PNG.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement