I've created program in C witch reads .bmp file and apply on it blur effect. Algorithm is simple. Read file, separate each colour channel and do channel convolution with given matrix.My image is 24 bits per pixel.Here is result of my program: http://imgur.com/lTNvPrX while this is original http://imgur.com/IVGHCQk . I think I'm making error when accessing data in separate channels, but I have no idea how I can do this. I know that rows and cols contain number of pixels not bytes but when I multiply this by 3 I get segmentation-fault on channelBlur[y*cols+x] = toWrite. I'm compile this with gcc -m32 ... Below are structures and code used to read file and process image:
typedef struct __attribute__((__packed__))
{
WORD fType;
DWORD byteSize;
WORD reserved1;
WORD reserved2;
DWORD offsetToImage;
}BITMAPHEADER;
typedef struct __attribute__((__packed__))
{
DWORD structSize;
LONG width;
LONG height;
WORD planes;
WORD bitsPerPix;
DWORD compression;
DWORD imgSizeBytes;
LONG pixPerMeterX;
LONG pixPerMeterY;
DWORD colorUsd;
DWORD colorImp;
}BITMAPINFOHEADER;
typedef unsigned char* IMAGE;
Load function:
IMAGE loadImg(const char* filename, BITMAPINFOHEADER* infoHeader)
{
FILE* fImg;
BITMAPHEADER header;
IMAGE bitmap;
fImg = fopen(filename,"rb");
if(fImg == NULL)
return NULL;
fread(&header,sizeof(BITMAPHEADER),1,fImg);
if(header.fType != 0x4D42)
{
fclose(fImg);
return NULL;
}
fread(infoHeader,sizeof(BITMAPINFOHEADER),1,fImg);
fseek(fImg,header.offsetToImage, SEEK_SET);
bitmap = (unsigned char*)malloc(infoHeader->imgSizeBytes);
fread(bitmap,infoHeader->imgSizeBytes,1,fImg);
fclose(fImg);
return bitmap;
}
And naive separate channel and combine function:
void separateChannels(const IMAGE src,unsigned int nPixels, unsigned char* red, unsigned char* green,unsigned char* blue)
{
PIXEL pix;
unsigned int i;
for(i=0;i<nPixels;i=i+3)
{
blue[i] = src[i];
green[i] = src[i+1];
red[i] = src[i+2];
}
}
IMAGE combineChannels(unsigned char* red, unsigned char* green,unsigned char* blue, unsigned int nPixels, BITMAPINFOHEADER infoHeader)
{
IMAGE image = createNewImage(infoHeader);
unsigned int i;
for(i=0;i<nPixels;i=i+3)
{
image[i] = blue[i];
image[i+1] = green[i];
image[i+2] = red[i];
}
return image;
}
createNewImage works properly
Allocating channels:
unsigned char* redBlur = (unsigned char*)malloc(infoHeader.imgSizeBytes);
unsigned char* greenBlur = (unsigned char*)malloc(infoHeader.imgSizeBytes);
unsigned char* blueBlur = (unsigned char*)malloc(infoHeader.imgSizeBytes);
Here is the problematic function:
void applyFilterOnChannel(const unsigned char* channel,unsigned char* channelBlur ,unsigned int cols,unsigned int rows, const float* filter)
{
unsigned int x;
unsigned int y;
for(y=0;y<cols;++y)
{
for(x=0;x<rows;++x)
{
float value = 0;
unsigned int filterX;
unsigned int filterY;
for(filterY=0;filterY<filterSize/2;++filterY)
{
for(filterX=0;filterX<filterSize/2;++filterX)
{
int pixelPosY = min(max(y+filterY,0),(int)rows-1);
int pixelPosX = min(max(x+filterX,0),(int)cols-1);
float pixelVal = (float)channel[pixelPosY*cols+pixelPosX];
float filterVal = filter[(filterY+filterSize/2)*filterSize+filterX+filterSize/2];
value += pixelVal*filterVal;
}
}
unsigned char toWrite = (unsigned char)value;
channelBlur[y*cols+x] = toWrite;
}
}
}
There are several problems. Some might apply in your case, some might not (depending on specific image and processor architecture):
First, separateChannel and combineChannel don't work properly. You only access every third byte of the array. It should be (and similarly for combineChannel):
void separateChannels(const IMAGE src, unsigned int nPixels, unsigned char* red, unsigned char* green, unsigned char* blue)
{
unsigned int i, j;
for(i = 0, j = 0; i < nPixels; i++, j = j + 3)
{
blue[i] = src[j];
green[i] = src[j + 1];
red[i] = src[j + 2];
}
}
The allocated arrays for the three channels can be accordingly smaller.
Next, you seem to process a BGR file, i.e. every pixel requires 3 bytes. Part of the BMP standard is that the size of every row is rounded to a multiple of 4 bytes so that each pixel rows starts on a double word boundary.
Next, I assume that you run the code on a little endian processor architecture. Otherwise, your code for reading the BMP header is invalid.
Finally, the BMP format covers a wide range of image types but your code only handles 24-bit per pixel, top to bottom BGR files.
Related
I still cannot access the color bits from a bitmap image. The problem is that, after saving the bitmap's content into a buffer, I do not know:
Where to start the loop (If i start from 0 i think it will erase the headers)?
How to access the bytes and make the changes (transform a color from the BMP into a desired one from the output)?
And, how to insert the buffer into a new bitmap file?
All the images I want to modify have rows which are divisible by 4 (I have to insert 0 when a specific byte is padding) and 24 bits per pixel. Even few tips would be much appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "bmp_header.h"
int main(void)
{
FILE *f;
f = fopen("captcha.bmp","rb");
if ((f = fopen("captcha.bmp", "rb")) == NULL)
{
printf("Error opening file %s.\n", "captcha.bmp");
exit(1);
}
fread(&BMP_header,sizeof(BMP_header),1,f);
fread(&BMP_info_header,sizeof(BMP_info_header),1,f);
fseek(f,BMP_header.imageDataOffset,SEEK_SET);
int rows = (BMP_info_header.bitPix * BMP_info_header.width + 31 ) /32 * 4 ;
char *PixelArray =malloc( rows * abs(BMP_info_header.height)*sizeof(char));
int i;
for( i =sizeof(BMP_header)+sizeof(BMP_info_header); i<=(rows * abs(BMP_info_header.height))-2;i+=3)
{
PixelArray[i]=255; // just a random value to test if this makese any sense
PixelArray[i+1]=255;
PixelArray[i+2]=255;
}
return 0;
}
And, here is bmp_header.h's content:
#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 */
}BMP_header,BMP_header_out;
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;
}BMP_info_header,BMP_info_header_out;
#pragma pack()
Alright, I wrote some code to write out a completely black bitmap file with the original dimensions of the old bitmap file.
This will not work with all types of bitmaps. 16-color bitmaps, for instance, have a color palette after the info header that my program does not account for. The bits per pixel also needs to be divisible by 8. If those preconditions are met, as I believe they are in 24-bit bitmaps, then this program should work.
The main code here is in getNewImageData. We calculate the row size for the image with the same formula that Wikipedia uses - it calculates the required bits and then pads that to a multiple of four bytes and then converts bits to bytes. Then we set all of the pixel array memory to zero (mostly me being paranoid about leaving values in the pad bytes). Then we run along each row and edit each pixel. The innermost for loop corresponds to each pixel. One iteration through the middle for loop writes to one pixel.
You can obviously modify this code to read the pixel data into a malloced section of memory and then edit the pixel data in place before writing it back out. This sample code does not read the input pixel data and just writes out a black bitmap of the same dimensions as the input file.
Edit: I guess I should mention what you were doing wrong.
You called fopen twice, leaving an open file pointer hanging somewhere in memory.
rows should probably be renamed to rowSize since it's the size of a row of pixels in bytes
PixelArray is not being freed.
Your for loop starts from an offset (the size of the two headers) and then is bounded by the size of the pixel data. The for loop should start from 0 and go to the size of the pixel data (unless you are reading pixel data in as you do this... which you probably shouldn't do).
Your for loop tries to write to all of the pixel data at once and doesn't account for the fact that there is anywhere between 0 and 31 bits of padding on the end of each row of pixels (my program assumes the padding is only 0, 8, 16, or 24 bits).
Here is the code:
#include <stdio.h>
#include "bmp_header.h"
#include <stdlib.h>
int readBitmapHeaders(char* fileLocation, bmp_fileheader* fileheader, bmp_infoheader* infoheader)
{
FILE* f;
f = fopen(fileLocation, "rb");
if (!f)
{
printf("Error opening file %s.\n", fileLocation);
return 1;
}
fread(fileheader, sizeof(bmp_fileheader), 1, f);
fread(infoheader, sizeof(bmp_infoheader), 1, f);
fclose(f);
return 0;
}
int writeBitmap(char* fileName, bmp_fileheader* fileheader, bmp_infoheader* infoheader, char* pixelArray, size_t pixelArraySize)
{
FILE* out;
out = fopen(fileName, "wb");
if (!out)
{
printf("Error opening file %s.\n", fileName);
return 1;
}
fwrite(fileheader, sizeof(bmp_fileheader), 1, out);
fwrite(infoheader, sizeof(bmp_infoheader), 1, out);
fwrite(pixelArray, pixelArraySize, 1, out);
fclose(out);
return 0;
}
char* getNewImageData(bmp_infoheader* infoheader, size_t* imageSize)
{
//rowsize is padded to 4 bytes
size_t rowSize = (infoheader->bitPix * infoheader->width + 31) / 32 * 4;
size_t pixelArraySize = rowSize * abs(infoheader->height);
char* pixelArray = (char*)malloc(pixelArraySize);
if (!pixelArray)
{
return NULL;
}
memset(pixelArray, 0, pixelArraySize);
size_t bytesPerPixel = infoheader->bitPix / 8;
for (int i = 0; i < infoheader->height; i++)
{
for (int j = 0; j < infoheader->width; j++)
{
size_t offset = rowSize * i + bytesPerPixel * j;
for (size_t k = 0; k < bytesPerPixel; k++)
{
pixelArray[offset + k] = 0;
}
}
}
if (imageSize)
{
*imageSize = pixelArraySize;
}
return pixelArray;
}
int main()
{
char* fileLocation = "test.bmp";
bmp_fileheader header;
bmp_infoheader infoheader;
int readResult = readBitmapHeaders(fileLocation, &header, &infoheader);
if (readResult)
{
return readResult;
}
size_t pixelArraySize;
char* pixelArray = getNewImageData(&infoheader, &pixelArraySize);
if (!pixelArray)
{
printf("%s", "Failed to create the new image data. Exiting with fatal error.\n");
return 1;
}
char* outFile = "out.bmp";
int writeResult = writeBitmap(outFile, &header, &infoheader, pixelArray, pixelArraySize);
free(pixelArray);
return writeResult;
}
I changed the bitmap header file a little to typedef the structs and make life easier (at least for me):
#pragma once
#pragma pack(1)
typedef 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 */
} bmp_fileheader;
typedef 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;
} bmp_infoheader;
#pragma pack()
I'm trying to take a BMP file and read it in and then perform an operation on the pixels in it to change its color. My problem is that I am having trouble reading in the data from the file into the two BMP header structures. I'm able to read all the data into the first structure fine, but I get a seg fault when reading into the second. As you can see from the code, the first structure, FILEHEADER, is read to and contains all the correct data it should, but the second struc, BMPInfoHeader, is not being read to correctly. Why is this seg fault occuring?
#include <stdio.h>
#include <stdlib.h>
typedef struct
{ unsigned short int Type; /* Magic identifier */
unsigned int Size; /* File size in bytes */
unsigned short int Reserved1, Reserved2;
unsigned int Offset; /* Offset to data (in B) */
} FILEHEADER; /* 14 Bytes */
typedef struct
{ unsigned int Size; /* Header size in bytes */
int Width, Height; /* Width / Height of image */
unsigned short int Planes; /* Number of colour planes */
unsigned short int Bits; /* Bits per pixel */
unsigned int Compression; /* Compression type */
unsigned int ImageSize; /* Image size in bytes */
int xResolution, yResolution;/* Pixels per meter */
unsigned int Colors; /* Number of colors */
unsigned int ImportantColors;/* Important colors */
} BMPInfoHeader; /* 40 Bytes */
typedef struct
{ unsigned char r; /* Red */
unsigned char b; /* Blue */
unsigned char g; /* Green */
} IMAGE;
int main(int argc, char *argv[]) {
FILE *BMPFile;
FILEHEADER BMPFileHeader;
BMPInfoHeader *InfoHeader;
BMPFile=fopen(argv[1],"rb");
unsigned char *BMPimage;
if (BMPFile==NULL) {
printf("\n\nERROR: File not opened properly\n\n");
return -1;
}
fread(&BMPFileHeader,sizeof(unsigned char),14,BMPFile);
fseek(BMPFile,BMPFileHeader.Offset,SEEK_SET);
fread(InfoHeader,sizeof(unsigned char),40,BMPFile);
if (BMPFileHeader.Type != 0x4D42) {
printf("\n\nERROR with fread\n\n");
return -1;
}
return 0;
}
The problem is that the FILEHEADER you've defined is mis-aligned, so the compiler will insert padding between fields. The normal way to read a bmp header is to split off the 2-byte magic number and read it separately:
typedef struct
{
unsigned int Size; /* File size in bytes */
unsigned short int Reserved1, Reserved2;
unsigned int Offset; /* Offset to data (in B) */
} FILEHEADER; /* 12 Bytes */
:
char Magic[2];
FILEHEADER BMPFileHeader;
fread(Magic, 1, 2, BMPFile);
fread(&BMPFileHeader, 1, 12, BMPFile);
This will still have problems if you run it on a big-endian machine due to byte ordering. For full generality, you need to read the file contents as bytes and construct the multibyte values manually.
I am trying to take in a .bmp file and eventually edit the pixels one by one but I am coming up with a problem with the width and height returned to me in the INFOHEADER struct. The width returned is 13107200 and the height is 65536. However, whenever I run through the program a total of only 60003 total pixels are counted. I have no idea why this is. Any help would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] ){
//define structures
typedef struct
{ unsigned short int Type; /* Magic identifier */
unsigned int Size; /* File size in bytes */
unsigned short int Reserved1, Reserved2;
unsigned int Offset; /* Offset to data (in B)*/
}HEADER; /* -- 14 Bytes -- */
typedef struct
{ unsigned int Size; /* Header size in bytes */
int Width, Height; /* Width / Height of image */
unsigned short int Planes; /* Number of colour planes */
unsigned short int Bits; /* Bits per pixel */
unsigned int Compression; /* Compression type */
unsigned int ImageSize; /* Image size in bytes */
int xResolution, yResolution;/* Pixels per meter */
unsigned int Colors; /* Number of colors */
unsigned int ImportantColors;/* Important colors */
}INFOHEADER; /* -- 40 Bytes -- */
typedef struct
{ unsigned char Red, Green, Blue;
}PIXEL;
//make instance of all three structures
HEADER data;
INFOHEADER data2;
PIXEL pixel;
//declare file read pointer
FILE *file;
//declare fileout read pointer
//FILE *fileout; //declare file printed file pointer
// open file 1 of argument counter and return 0 apon error
if( !(file = fopen( "CU.bmp","rb")))return 0;
//read HEADER data into data
fread(&data,sizeof(HEADER),1,file);
//read IB+NFOHEADER data into data2
fread(&data2,sizeof(INFOHEADER),1,file);
//Print PIXEL data
//Allocate space for pixelarray
PIXEL **pixelarray;
int r=0,c=0,rows=data2.Height,collumns=data2.Width;
pixelarray= malloc(rows*sizeof(PIXEL *));
for(r=0; r<rows; r++){
pixelarray[r]=malloc(collumns*sizeof(PIXEL));
}
//fill pixel array with pixel structs
r=0;c=0;
int pixelnum=1;
while( fread(&pixel,sizeof(PIXEL),1,file) ){
if(c == collumns){
c=0;
r++;
}
pixelarray[r][c] = pixel;
printf("\nPixel %10d: %02X%02X%02X",pixelnum,pixelarray[r][c].Red,pixelarray[r][c].Blue,pixelarray[r][c].Green);
fflush(stdout);
c++;pixelnum++;
}
free(pixelarray);
fclose(file); //close the files prior to exiting
I guess your problem is structure alignment. You can refer to it here and here. To eliminate it use the #pragma directive. So your structure declaration would be something like this:
#pragma pack(push) // push current alignment to stack
#pragma pack(1) // set alignment to 1 byte boundary
typedef struct
{
unsigned short int Type; /* Magic identifier */
unsigned int Size; /* File size in bytes */
unsigned short int Reserved1;
unsigned short int Reserved2;
unsigned int Offset; /* Offset to data (in B)*/
}HEADER; /* -- 14 Bytes -- */
typedef struct
{
unsigned int Size; /* Header size in bytes */
int Width;
int Height; /* Width / Height of image */
unsigned short int Planes; /* Number of colour planes */
unsigned short int Bits; /* Bits per pixel */
unsigned int Compression; /* Compression type */
unsigned int ImageSize; /* Image size in bytes */
int xResolution;
int yResolution;/* Pixels per meter */
unsigned int Colors; /* Number of colors */
unsigned int ImportantColors;/* Important colors */
}INFOHEADER; /* -- 40 Bytes -- */
typedef struct
{
unsigned char Red;
unsigned char Green;
unsigned char Blue;
}PIXEL;
#pragma pack(pop) // restore original alignment from stack
This correctly reads the width and height of BMP image. Further while reading image data, do it directly:
for( r=0; r<rows; r++ )
{
for( c=0; c<collumns; c++ ) // read pixel data from image
{
fread(&pixelarray[r][c] , 1, sizeof(PIXEL), file);
pixelnum++;
}
}
You must use 16 bit variable (unsigned short) instead of int for width and height. According to Wikipedia, width/height is 16 bit.
Open the bmp file in a hex editor and see what value is present in the info header.
Then debug you code and check what value you read in the infoheader.
I am working on inputting a BMP and then manipulating the nearly every pixel in my 2D pixelarray and storing it in the array 2D pixelarrayout (which is seen inside of the first nested for loop in the final code segment below). I feel that the outputted BMP should be functional and everything seems to be alright when looking at the file through a Hex editor but for some reason the file cannot open properly. Any ideas why? Possibly an error in the header, but the first 54 bytes (size of both headers) of each file are the same
//make an instance of all output structure
HEADER dataoutput;
INFOHEADER data2output;
char pixeloutput[pixelnum];
int pixcount=0;
for(r=0; r<rows; r++){
for(c=0; c<collumns;c++){
pixeloutput[pixcount]=pixelarrayout[r][c].Red;
pixcount++;
}
}
dataoutput.Type = data.Type;
dataoutput.Size = data.Size;
dataoutput.Reserved1 = data.Reserved1;
dataoutput.Reserved2 = data.Reserved2;
dataoutput.Offset = data.Offset;
data2output.Size = data2.Size;
data2output.Width = data2.Width;
data2output.Height = data2.Height;
data2output.Planes = data2.Planes;
data2output.Bits = data2.Bits;
data2output.Compression = data2.Compression;
data2output.ImageSize = data2.ImageSize;
data2output.xResolution = data2.xResolution;
data2output.yResolution = data2.yResolution;
data2output.Colors = 0;
data2output.ImportantColors = 0;
if( !(fileout = fopen( "CUoutput4.bmp","wb")))return 0;
//calloc an array of 16 bytes set to NULL to be used to pad the end of the file
char *nullarray;
nullarray = (char*) calloc(16,sizeof(char));
fwrite(&dataoutput,sizeof(HEADER),1,fileout);
fwrite(&data2output,sizeof(INFOHEADER),1,fileout);
int i;
char *pixelvaluehold;
for(i=0;i<pixelnum;i++){
pixelvaluehold = &pixeloutput[i];
fwrite(pixelvaluehold,sizeof(char),1,fileout);
}
int count=0;
while(( count + sizeof(HEADER) + sizeof(INFOHEADER) + pixelnum * sizeof(PIXEL) ) % 16 != 0){
fwrite(nullarray,sizeof(char),1,fileout);
count++;
}
fclose(file);
fclose(fileout);
free(pixelarray);
free(pixelarrayout);
And here are the structs for HEADER,INFOHEADER, and PIXEL
//define structures
typedef struct
{ unsigned short int Type; /* Magic identifier */
unsigned int Size; /* File size in bytes */
unsigned short int Reserved1, Reserved2;
unsigned int Offset; /* Offset to data (in B)*/
}HEADER; /* -- 14 Bytes -- */
typedef struct
{ unsigned int Size; /* Header size in bytes */
unsigned int Width, Height; /* Width / Height of image */
unsigned short int Planes; /* Number of colour planes */
unsigned short int Bits; /* Bits per pixel */
unsigned int Compression; /* Compression type */
unsigned int ImageSize; /* Image size in bytes */
int xResolution, yResolution;/* Pixels per meter */
unsigned int Colors; /* Number of colors */
unsigned int ImportantColors;/* Important colors */
}INFOHEADER; /* -- 40 Bytes -- */
//restor original stack allignment
#pragma pack(pop)
typedef struct
{ unsigned char Red, Blue, Green;
}PIXEL;
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.