Reading and writing BMP files in C memory error - c

I am attempting to write a program to invert the color of an image. My problem is when I try to read from the DIB header in my BMP file.
When I try to get the file header size and use fread(dib.fileheader, 4,1,fp); . I get an error that says "The memory could not be written". I have attached it for further clarification.
Here is my code:
#include <stdio.h>
#include <string.h>
struct BMP {
char filetype[2]; // must be BM, must check if BM
unsigned int filesize;
short reserved1;
short reserved2;
unsigned int dataoffset;
};
struct DIB {
unsigned int fileheader;
unsigned int headersize;
int width;
int height;
short planes;
short bitsperpixel; /* we only support the value 24 here */
unsigned int compression; /* we do not support compression */
unsigned int bitmapsize;
int horizontalres;
int verticalres;
unsigned int numcolors;
unsigned int importantcolors
};
struct pixel {
int val;
char * def;
struct listitem * next;
};
void invertImage(char fileName[]){
struct BMP bmp;
struct DIB dib;
FILE *fp = fopen(fileName, "rb");
//FileType
fread(bmp.filetype, 1,2,fp);
printf("Value is %c\n", bmp.filetype[1]);
//Check if file format is BM
if(bmp.filetype[0] != 'B' && bmp.filetype[1] !='M'){
printf("Wrong format");
}
//Size of the file in bytes
fread(bmp.filesize, 4,1,fp);
printf("Value is %d\n", bmp.filesize);
//Go to dataoffset
fseek(fp,10,SEEK_CUR);
fread(bmp.dataoffset, 4,1,fp);
printf("Offset is %d\n", bmp.dataoffset);
fread(dib.fileheader, 4,1,fp);
printf("File header is %d bytes\n", dib.fileheader);
fclose(fp);
}
int main(int argc, char *argv[] ){
printf("Program name %s\n", argv[0]);
if( strcmp(argv[1],"-invert") == 0) {
printf("Invert\n");
printf("File name is %s\n", argv[2] );
invertImage(argv[2]);
}
else {
printf("Greyscale\n");
//greyScaleImage();
}
return 0;
}
Also here is the output to my program.

fread expects a pointer to memory to write the file contents. So you need to give it the address of dib.fileheader
fread( &dib.fileheader, sizeof(dib.fileheader),1,fp );
printf("File header is %d bytes\n", dib.fileheader);
It's complaining because it's interpreting whatever is in dib.fileheader as the address to write to, which may or may not be valid for your program.
Note that the following is ok as it stands because bmp.filetype is already a pointer to char - it's a char[]
fread(bmp.filetype, 1,2,fp);
printf("Value is %c\n", bmp.filetype[1]);
To make it a bit more general, you could write
fread(bmp.filetype, sizeof(bmp.filetype), 1, fp);
printf("Value is %c\n", bmp.filetype[1]);

I tried to compile your code. You must make some change in your code.
fread(bmp.filesize, 4,1,fp); --- > fread(&bmp.filesize, 4,1,fp);
fread(bmp.dataoffset, 4,1,fp); --- > fread(&bmp.dataoffset, 4,1,fp);
fread(dib.fileheader, 4,1,fp); --- > fread(&dib.fileheader, 4,1,fp);
declare the function : void invertImage(char fileName[]);

Related

Cutting amplitude of a signal from .wav file

I'm currently working on a C program that is opening a .wav file , copy the .wav header in the output file and after the header it adds the processed data that is obtained from the input file. The process consist of multiplying each sample with 0.5 in order to reduce the amplitude of the signal.
Here is my code:
program.c
#include <stdio.h>
#include <stdlib.h>
struct header_file
{
char chunk_id[4];
int chunk_size;
char format[4];
char subchunk1_id[4];
int subchunk1_size;
short int audio_format;
short int num_channels;
int sample_rate;
int byte_rate;
short int block_align;
short int bits_per_sample;
char subchunk2_id[4];
int subchunk2_size;
};
struct header_file header;
int main()
{
FILE * inputfile = fopen("maneskin.wav","rb"); // deschidere fisier .wav, modul de citire
FILE * outputfile = fopen("Output.wav","wb"); // creeaza fisierul .wav, modul de scriere
int BUFFSIZE = 10000; // lungimea buffer-ului
int count = 0; // numara cate frame-uri sunt in fisier
short int inputBuffer[BUFFSIZE];
short int outputBuffer[BUFFSIZE];
/* header_p meta = (header_p)malloc(sizeof(header)); */
int nb; // numarul de bytes returnati
int temp;
if (inputfile)
{
fread(&header, sizeof(header),1, inputfile);
fwrite(&header,sizeof(header),1, outputfile);
short int ch2[BUFFSIZE];
for(int i=0; i<BUFFSIZE; i++) \
ch2[i] = 1;
while (!feof(inputfile))//cat timp se citeste fisierul
{
for(int i=0; i<BUFFSIZE && !feof(inputfile); i++)
fread((char*)&inputBuffer[i],sizeof(short int),1, inputfile); // citirea datelor
count++;// incrementarea numarului de frame-uri
for(int z=0; z<BUFFSIZE; z++){
outputBuffer[z]=0.5*inputBuffer[z];
}
for(int k=0; k<BUFFSIZE; k++)
{
fwrite((char*)&outputBuffer[k], sizeof(short int), 1, outputfile);// scriere in fisier
}
}
printf("Numarul de cadre din fisierul wav:%d\n", count);
}
return 0;
}
The problemm that I have is when I'm trying to open the output file with VLC or any other media player it doens't open and gives me an error. I think it might be a problem with the header writing in the output file but I'm not sure. I tried importing the file as raw data in Audacity and played the audio file just fine but if I'm trying to import it as wav file it doesn't work.What could be the problem?
I don't know if this is your only problem, but it's definitely a problem...
In C, generally when you define a structure, the members of that structure do not sit right next to each other in memory. The compiler arranges them to fall on boundaries that are comfortable for the processor, usually in increments of the word size of the processor. So an element of type char surrounded by two ints, is not nestled right between them, but actually has perhaps 7 bytes of space between it and the next element.
This is done for execution efficiency, and usually makes sense.
But in situations like this, you want to pack the structure elements tightly together and for this there is a standard way to tell the compiler that this is what you want:
/* pack in 1 byte increments */
#pragma pack(1)
struct header_file
{
char chunk_id[4];
int chunk_size;
char format[4];
char subchunk1_id[4];
int subchunk1_size;
short int audio_format;
short int num_channels;
int sample_rate;
int byte_rate;
short int block_align;
short int bits_per_sample;
char subchunk2_id[4];
int subchunk2_size;
};
/* reset to default */
#pragma pack()
I would also suggest using size-specific types, for example uint16_t instead of short int, because you do not know the size of int on every platform where your code might be compiled.
In your code, try printing the sizeof header to see if it's what you expect, eg:
printf("sizeof(header)=%d\n", sizeof(header));
If the number does not match what it should be for a WAV header then you have got a problem with the size of one or more elements, or a problem with the packing.

c - Segmentation fault when using global struct variable

This is in a program meant to work with ppm image files.
I'm getting a segmentation fault when trying to read an image from a file and assigning that image to my global struct image.
These are the relevant parts of my ppmIO.c file:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <ppmIO.h>
struct Image *instance;
void ImageRead(char *filename)
{
printf("hi 0!");
int width, height, num, size;
//unsigned char *p;
//Image *image = (Image *) malloc(sizeof(Image));
FILE *fp = fopen(filename, "r");
//if (!image) die("cannot allocate memory for new image");
if (!fp) die("cannot open file for reading");
readPPMHeader(fp, &width, &height);
size = width * height * 3;
printf("hi!");
//instance->data = (unsigned char *) malloc(size);
printf("hi 2!");
instance->width = width;
printf("hi 3!");
instance->height = height;
printf("hi 4!");
if (!instance->data) die("cannot allocate memory for new image");
num = fread((void *) instance->data, 1, (size_t) size, fp);
if (num != size) die("cannot read image data from file");
fclose(fp);
}
This is my ppmIO.h file:
#ifndef PPMIO_H
#define PPMIO_H
struct Image
{
int width;
int height;
unsigned char *data;
};
extern struct Image *instance;
//extern Image *ImageCreate(int width, int height);
//extern void ImageClear(struct Image *image, unsigned char red, unsigned char green, unsigned char blue);
extern void ImageRead(char *filename);
extern void ImageWrite(char *filename);
extern void ImageSetPixel(int x, int y, int chan, unsigned char val);
extern unsigned char ImageGetPixel(int x, int y, int chan);
#endif /* PPMIO_H */
And this is the segmentation fault that GDB reports:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400fff in ImageRead (filename=0x7fffffffdc32 "nika.ppm")
at ppmIO.c:126
126 instance->width = width;
I think there is a problem with how I'm trying to use the Image *instance... but I really have no real clue what is causing this mess. :(
You're getting this error as you have not allocated any memory for instance. Before you try and use any member of instance (i.e. width or data) you must allocate memory (from inside a function), i.e:
instance = malloc(sizeof *instance);
You should not cast the return value of instance (See: this), and there is no need to specify the type since the compiler already knows. You can't allocate the memory when you declare the variable as static initializations must be to constant values (See: this) (the return value of a function is not constant).
You will also need to allocate memory for the instance->data part of the structure, based on the size you read from the file.

Segmenatation fault in fread

I encounter segmenatation fault in fread while I am reading 1500 or more ethernet data packets. Here "test2" is the binary file whose file size is 22.6MB. 1132 is the number of useful data points in each packet and 142 points carries header information hence it is skipped.
here is the main program:
void main()
{
int count;
FILE *fp;
long file_size;
unsigned char rawdata[1132];
fp=fopen("test2","rb");
if(fp==-1)
{
printf("unsucessful");
exit(0);
}
long int before=ftell(fp);
fseek(fp,0,SEEK_END);
file_size=ftell(fp);
rewind(fp);
long int after=ftell(fp);
//skip first 142 bytes(header information)since its not required
fseek(fp,142,SEEK_SET);
long int s=ftell(fp);
int length_of_fft=4096;
int buffer_width=128;
int buffer_depth=1024;
int k,aa,payloadindex=0,l=0,j,a;
int no_of_data_pts_to_be_read=1132;
int no_of_ethernet_pkts_to_be_read=1500;
int q=no_of_ethernet_pkts_to_be_read*buffer_depth;
unsigned char payload[q];
unsigned int payloadint[q];
int no_of_data_pks_read=0;
int reading_for_first_time=1;
unsigned char data_from_file[no_of_ethernet_pkts_to_be_read][buffer_depth];
int addr_offset_in_inarray=0;
int udp_counter_values[no_of_ethernet_pkts_to_be_read];
unsigned int rawdataint[1132];
long int size;
count=0;
for(a=0; a<no_of_ethernet_pkts_to_be_read; a++)
{
int p=fread(rawdata,1 ,sizeof(rawdata), fp);
count=p;
//----------- to check if all data points have been read, i,e the pointer must be at a position wich is a multiple of 1132 which is[(1274-142=1132)*(a+1)],( since 142 bytes were skipped in the beginning )
printf("\n\n %d\t Start=%x\t\t Stop=%x\t Count=%d\t Address=%x",no_of_data_pks_read, rawdata[0], rawdata[sizeof(rawdata)-1],count,
ftello(fp));
if(count==no_of_data_pts_to_be_read)
{
printf("\nNumber of data points read in packet %d (of %d) is %d ",no_of_data_pks_read, no_of_ethernet_pkts_to_be_read, count);
reading_for_first_time=0;
//--------------converting char array rawdata into int array and then call udp
for(i=0;i<1132;i++)
rawdataint[i]=rawdata[i]-'\0';
udp_counter_values[a]=check_UDPpacketCount(&addr_offset_in_inarray, &rawdataint,10,no_of_data_pks_read,1132);
// printf("\n--------udp:: %d ",udp_counter_values[a]);
//-----------------create new mat and compute payload and put the contents of array rawwdata into the respective row of the new matrix
int k,t,w,time=0;
for(k=0,l=addr_offset_in_inarray;l<sizeof(rawdata),k<1024;k++,l++)
{
data_from_file[no_of_data_pks_read][k]=rawdata[l];
// printf("\n datafile:%d",data_from_file[no_of_data_pks_read][k]);
}
for(t=0;t<1024;t++)
{
payload[payloadindex++]=data_from_file[no_of_data_pks_read][t];
}
no_of_data_pks_read++;
}
else
{
count=0;
printf("\n not equal, exiting ");
exit(0);
}
}
//------convert payload to int array and send to data extraction function
for(i=0;i<sizeof(payload);i++)
{
payloadint[i]=payload[i]-'\0';
}
printf(" sizepayload: %d", sizeof(payload));
size=sizeof(payload);
data_extraction(size, payloadint,buffer_depth,buffer_width,length_of_fft);
printf("\n s:%d",file_size);
printf("\n ft:%x",ftell(fp));
printf("\n****----end----****");
fclose(fp);
}
As it has already been mentioned that you might be using up all your stack, try making all statically allocated variables global or use dynamic allocation. That should improve your situation.
fopen() returns a NULL pointer upon error, not -1.
If fopen has failed, you go on and do file operations with a NULL pointer.
This is wrong:
fp=fopen("test2","rb");
if(fp==-1)
{
printf("unsucessful");
exit(0);
}
It should be (and watch my use of whitespace)
fp = fopen("test2", "rb");
if (fp == NULL) {
printf("Could not open test2\n"); /* A meaningful error message */
exit(0);
}
There are few errors in your code.
1.you need check fp==NULL instead of fp==-1 when ever fopen() fails it returns NULL
2.in for loop you are using comma ,I guessing that is AND.
for(k=0,l=addr_offset_in_inarray;l<sizeof(rawdata),k<1024;k++,l++)
^
for(k=0,l=addr_offset_in_inarray;((l<sizeof(rawdata) )&& (k<1024));k++,l++)
^^
3.did not declared variable i.
warnings need to remove
You did not used many variables even though they are initialized with values
type mismatch while printing.
MODIFIED CODE
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void main()
{
int count,i;
FILE *fp;
long file_size;
unsigned char rawdata[1132];
fp=fopen("test2","rb");
if(fp==NULL)
{
printf("unsucessful");
exit(0);
}
long int before=ftell(fp);
fseek(fp,0,SEEK_END);
file_size=ftell(fp);
rewind(fp);
long int after=ftell(fp);
//skip first 142 bytes(header information)since its not required
fseek(fp,142,SEEK_SET);
long int s=ftell(fp);
int length_of_fft=4096;
int buffer_width=128;
int buffer_depth=1024;
int k,aa,payloadindex=0,l=0,j,a;
int no_of_data_pts_to_be_read=1132;
int no_of_ethernet_pkts_to_be_read=1500;
int q=no_of_ethernet_pkts_to_be_read*buffer_depth;
unsigned char payload[q];
unsigned int payloadint[q];
int no_of_data_pks_read=0;
int reading_for_first_time=1;
unsigned char data_from_file[no_of_ethernet_pkts_to_be_read][buffer_depth];
int addr_offset_in_inarray=0;
int udp_counter_values[no_of_ethernet_pkts_to_be_read];
unsigned int rawdataint[1132];
long int size;
count=0;
for(a=0; a<no_of_ethernet_pkts_to_be_read; a++)
{
int p=fread(rawdata,1 ,sizeof(rawdata), fp);
count=p;
//----------- to check if all data points have been read, i,e the pointer must be at a position wich is a multiple of 1132 which is[(1274-142=1132)*(a+1)],( since 142 bytes were skipped in the beginning )
printf("\n\n %d\t Start=%x\t\t Stop=%x\t Count=%d\t Address=%x",no_of_data_pks_read, rawdata[0], rawdata[sizeof(rawdata)-1],count,(unsigned int) ftell(fp));
if(count==no_of_data_pts_to_be_read)
{
printf("\nNumber of data points read in packet %d (of %d) is %d ",no_of_data_pks_read, no_of_ethernet_pkts_to_be_read, count);
reading_for_first_time=0;
//--------------converting char array rawdata into int array and then call udp
for(i=0;i<1132;i++)
rawdataint[i]=rawdata[i]-'\0';
udp_counter_values[a]=check_UDPpacketCount(&addr_offset_in_inarray, &rawdataint,10,no_of_data_pks_read,1132);
// printf("\n--------udp:: %d ",udp_counter_values[a]);
//-----------------create new mat and compute payload and put the contents of array rawwdata into the respective row of the new matrix
int k,t,w,time=0;
for(k=0,l=addr_offset_in_inarray;(l<sizeof(rawdata)|| k<1024);k++,l++)
{
data_from_file[no_of_data_pks_read][k]=rawdata[l];
// printf("\n datafile:%d",data_from_file[no_of_data_pks_read][k]);
}
for(t=0;t<1024;t++)
{
payload[payloadindex++]=data_from_file[no_of_data_pks_read][t];
}
no_of_data_pks_read++;
}
else
{
count=0;
printf("\n not equal, exiting ");
exit(0);
}
}
//------convert payload to int array and send to data extraction function
for(i=0;i<sizeof(payload);i++)
{
payloadint[i]=payload[i]-'\0';
}
printf(" sizepayload: %ld", sizeof(payload));
size=sizeof(payload);
data_extraction(size, payloadint,buffer_depth,buffer_width,length_of_fft);
printf("\n s:%ld",file_size);
printf("\n ft:%x",(unsigned int)ftell(fp));
printf("\n****----end----****");
fclose(fp);
}
If you're on a Unix-like platform, you could replace the fopen, fread, fseek calls with the raw system-calls just to see what happens.
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
int fd = open("test2", O_RDONLY);
if (fd < 0) {
printf("Could not open test2\n");
exit(0);
}
And then use read() instead of fread(), lseek() instead of fseek() ,etc.

I get segmentation fault reading infoheader on a BMP using fread. How do I fix this please?

This is got me pretty stuck, how do I fix this? I know I haven't got error checking, but they aren't required i'd guess since it's restricted to my desktop. It obveously can't be EOF. It's for the infoheader struct, fileheader works fine. Do i need to take a new line or something?
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
unsigned char fileMarker1; /* 'B' */
unsigned char fileMarker2; /* 'M' */
unsigned int bfSize;
unsigned short unused1;
unsigned short unused2;
unsigned int imageDataOffset; /* Offset to the start of image data */
}FILEHEADER;
typedef struct
{
unsigned int biSize;
int width; /* Width of the image */
int height; /* Height of the image */
unsigned short planes;
unsigned short bitPix;
unsigned int biCompression;
unsigned int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
unsigned int biClrUsed;
unsigned int biClrImportant;
}INFOHEADER;
typedef struct
{
unsigned char b; /* Blue value */
unsigned char g; /* Green value */
unsigned char r; /* Red value */
}IMAGECOMPONENT;
int fileheadfunc(FILE *image);
int infoheadfunc(FILE *image);
int main( int argc, char *argv[] )
{
char *filename; /* *threshholdInput = argv[2]; */
FILE *image;
int filehead, infohead;
filename = argv[1];
/* int threshhold = atoi(threshholdInput); */
if (argc != 2)
{
printf(" Incorrect Number Of Command Line Arguments\n");
return(0);
}
image = fopen( filename, "r");
if (image == NULL)
{
fprintf(stderr, "Error, cannot find file %s\n", filename);
exit(1);
}
filehead = fileheadfunc(image);
infohead = infoheadfunc(image);
fclose(image);
return(0);
}
int fileheadfunc(FILE *image)
{
FILEHEADER *header;
long pos;
fseek (image , 0 , SEEK_SET);
fread( (unsigned char*)header, sizeof(FILEHEADER), 1, image );
if ( (*header).fileMarker1 != 'B' || (*header).fileMarker2 != 'M' )
{
fprintf(stderr, "Incorrect file format");
exit(1);
}
printf("This is a bitmap!\n");
pos = ftell(image);
printf("%ld\n", pos);
printf("%zu\n", sizeof(FILEHEADER));
return(0);
}
int infoheadfunc(FILE *image)
{
INFOHEADER *iheader;
fseek (image, 0, SEEK_CUR );
fread( (unsigned int*)iheader, sizeof(INFOHEADER), 1, image );
printf("Width: %i\n", (*iheader).width);
printf("Height: %i\n", (*iheader).height);
return(0);
}
You're not actually allocating any storage for the BMP header data structures, e.g. you need to change this:
int fileheadfunc(FILE *image)
{
FILEHEADER *header;
long pos;
fseek(image, 0, SEEK_SET);
fread((unsigned char*)header, sizeof(FILEHEADER), 1, image);
...
to this:
int fileheadfunc(FILE *image)
{
FILEHEADER header; // <<<
long pos;
fseek(image, 0, SEEK_SET);
fread(&header, sizeof(FILEHEADER), 1, image); // <<<
...
Also, as previously noted in one of the comments above, you need #pragma pack(1) (or equivalent if you're not using gcc or a gcc-compatible compiler) prior to your struct definitions to eliminate unwanted padding. (NB: use #pragma pack() after your struct definitions to restore normal struct padding/alignment.)
There are two problems with the code:
Alignment
For performance reasons the compiler will, unless instructed to do otherwise, arrange struct fields on its "natural boundaries", effectively leaving uninitialised gaps between byte-size fields. Add
#pragma pack(1)
before the struct definitions and you should be fine. It's also easy to test: just print out the struct size without and with pragma pack in place, and you'll see the difference.
Allocation
As Paul R already said, you should allocate space for the headers, not just provide a pointer to the structures. The fact that fileheadfunc works is a coincidence, there just wasn't anything in the way that got smashed when data got written outside of the allocated space.
A last one, just for prevention sake: should you ever want to return the read structures to the calling program, do not just return a pointer to the structure allocated in the function as that will cause problems similat to the unallocated variables you have now. Allocate them in the calling function, and pass a pointer to that variable to the header read functions.
EDIT clarification regarding the last point:
DON'T
FILEHEADER * fileheadfunc(FILE *image)
{
FILEHEADER header;
...
return &header; // returns an address on the function stack that will
// disappear once you return
}
DO
int fileheadfunc(FILE *image, FILEHEADER *header)
{
...
}
which will be called like this
...
FILEHEADER header;
returnvalue = fileheaderfunc(imagefile,&header);
EDIT2: just noticed that the way you read the DIB header is not correct. There are several variations of that header, with different sizes. So after reading the file header you first need to read 4 bytes into an unsigned int and based on the value read select the correct DIB header structure to use (don't forget you already read its first field!) or tell the user you encountered an unsupported file format.

Problems with BMP{FileHeader, InfoHeader} structures

I want to load a bmp file into memory in C. I've found many different types of BmpFileHeader and BmpInfoHeader structures. The last one that I've taken it from msdn.microsoft.com but it still does not read properly from binary file. With test file lena
Image Size: -1076791624
Memory could not be allocated
What's the point I am missing? Thanks.
#include <stdio.h>
#include <stdlib.h>
typedef struct tagBITMAPFILEHEADER {
unsigned short bfType;
unsigned int bfSize;
short bfReserved1;
short bfReserved2;
unsigned int bfOffBits;
} BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER {
unsigned int biSize;
int biWidth;
int biHeight;
short biPlanes;
short biBitCount;
unsigned int biCompression;
unsigned int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
unsigned int biClrUsed;
unsigned int biClrImportant;
} BITMAPINFOHEADER;
int main(int argc, char *argv[])
{
if(argc != 2)
{
printf("Usage: %s input.bmp\n", argv[0]);
exit(-1);
}
FILE *filePtr;
BITMAPFILEHEADER bitmapFileHeader;
BITMAPINFOHEADER bitmapInfoHeader;
unsigned char *bitmapImage;
int imageIdx=0;
unsigned char tempRGB;
filePtr = fopen(argv[1],"rb");
if (filePtr == NULL)
{
printf("File could not opened\n");
exit(-1);
}
//read the bitmap file header
fread(&bitmapFileHeader, sizeof(bitmapFileHeader), 1, filePtr);
if (bitmapFileHeader.bfType !=0x4D42)
{
fclose(filePtr);
printf("Not a bmp file\n");
exit(-1);
}
fseek(filePtr, bitmapFileHeader.bfOffBits, SEEK_SET);
bitmapImage = (unsigned char*)malloc(sizeof(unsigned char)*bitmapInfoHeader.biSizeImage);
printf("Image Size: %d\n", bitmapInfoHeader.biSizeImage);
if (!bitmapImage)
{
free(bitmapImage);
fclose(filePtr);
printf("Memory could not be allocated\n");
exit(-1);
}
//swap the r and b values to get RGB (bitmap is BGR)
for (imageIdx = 0; imageIdx < bitmapInfoHeader.biSizeImage; imageIdx+=3)
{
tempRGB = bitmapImage[imageIdx];
bitmapImage[imageIdx] = bitmapImage[imageIdx + 2];
bitmapImage[imageIdx + 2] = tempRGB;
}
int i;
for(i = 0; i < bitmapInfoHeader.biSizeImage; i+=3){
printf("R: %c G: %c B: %c\n", bitmapImage[i], bitmapImage[i + 1], bitmapImage[i + 2]);
}
fclose(filePtr);
return 0;
}
The first thing that I would do is to find an authoritative statement on the byte layout of these headers and then, assuming that you want to continue to use the structs that you have defined, add some asserts on the field offsets, for example:
assert(offsetof(BITMAPFILEHEADER, bfType) == 0); // or whatever
assert(offsetof(BITMAPFILEHEADER, bfSize) == 2); // or whatever
assert(offsetof(BITMAPFILEHEADER, bfOffBits) == 10); // or whatever
etc.
Chances are that your use of unsigned int, short, etc plus your compiler options (especially structure packing) might mean that your struct fields do not match the actual BMP file data (in offset, and maybe in length).
Your bitmapInfoHeader is uninitialized!
That is, you read the bitmapFileHeader, and then set the file pointer to where the actual bitmap data should be. But you didn't read the bitmapInfoHeader, which contains all the information about the bitmap (dimensions, bpp and etc.)
P.S.
Next time please try do debug your code befure posting the question.
There exist several versions of the BMP file format and most of them differ in the size of the headers. If you want to be able to read all valid BMP files, you'll need to support them all. The lena image seems to be a Windows V3 version.
There's a good description of the different versions in Wikipedia.
Furthermore, I don't see no endianness handling in your code. If you're machine isn't little endian, it will not work.
Finally, the alignment of the struct members is a problem. Your compiler will most likely align the bfSize member at offset 4 but it should be at offset 2. (See the Wikipedia article for a solution.)

Resources