I am not sure if this is the right place to ask my question.
If not, can some direct me to the right place, please?
Anyways, here is the problem.
I have written a little program to write bitmaps.
But when I write the bitmap headers as understood from the
specifications I found when googling specifically the offset
to the bitmap data goes in the wrong place.
I used od -d to look at the header that I was producing and the header
of a sample bitmap file. By doing this I saw what needed to be
changed.
And I hacked the code it force things right. But it looks ugly.
I have included the code that should work and the hack.
Here are the octal dumps, note the value of 54 - ie the offset is in
the wrong place. And I cannot figure out why....
Note, I have already reduced the size of the header from 16 bytes to
the expected 14 bytes by not writing the last two bytes to the file.
octal dump of broken bitmap
[ilan@pillemer COS340A]$ od -d gasket.bmp | grep 19778 -C5
0000000 19778 0 54 36 0 0 54 40
0000020 0 1024 0 768 0 1 24 0
0000040 0 0 0 0 0 0 0 0
0000060 0 0 0 0 254 65024 0 254
0000100 65024 1 509 64768 1 509 64768 2
0000120 764 64512 2 764 64512 3 1019 64256
octal dump of bitmap formed by hack - works.
[ilan@pillemer COS340A]$ od -d gasket_hack.bmp | grep 19778 -C5
0000000 19778 0 54 36 0 54 0 40
0000020 0 1024 0 768 0 1 24 0
0000040 0 0 0 0 0 0 0 0
0000060 0 0 0 0 254 65024 0 254
0000100 65024 1 509 64768 1 509 64768 2
0000120 764 64512 2 764 64512 3 1019 64256
[ilan@pillemer COS340A]$
*Code before Hack*
bitfile = fopen("gasket.bmp","wb");
rc = fwrite(&header,sizeof(BITMAPFILEHEADER)-2,1,bitfile);
rc = fwrite(&info,sizeof(BITMAPINFOHEADER),1,bitfile);
typedef struct /**** BMP file header structure ****/
{
unsigned short bfType; /* Magic number for file */
unsigned int bfSize; /* Size of file */
unsigned short bfReserved1; /* Reserved */
unsigned short bfReserved2; /* ... */
unsigned int bfOffBits; /* Offset to bitmap data. */
} BITMAPFILEHEADER;
typedef struct /**** BMP file info structure ****/
{
unsigned int biSize; /* Size of info header */
int biWidth; /* Width of image */
int biHeight; /* Height of image */
unsigned short biPlanes; /* Number of color planes */
unsigned short biBitCount; /* Number of bits per pixel */
unsigned int biCompression; /* Type of compression to use */
unsigned int biSizeImage; /* Size of image data */
int biXPelsPerMeter; /* X pixels per meter */
int biYPelsPerMeter; /* Y pixels per meter */
unsigned int biClrUsed; /* Number of colors used */
unsigned int biClrImportant; /* Number of important colors */
} BITMAPINFOHEADER;
<snip>
bitfile = fopen("gasket.bmp","wb");
rc = fwrite(&header,sizeof(BITMAPFILEHEADER)-2,1,bitfile);
rc = fwrite(&info,sizeof(BITMAPINFOHEADER),1,bitfile);
====================================================================
*Hack*
====================================================================
typedef struct /**** BMP file header structure ****/
{
unsigned short bfType; /* Magic number for file */
unsigned int bfSize; /* Size of file */
unsigned short bfReserved1; /* Reserved */
unsigned short bfReserved2; /* ... */
unsigned int bfOffBits; /* Offset to bitmap data. Actually moved to other header. */
} BITMAPFILEHEADER;
typedef struct /**** BMP file info structure ****/
{
unsigned int bfOffBeats; /* Because of some complication moved offset to here. Ugly Hack. */
unsigned int biSize; /* Size of info header */
int biWidth; /* Width of image */
int biHeight; /* Height of image */
unsigned short biPlanes; /* Number of color planes */
unsigned short biBitCount; /* Number of bits per pixel */
unsigned int biCompression; /* Type of compression to use */
unsigned int biSizeImage; /* Size of image data */
int biXPelsPerMeter; /* X pixels per meter */
int biYPelsPerMeter; /* Y pixels per meter */
unsigned int biClrUsed; /* Number of colors used */
unsigned int biClrImportant; /* Number of important colors */
} BITMAPINFOHEADER;
<snip>
bitfile = fopen("gasket.bmp","wb");
rc = fwrite(&header,sizeof(BITMAPFILEHEADER)-6,1,bitfile);
rc = fwrite(&info,sizeof(BITMAPINFOHEADER),1,bitfile);
Why should you write only 14 bytes instead of 16 bytes as is the size
of the struct? You probably assume that as the size of fields sum up
to 14, if you write 14 bytes you would write all the fields and this
assumption is not correct. You should either be writing field by field
from the structure if you want to optimize for the two bytes or you
should be writing full 16 bytes. By writing 2 bytes less, you are
infact losing the two bytes of the last field, i.e., bfOffBits, in
this case. As you still got the offset correctly, I guess you are
working on a little-endian machine (Intel...). Had you been working on
a big-endian machine or if the offset had been larger than 2^16 and
had you truncated 2 bytes while writing the header, you wouldn't have
even found the correct offset anywhere in the file.
To explain here is the structure with the offsets of each field.
****Important thing to understand is that in a structure, int field
address/offset should by 4-byte aligned and that of short should 2-
byte aligned.****
typedef struct /**** BMP file header structure
****/
{
unsigned short bfType; /* offset 0 */
unsigned int bfSize; /* offset 4 */
unsigned short bfReserved1; /* offset 8 */
unsigned short bfReserved2; /* offset 10 */
unsigned int bfOffBits; /* offset 12 */
} BITMAPFILEHEADER;
So if you notice, the second field (bfSize) would be at the offset 4
and not at 2 as someone might assume based on the size of the first
field which is of type short. So it is the first field (bfType) which
is padded (with two bytes of 0s') and not the last field as someone
might assume.
Essentially, if this header format is your own, you would rather do
better to write full structure. But if it's some standard format of
header you want to write and you want to write only 14 bytes, you need
to first reform the string from the structure so as to take out the
field of exact sizes and then write that. Also, take care of
endianness.
> On Mar 27, 10:49 pm, ilan pillemer <i...@pillemer.net> wrote:
> > Hi,
> >
> > octal dump of broken bitmap
> > [ilan@pillemer COS340A]$ od -d gasket.bmp | grep 19778 -C5
> > 0000000 19778 0 54 36 0 0 54 40
> > 0000020 0 1024 0 768 0 1 24 0
> > 0000040 0 0 0 0 0 0 0 0
> > 0000060 0 0 0 0 254 65024 0 254
> > 0000100 65024 1 509 64768 1 509 64768 2
> > 0000120 764 64512 2 764 64512 3 1019 64256
> >
> > octal dump of bitmap formed by hack - works.
> > [ilan@pillemer COS340A]$ od -d gasket_hack.bmp | grep 19778 -C5
> > 0000000 19778 0 54 36 0 54 0 40
> > 0000020 0 1024 0 768 0 1 24 0
> > 0000040 0 0 0 0 0 0 0 0
> > 0000060 0 0 0 0 254 65024 0 254
> > 0000100 65024 1 509 64768 1 509 64768 2
> > 0000120 764 64512 2 764 64512 3 1019 64256
> > [ilan@pillemer COS340A]$
>
Wow... That explains it to me perfectly. I just assumed it was at the
end; and I could see that it was not Endianness that was causing the
problem or my desperate hack would not have worked. So I was
completely and utterly confused. I asked a lot of people (so-called
experts) who all gave me explanations that I could see were wrong.
Finally an answer that explains it perfectly.. Thanks again. I am just
a newbie at this.
>
> Essentially, if this header format is your own, you would rather do
> better to write full structure. But if it's some standard format of
> header you want to write and you want to write only 14 bytes, you need
> to first reform the string from the structure so as to take out the
> field of exact sizes and then write that. Also, take care of
> endianness.
I can not control the format, it is a standard format and I need to
write only 14 bytes.
Thanks for the help; I really appreciate it as until now no-one
anywhere could lead me out of the confusion.
-- ilAn