Jump to content
  • Advertisement
Sign in to follow this  
myvraccount

Goofy bitmap horrible nonsense garbage!

This topic is 464 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 was trying to read bitmaps manually by just loading the files and reading bytes from them, and I noticed something very odd.  I got some unexpected results when I read or manipulated the data for bitmaps in which the width and/or height is not divisible by 4, but it always seemed to work fine when they are divisible by 4.

 

I looked though the header information I was getting, and weirdly, the file size and image size fields (I don't know why it needs both, one's just the other + 54 for the header size, but whatever) are larger than they should be.  They're still a difference of 54, but the image size is bigger than the actual number of pixels * bytes per pixel (3 for 24 bit color).

 

This seemed to be the cause of a problem when I tried to save a bitmap, so even when I tried to just read one and write it directly to another one, it wouldn't open in Paint or any image viewer.  I suspected that it was because it thinks the file size is larger than it actually is, because the header info is wrong (which makes me wonder, what is Paint storing in the extra data?).

 

So I tried adjusting those 2 fields to equal the actual amount of bytes of my pixels (+ 54 for the file size), and now it will open, but looks oddly skewed.  I thought that maybe it's padding the scan lines with blank pixels or something, but that would be wasteful, and nothing in the header seems to indicate any amount of padding.  So I tried copying the data first before saving it, and copied pixel by pixel, so that it would come in correctly, but that doesn't fix it either.

 

I've used bitmaps before, and never had a problem like this.  What could be wrong with it?  And no, I DON'T have source code, but for God's sake, this is a common enough format that someone should understand it anyway, isn't it?

Share this post


Link to post
Share on other sites
Advertisement

Oh, I just read somewhere that bitmap scan lines are padded to have a multiple of 4 bytes per line.  That's dumb; what's the point of it?  And can I be absolutely sure that it's universally true, or is it optional?

Share this post


Link to post
Share on other sites

I've used bitmaps before, and never had a problem like this.  What could be wrong with it?  And no, I DON'T have source code, but for God's sake, this is a common enough format that someone should understand it anyway, isn't it?

Many people understand it, and it is extremely well documented.  Not only in MSDN, but also many different file format sites, and even in Wikipedia.

The bitmap format is old, dating back to the early 1980s. That's why you see so many thing you might think are strange.

 

 

The sizes don't necessarily need to be run by fours, they can be different sizes. This is due to old hardware that worked with different size scan lines relative to the sizes of the displayed images.

There are plenty of places in the format where gaps appear. Again, this is due to hardware variation over the decades.

Data was originally one bit per pixel for black and white images (where the original bitmap name came from) up through 32 bits per pixel commonly used today. Colors can be stored in color tables, in bitplanes, in RGB values, and other formats besides. Those all come from hardware and software evolution over the decades.

Byte ordering of data can differ because of old hardware. People today use RGB or RGBA ordering. Back years ago BGR and BGRA were the common orderings, so those are supported in the format.  

The same thing with color planes, back in CGA, EGA, and VGA monitor eras through the 80s and 90s data was not stored in RGB triplets. It wasn't until VGA introduced something called "chained" mode. It was more friendly to hobby developers because they could work in RGB sets instead of color planes with more complicated offsets, and it was slower for the graphics cards, and it meant you could only reference 64K instead of the full 256K of video memory. But most casual developers were wiling to take the tradeoffs of slower graphics and less memory in exchange for ease of use.  So there's another historical change.

Many years ago devices commonly had pixel ordering that went bottom to top, so that's why they have positive height going bottom to top, negative height going top to bottom.

30 years of updates have caused many variations and subtleties in the file format. 

Share this post


Link to post
Share on other sites
Very frequently when accessing raw pixel data, you will need to use the "stride" of a row instead of the width when calculating the index for a given x,y.

ex:

index = y * stride + x; // right
index = y * width + x; // wrong unless you get lucky and stride == width

Share this post


Link to post
Share on other sites

Is bitmap really that simple? Headers palettes then pixel data I thought pixel data is related to palette
It varies. In black/white image formats (mono colours), it's literally a bit for each pixel. The colours aren't relevant mostly, it's commonly used for masks. (The XBM format is fun, its data is stored as C-text, so you can literally #include "myimage.xbm" and access the array.)

8bpp image formats like gif or png used a palette, mostly originating from the video hardware, where having 3 bytes for each pixel was too costly, so they had a 256 entries palette, and one byte for each pixel instead.

Nowadays, memory size is a non-issue, so you have 3 bytes for each pixel at least, and 4 bytes is common, since that aligns better in memory.

Share this post


Link to post
Share on other sites
Btw, 1) why are you using BMP and not PNG? and 2) why don't you use a simple library to handle that? I know for some cases it's interesting to make your own implementation of things for learning purpose, reducing dependencies or reducing executable size. But, BMP and PNG are not simple formats. Even if you achieve the implementation of the loader, you will be just executing a step-by-step (like in the list frob mentioned).

Share this post


Link to post
Share on other sites

Btw, 1) why are you using BMP and not PNG? and 2) why don't you use a simple library to handle that? I know for some cases it's interesting to make your own implementation of things for learning purpose, reducing dependencies or reducing executable size. But, BMP and PNG are not simple formats. Even if you achieve the implementation of the loader, you will be just executing a step-by-step (like in the list frob mentioned).

 

1) There is a huge gap in complexity between the two if you're trying to write your own loader. Also, granted, my PNG code is slow to start with and I've added some minor optimizations to my BMP loader, but the two are likely to yield fairly different execution times.

2) BMP is rather a simple format if you're not trying to support every single variation out there. If you only ever need 24- or 32-bit 8bpp RGB(A) formats, then reading these from disk and passing directly to the GPU is actually trivial. This is particularly true if you doctor your own art and becomes a desirable limitation when you decide what formats you want to support in the long run. If you're dealing with complex formats or non-standard bpp values, then that is what your favorite Photoshop (clone) is for. With basic bitmaps all you really need to worry about is the vertical flip, which - if you're lazy - can be undone with a simple tex coord swap.

That being said, the true power of a custom-rolled BMP implementation comes when you need to dump images to disk. It's slow, but you can roll one out in minutes if you only ever need the abovementioned basic formats. And you won't need to worry about looking for an external library, managing dependencies, incompatibilities, lack of maintenance and so forth. Incidentally, the same applies to writing a wav importer/exporter.

TL;DR - if you only need support for basic color formats, then importing and exporting a bitmap pretty much becomes a block write operation.

Share this post


Link to post
Share on other sites
Very frequently when accessing raw pixel data, you will need to use the "stride" of a row instead of the width when calculating the index for a given x,y.

Well where in the header is the "stride" stored, so that I can know for certain what it is?  Based on what I've seen, there's just a width and height, and a horizontal and vertical resolution measured in pixels per meter (which seems arbitrary, and I don't use it for anything).

 

And yes, I realize that there are palette bitmaps and all that, which work differently, but I'm just using a plain old 24-bit image, which btw is specified as a field in the header, so that it's possible to know how to read/write the data.  If the "stride" isn't specified anywhere, what am I supposed to do, just guess and hope I'm correct?!

Edited by myvraccount

Share this post


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

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!