Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Storing (16, 24, 32)bpp bitmaps in binary files.

This thread is locked; no one can reply to it. rss feed Print
Storing (16, 24, 32)bpp bitmaps in binary files.
Paul whoknows
Member #5,081
September 2004
avatar

Due to the complexity of my game I have decided to create my own file format for graphic data storage.
I never did this before, so I want to begin with something simple.
I want to begin writing simple bitmaps to binary files.
Let's say I want to store 5 frames of a 100x100x16bpp bitmap in a binary file.
I guess I will need something like this:

typedef struct {
  int frame_number;
  char bytes[10000];  /* How many bytes do I need to store a single pixel in 16bpp? */
}my_frame;

I want to LEARN how to deal whit this, so detailed explanation, theory, and/or links will be accepted! thanks!
C only please.

____

"The unlimited potential has been replaced by the concrete reality of what I programmed today." - Jordan Mechner.

Arthur Kalliokoski
Second in Command
February 2005
avatar

I don't have one with me, but I use

typedef struct
{
 int width;   //pixels, not bytes per line
 int height;
 int color_depth; //in bytes, not bits per pixel
 int rgba;        //set to 1 for rgba (when color_depth == 4) or 0 for bgra
 int version;     //very helpful when you change this struct!
}TEXHEADER;

so size of image data is width*height*color_depth. You could also have another int for how many bytes past TEXHEADER the actual pixel data starts to make room for variable sized comment strings or something.

I just seen you want 5 frames, maybe add yet another int for how many times the pixel data is repeated?

[EDIT] I just remembered that the color_depth doesn't discriminate between 15/16 bits per pixel, but I don't use 15, or 8 for that matter.

They all watch too much MSNBC... they get ideas.

Paul whoknows
Member #5,081
September 2004
avatar

Thanks very much!
Another int added for frames, just like you said, but to make life easier I won't allow different size frames...just for now.

typedef struct
{
 int width;   //pixels, not bytes per line
 int height;
 int color_depth; //in bytes, not bits per pixel
 int rgba;        //set to 1 for rgba (when color_depth == 4) or 0 for bgra
 int version;     //very helpful when you change this struct!
 int frames;    //amount of frames  
}TEXHEADER;

So the header should look like this:
0000 Width 0001 0002 0003 0004 Height 0005 0006 0007 0008 color depth 0009 000A 000B 000C rgba 000D 000E 000F 0010 version 0011 0012 0013 0014 frames 0015 0016 0017 0018 Begin of data . .

I don't understand the rgba flag, what's the diference between bgra or rgba?
I am not sure about how I should store my bytes, little or big endian???

____

"The unlimited potential has been replaced by the concrete reality of what I programmed today." - Jordan Mechner.

Arthur Kalliokoski
Second in Command
February 2005
avatar

Assuming for OpenGL:

rgba vs. bgra is the order the red, blue, green values are stored, Windows uses bgr and I've read on an Nvidia page that they've optimized bgr as opposed to rgb due to Windows. Some older cards may not handle the bgr order, check the flags. If you're worried about porting to other cpu's, you could either store/load the bytes individually or (probably faster) swap them around after loading from disk. I haven't had a big-endian computer (well, Motorola 8 bit doesn't have an endianness) but

union
{
 int a;
 char b[4];
}endian;

int is_small_endian = 0;

endian.a = 1;
is_small_endian = endian.b[3];  //little endian would set b[0]

They all watch too much MSNBC... they get ideas.

ImLeftFooted
Member #3,935
October 2003
avatar

#define POST_PACKED __attribute__((packed))

struct TEXHEADER
{
 int32_t width;   //pixels, not bytes per line
 int32_t height;
 int32_t color_depth; //in bytes, not bits per pixel
 int32_t rgba;        //set to 1 for rgba (when color_depth == 4) or 0 for bgra
 int32_t version;     //very helpful when you change this struct!
 int32_t frames;    //amount of frames  
} POST_PACKED;

Now you're rollin.

orz
Member #565
August 2000

That doesn't actually change the size of the struct in question (try a sizeof on it both ways, on any platform gcc supports today), and it breaks compatibility with some compilers.

edit: okay, I'm just whining pointlessly; the #define could be #ifdefed to something equivalent on another compiler to improve compatibility, and while packing it doesn't change this particular struct, it is vaguely appropriate for structs corresponding to formats on disk.

Paul whoknows
Member #5,081
September 2004
avatar

Quote:

union
{
 int a;
 char b[4];
}endian;

That's amazing! really useful, thanks!

Quote:

#define POST_PACKED __attribute__((packed))

Dustin I don't know what are you doing here, please can you comment it?
I do never use structs, I use typedefs structs instead, something wrong with that?
Problems with ifferent size of ints isn't a problem right now, but perhaps this would be a better alternative:

typedef struct
{
 /* width */
 char width[4];
 char height[4];
.
.
. and so on

EDITED!!!

____

"The unlimited potential has been replaced by the concrete reality of what I programmed today." - Jordan Mechner.

ImLeftFooted
Member #3,935
October 2003
avatar

Quote:

Dustin I don't know what are you doing here, please can you comment it?
I do never use structs, I use typedefs structs instead, something wrong with that?
Problems with ifferent size of ints isn't a problem right now, but perhaps this would be a better alternative:

If you're going to be accessing the data of a struct manually, then specify the packed option. Don't do it and the god of coding karma will strike you down.

You might as well just use the struct name, unless you're trying to conform to an old C standard. typedef went out of style decades ago.

Different sized ints are always a problem.

Paul whoknows
Member #5,081
September 2004
avatar

Quote:

if you're going to be accessing the data of a struct manually, then specify the packed option. Don't do it and the god of coding karma will strike you down.

The keyword _attribute_ doesn't exist in my Borland 5.0 compiler! is that ANSI C supported?

Quote:

You might as well just use the struct name, unless you're trying to conform to an old C standard.

Like I said at the beginning of this post I am using C.

____

"The unlimited potential has been replaced by the concrete reality of what I programmed today." - Jordan Mechner.

orz
Member #565
August 2000

Quote:

The keyword _attribute_ doesn't exist in my Borland 5.0 compiler! is that ANSI C supported?

It's gcc-only. There are equivalents in most compilers though. I don't know about Borland. Try looking up "packing" or "alignment", or anything about controlling the actual layout of structure members in memory in any docs you have.

Ron Ofir
Member #2,357
May 2002
avatar

Isn't packing only relevant when you directly write the struct to disk? I thikn it's better to simply write the fields one after another insteda of all of them at the same time.

orz
Member #565
August 2000

Quote:

Isn't packing only relevant when you directly write the struct to disk?

Pretty much. It can effect the size of the struct in memory as well, but that's not usually important.

Quote:

I thikn it's better to simply write the fields one after another insteda of all of them at the same time.

Some people find it easier to code / maintain / examine / debug / etc to let that happen automatically in a single fwrite call or whatever.

Thomas Fjellstrom
Member #476
June 2000
avatar

Quote:

Some people find it easier to code / maintain / examine / debug / etc to let that happen automatically in a single fwrite call or whatever.

And now you have endian dependant files. Not as important as it once was, but if you ever want those images to load properly on a BigEndian machine, never write the struct directly.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

orz
Member #565
August 2000

Quote:

And now you have endian dependant files. Not as important as it once was, but if you ever want those images to load properly on a BigEndian machine, never write the struct directly.

Some people use the structs with endian-independant integer types (ie plain ints on one endianness, #ifdefed to classes that emulate non-native endiannes ints on the other endianness). Not a very popular practice admittedly, but I know a few.

Thomas Fjellstrom
Member #476
June 2000
avatar

The "best" (IMO) method is just to store and read the ints in a single endian, and convert to the proper endian on load (if needed).

for example, you can use:

// set 1
pack_igetw(); pack_iputw(); // 16 bit
pack_igetl(); pack_iputl(); // 32 bit

// set 2
pack_mgetw(); pack_mputw();
pack_mgetl(); pack_mputl();

Use one or the other, and your ints will be properly saved and loaded, without having to worry about endianess.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Go to: