Sign in to follow this  
myvraccount

Goofy bitmap horrible nonsense garbage!

Recommended Posts

myvraccount    235

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
myvraccount    235

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
frob    44974

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
Nypyren    12074
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
Alberth    9527

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
felipefsdev    360
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
irreversible    2862

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
myvraccount    235
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
myvraccount    235

All I meant was that unless there's a specific standard divisibility that is always used, there would be no way to know for certain how the data's stored, unless there's a field in the header that specifies it, like how the bits per pixel field specifies the pixel format.

Share this post


Link to post
Share on other sites
Alberth    9527
All I meant was that unless there's a specific standard divisibility that is always used, there would be no way to know for certain how the data's stored,

Of course there is, the file format is documented, which means it is described how data is stored there. There are usually also libraries that deal with all the low-level details if you don't (want to) know.

You are free to ignore existence of the documentation and such libraries, but don't complain about stuff being unclear then.

Edited by Alberth

Share this post


Link to post
Share on other sites
mhagain    13430

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?

 

It's not dumb, it means that a scan line is aligned on a 4 byte boundary and can always be read in chunks of 4 bytes.  Think a little about possible intended uses of bitmaps and how this may interact with hardware.

You're very quick to dismiss something as "dumb", in this and other threads, in cases where a little more understanding on your part may actually be of benefit to you.

Share this post


Link to post
Share on other sites
frob    44974

Use whatever you want. Just be aware that most games don't use any of the formats mentioned, except by artists who use a lossless algorithm. The formats you mention require parsing, potentially expanding or decoding, then eventual uploading to the graphics card. 

Most modern games encode the files into a compressed format supported directly by the graphics card, which can be dumped directly into video memory without any additional processing nor any unexpected artifacts. S3/DXT, PVRTC, ETCX, ATITC, and other formats are all compressed and directly usable on the proper cards.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this