Ciprian Popescu
Ciprian Popescu

Reputation: 3

Writing bitmap in C

This is my code for a bitmap image but it dosen't work and I have no idea why. I previously did something the same but I was reading an original bitmap and I had only to change its colors. The code was exactly the same thought and it did work that time but for reading an image from 0 it seems it didn't work. I searched a lot on the internet for answers and i think maybe it's a problem with data from headers or something about padding. Can you help me, please?

Header:

#pragma pack(1)

struct bmp_fileheader
{
unsigned char  fileMarker1; /* 'B' */
unsigned char  fileMarker2; /* 'M' */
unsigned int   bfSize; /* File's size */
unsigned short unused1;
unsigned short unused2;
unsigned int   imageDataOffset; /* Offset to the start of image data */
};

struct bmp_infoheader
{
unsigned int   biSize; /* Size of the info header - 40 bytes */
signed int     width; /* Width of the image */
signed int     height; /* Height of the image */
unsigned short planes;
unsigned short bitPix;
unsigned int   biCompression;
unsigned int   biSizeImage; /* Size of the image data */
int            biXPelsPerMeter;
int            biYPelsPerMeter;
unsigned int   biClrUsed;
unsigned int   biClrImportant;
};

#pragma pack()

Code:

#include <stdio.h>
#include <stdlib.h>
#include "bmp_header.h"

typedef struct {
unsigned char b;
unsigned char g;
unsigned char r;
}rgb;
int main() {

int i, j, k;
struct bmp_fileheader a;
struct bmp_infoheader b;
FILE * p = fopen("img.bmp", "wb");


a.fileMarker1 = 'B';
a.fileMarker2 = 'M';
a.unused1=0;
a.unused2=0;
a.bfSize = 54+3*40*40;
a.imageDataOffset=54;


b.biSize = 40;
b.width = 40;
b.width = 40;
b.planes = 1;
b.bitPix = 24;
b.biCompression = 0;
b.biSizeImage = 4*40*40;
b.biXPelsPerMeter = 0;
b.biYPelsPerMeter = 0;
b.biClrUsed = 0;
b.biClrImportant = 0;

rgb matrix[40][40];

for (i = 0; i < 10; i++) {
    for (j = 0; j < 40; j++) {
        matrix[i][j].b = 255;
        matrix[i][j].g = 255;
        matrix[i][j].r = 255;
    }
}

for (i = 10; i < 30; i++) {
    for (j = 0; j < 40; j++) {
        if (j < 10 || j > 29) {
            matrix[i][j].b = 255;
            matrix[i][j].g = 255;
            matrix[i][j].r = 255;
        } else {
            matrix[i][j].b = 255;
            matrix[i][j].g = 255;
            matrix[i][j].r = 0;
        }
    }
}

for (i = 30; i < 40; i++) {
    for (j = 0; j < 40; j++) {
        matrix[i][j].b = 255;
        matrix[i][j].g = 255;
        matrix[i][j].r = 255;
    }
}

fwrite( & a, sizeof(a), 1, p);
fwrite( & b, sizeof(b), 1, p);

int t = (4 - (40 * 3)%4)%4;//padding equation found on the internet
for(i = 0; i < 40; i++){
    for(j = 0; j < 40; j++)
        fwrite(&matrix[i][j], sizeof(matrix[i][j]), 1, p);

    for(k = 0; k < t; k++){
        putc(0,p); //padding
    }

}
fclose(p);
}

Upvotes: 0

Views: 91

Answers (1)

Paul Ogilvie
Paul Ogilvie

Reputation: 25266

The scanline size is calculated as:

#define WIDTHBYTES(bits)    (((bits) + 31) / 32 * 4)

The biSizeImage field is computed as:

b.biSizeImage= WIDTHBYTES(xRes*24) * yRes;

The 24 is the number of bits per pixel.

You also set b.width twice. The second one should be height.


Also the infoheader fields must be calcualed as (adapt to your struct naming):

fheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER) + 0/*no palette for 24 bits color*/;
fheader.bfSize = fheader.bfOffBits + iheader.biSizeImage;

Upvotes: 1

Related Questions