hi,
i wrote the following piece code to create a new bitmap file with random RGB values. I wanted to copy the header from the input file.
the problem is it adds two additional bytes to 3rd and 4th (just after the magic number). i can't figure out why.

// img.magic.magic[2] = 'G';
// img.magic.magic[3] = 'Y';

if i uncomment the above lines. those bytes will be replaced by 'G' and 'Y'.

can anyone please explain me what's going on here?

thanks in advance.

#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <stdlib.h>
#include <inttypes.h>
#include <sys/types.h>
#include <unistd.h>

typedef struct bmpfile_magic {
	uint8_t magic[2];
} MAGIC;

typedef struct bmpfile_header {
	uint32_t filesz;
	uint16_t creator1;
	uint16_t creator2;
	uint32_t bmp_offset;
} BITMAPHEADER;

typedef struct {
	uint32_t header_sz;
	int32_t width;
	int32_t height;
	uint16_t nplanes;
	uint16_t bitspp;
	uint32_t compress_type;
	uint32_t bmp_bytesz;
	int32_t hres;
	int32_t vres;
	uint32_t ncolors;
	uint32_t nimpcolors;
} BITMAPINFOHEADER;

typedef struct {
	MAGIC magic;
	BITMAPHEADER head;
	BITMAPINFOHEADER infohead;
	int ***pixel;
} image;

int
main (int argc, char **argv)
{
	int fd;
	fd = open(argv[1], O_RDONLY);
	
	image img;
	
	ssize_t n;
	int val;
	
	// grabbing the header
	// magic numbers
	uint8_t v1;
	n = read(fd, &v1, 1);
	img.magic.magic[0] = v1;
	printf ("filetype: %c", img.magic.magic[0]);
	
	n = read(fd, &v1, 1);
	img.magic.magic[1] = v1;
	printf ("%c\n", img.magic.magic[1]);
	
	// img.magic.magic[2] = 'G';
	// img.magic.magic[3] = 'Y';
	
	// file size
	n = read(fd, &val, 4);
	img.head.filesz = val;
	printf ("file size: %"PRIu32"\n", img.head.filesz);
	
	// creator 1
	n = read(fd, &val, 2);
	img.head.creator1 = val;
	printf ("creator1: %d\n", img.head.creator1);
	
	// creator 2
	n = read(fd, &val, 2);
	img.head.creator2 = val;
	printf ("creator2: %d\n", img.head.creator2);
	
	// bitmap offset
	n = read(fd, &val, 4);
	img.head.bmp_offset = val;
	printf ("bitmap offset: %d\n", img.head.bmp_offset);
	
	// header size
	n = read(fd, &val, 4);
	img.infohead.header_sz = val;
	printf ("header size: %d\n", img.infohead.header_sz);
	
	// width
	n = read(fd, &val, 4);
	img.infohead.width = val;
	printf ("width: %d\n", img.infohead.width);
	
	// height
	n = read(fd, &val, 4);
	img.infohead.height = val;
	printf ("height: %d\n", img.infohead.height);
	
	// planes
	n = read(fd, &val, 2);
	img.infohead.nplanes = val;
	printf ("planes: %d\n", img.infohead.nplanes);
	
	// bits per pixel
	n = read(fd, &val, 2);
	img.infohead.bitspp = val;
	printf ("bits per pixel: %d\n", img.infohead.bitspp);
	
	// compression type
	n = read(fd, &val, 4);
	img.infohead.compress_type = val;
	printf ("compression type: %d\n", img.infohead.compress_type);
	
	// size of raw data including padding
	n = read(fd, &val, 4);
	img.infohead.bmp_bytesz = val;
	printf ("size of raw data(including padding): %d\n", img.infohead.bmp_bytesz);
	
	// horizontal resolution
	n = read(fd, &val, 4);
	img.infohead.hres = val;
	printf ("horizontal resolution: %d\n", img.infohead.hres);
	
	// vertical resolution
	n = read(fd, &val, 4);
	img.infohead.vres = val;
	printf ("horizontal resolution: %d\n", img.infohead.vres);
	
	// number of colors on the palette
	n = read(fd, &val, 4);
	img.infohead.ncolors = val;
	printf ("number of colors on the palette: %d\n", img.infohead.ncolors);
	
	// important colors
	n = read(fd, &val, 4);
	img.infohead.nimpcolors = val;
	printf ("important colors: %d\n", img.infohead.nimpcolors);
	
	// allocating memory dynamically
	img.pixel = malloc(img.infohead.height * sizeof(int *));
	
	int row, col, c, colors;
	// bits per pixel
	if (img.infohead.bitspp == 24) colors = 3; else colors = 4;
	
	// padding size
	int padding;
	padding = (img.infohead.bmp_bytesz - img.infohead.height*img.infohead.width*colors)/img.infohead.height;
	printf ("padding: %d\n", padding);
	
	for (row = 0; row < img.infohead.height; row++)
	{
		img.pixel[row] = malloc(img.infohead.width * sizeof(int *));
	}
	
	for (row = 0; row < img.infohead.height; row++)
		for (col = 0; col < img.infohead.width; col++)
		{
			img.pixel[row][col] = malloc(colors * sizeof(int *));
		}
	
	// reading data
	off_t pos = lseek(fd, img.head.bmp_offset, SEEK_SET);
	
	for (row = img.infohead.height-1; row >= 0; row--)
		for (col = 0; col < img.infohead.width; col++)
			for (c = 0; c < colors; c++)
			{
				img.pixel[row][col][c] = (rand () % 255) + 0;
			}
	
	// write the new file
	FILE *fp2;
	fp2 = fopen(argv[2], "w");
	
	ssize_t nn;
	//nn = write(fd2, &img, img.head.bmp_offset-1);
	
	fwrite(&img, img.head.bmp_offset, 1, fp2);
	
	for (row = 0; row < img.infohead.height; row++)
		for (col = 0; col < img.infohead.width; col++)
			for (c = 0; c < colors; c++)
			{
				printf ("img.pixel[%d][%d][%d]: %d\n", row, col, c, img.pixel[row][col][c]);
				
			}
	
	close(fd);
	fclose(fp2);
	
	exit(EXIT_SUCCESS);
}

The compiler aligns BITMAPHEADER at a 4-byte boundary. Since MAGIC occupies only 2 bytes, the compiler (when laying out the image structure) inserts 2 bytes of padding between magic and head .

thank you nezachem.
so, is there anyway it can be done? i mean without setting each and every byte individually.??

i put all the header component in one structure. but still the same :(
what i don't understand is, it works as i expected when it reads from a bitmap file. but not when writes.

typedef struct bmpfile_header {
	uint8_t magic1;
	uint8_t magic2;
	uint32_t filesz;
	uint16_t creator1;
	uint16_t creator2;
	uint32_t bmp_offset;
	uint32_t header_sz;
	int32_t width;
	int32_t height;
	uint16_t nplanes;
	uint16_t bitspp;
	uint32_t compress_type;
	uint32_t bmp_bytesz;
	int32_t hres;
	int32_t vres;
	uint32_t ncolors;
	uint32_t nimpcolors;
} BITMAPHEADER;

i put all the header component in one structure. but still the same :(

typedef struct bmpfile_header {
	uint8_t magic1;
	uint8_t magic2;
	uint32_t filesz;
...
} BITMAPHEADER;

Of course. filesz is still naturally aligned at 4 bytes, which requires padding.

what i don't understand is, it works as i expected when it reads from a bitmap file. but not when writes.

You (correctly) read data very carefully, field by field. You shall write the same way you read.
It is very tempting to avoid padding issues with pragma pack (or __attribute__(align) , depending on a compiler). The result will be highly nonnportable, with the whole spectrum of problems from build failures to runtime faults.

Thanks again nezachem. i had no idea what was happening. however, i tried reading the whole header at once ( not field by field ). it didn't work. now i understand why. :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.