I tried to open bmp file and save it using c code. My code worked well on window compiler(visual studio) but it didn't work on linux using gcc. Even though the format of final output is bmp, it shows like empty file(white). I'm a beginner for using linux and c programming so I'm not sure what's wrong with this happening!
I compiled it using gcc: gcc bmp.c -o bmp.
the code below is what I used.
#define _CRT_SECURE_NO_WARNINGS
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#define WIDTHBYTES(bits) (((bits)+31)/32*4)
#pragma pack(push, 1)
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef long LONG;
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER {
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;
typedef struct tagRGBQUAD {
unsigned char rgbBlue;
unsigned char rgbGreen;
unsigned char rgbRed;
unsigned char rgbReserved;
} RGBQUAD;
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO;
int main(int argc, char* argv[]){
FILE *infile;
FILE *outfile;
BITMAPFILEHEADER hf;
BITMAPINFOHEADER hInfo;
RGBQUAD hRGBpal[256];
unsigned char *lpImg;
int i, j, pos, rwsize;
int nBitCount = 1;
infile = fopen("image.bmp", "rb");
if (infile == NULL)
{
printf("no image");
return 1;
}
fread(&hf, sizeof(BITMAPFILEHEADER), 1, infile);
if (hf.bfType != 0x4d42)
{
printf("ERROR\n");
fclose(infile);
exit(1);
}
fread(&hInfo, sizeof(BITMAPINFOHEADER), 1, infile);
if (hInfo.biBitCount == 8 || hInfo.biBitCount == 16 ||
hInfo.biBitCount == 24 || hInfo.biBitCount == 32)
{
nBitCount = hInfo.biBitCount / 8;
if (hInfo.biBitCount == 8)
{
pos = hf.bfOffBits - hf.bfSize - hInfo.biSize;
if (pos > 0)
{
fread((unsigned char *)hRGBpal, sizeof(unsigned char), pos, infile);
}
}
lpImg = (unsigned char*)malloc(hInfo.biSizeImage);
fseek(infile, hf.bfOffBits, SEEK_SET);
fread(lpImg, sizeof(unsigned char), hInfo.biSizeImage, infile);
fclose(infile);
}
rwsize = WIDTHBYTES(hInfo.biBitCount*hInfo.biWidth);
for (i = 0; i < hInfo.biHeight; i++)
{
for (j = 0; j < hInfo.biWidth; j++)
{
lpImg[i*rwsize + j];
}
}
outfile = fopen("out.bmp", "wb")
if (hInfo.biBitCount == 8)
{
hf.bfOffBits = sizeof(BITMAPFILEHEADER)
+ sizeof(BITMAPINFOHEADER) + sizeof(hRGBpal);
}
fwrite(&hf, sizeof(char), sizeof(BITMAPFILEHEADER), outfile);
fwrite(&hInfo, sizeof(char), sizeof(BITMAPINFOHEADER), outfile);
if (hInfo.biBitCount == 8)
{
fwrite(hRGBpal, sizeof(RGBQUAD), 256, outfile);
}
fwrite(lpImg, sizeof(unsigned char), hInfo.biSizeImage, outfile);
fclose(outfile);
if (lpImg)
free(lpImg);
printf("DONE!");}
This probably goes wrong here:
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef long LONG;
If you're on 64bit Linux, long has 64 bits. On 64bit Windows, it has only 32bits. For portable code, use fixed-size integers:
typedef uint16_t WORD;
typedef uint32_t DWORD;
typedef int32_t LONG;
On a further note, there's no need to introduce these ugly (my opinion here) winapi typedefs at all. A (sloppy) version of the bitmap file header I'm using (still relying on the "packed struct" feature and merging both structs into one) looks like this:
#pragma pack(push)
#pragma pack(1)
struct bmphdr
{
uint16_t bfType;
uint32_t bfSize;
uint32_t bfReserved;
uint32_t bfOffBits;
uint32_t biSize;
uint32_t biWidth;
int32_t biHeight;
uint16_t biPlanes;
uint16_t biBitCount;
uint32_t biCompression;
uint32_t biSizeImage;
int32_t biXPelsPerMeter;
int32_t biYPelsPerMeter;
uint32_t biClrUsed;
uint32_t biClrImportant;
};
#pragma pack(pop)
Related
Sorry for my bad English.
Im trying to read a .bmp file in a C code using gcc on Linux (Fedora 27) but it doesn't work, the specific problem is when I use "fread()". I run the same code on raspbian (4.9.2-10) and magically works, read and write a .bmp file correctly. I really don't know what happening, I need help, please :'(
I use this image:
https://mega.nz/#!c5hVEYTb!u4Mc3JxvrHxxpaMLpH8A-KS3_bb72_Nj9bHv1x-2keU
This is the code:
#include <stdio.h>
#include <stdlib.h>
#pragma pack(push, 1)
typedef struct Pix
{
unsigned char R;
unsigned char G;
unsigned char B;
unsigned char L;
int BW;
}Pix;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct BitMap
{
short Signature;
long Reserved1;
long Reserved2;
long DataOffSet;
long Size;
long Width;
long Height;
short Planes;
short BitsPerPixel;
long Compression;
long SizeImage;
long XPixelsPreMeter;
long YPixelsPreMeter;
long ColorsUsed;
long ColorsImportant;
struct Pix *pixels;
}BitMap;
#pragma pack(pop)
int main(int argc, char **argv)
{
unsigned long int i=0;
unsigned long int S=0;
struct BitMap source_info;
struct Pix source_pix;
FILE *fp;
FILE *Dfp;
fp=fopen("in.bmp","rb");
if (fp==NULL)
{
fputs("File error:", stderr);
exit(1);
}
Dfp=fopen("out.bmp","wb");
//I think maybe in this line is the problem:
fread(&source_info, sizeof(source_info),1,fp);
S=source_info.Width*source_info.Height;
source_info.pixels = (struct Pix *) malloc(sizeof(struct Pix)*S);
for(i=1;i<=S;i++)
{
//read pixel from the source file
fread(&source_pix,sizeof(struct Pix),1,fp);
source_info.pixels[i-1] = source_pix;
}
fwrite(&source_info, sizeof(BitMap),1,Dfp);
// write pixels to destination file
for(i=1;i<=S;i++)
{
fwrite(&source_info.pixels[i-1],sizeof(struct Pix),1,Dfp);
}
fclose(fp);
fclose(Dfp);
return 0;
}
You are not using fixed size types between architectures. For example on a 32-bit platform long is 32 bit, but on 64-bit long is 64 bit, which is why on a 64-bit platform it can not read the headers correctly. The solution is to use the defines in stdint.
#include <stdint.h>
#pragma pack(push, 1)
typedef struct Pix
{
uint8_t R, G, B;
int32_t BW;
}
Pix;
typedef struct BitMap
{
int16_t Signature;
int32_t Reserved1;
int32_t Reserved2;
int32_t DataOffSet;
int32_t Size;
int32_t Width;
int32_t Height;
int16_t Planes;
int16_t BitsPerPixel;
int32_t Compression;
int32_t SizeImage;
int32_t XPixelsPreMeter;
int32_t YPixelsPreMeter;
int32_t ColorsUsed;
int32_t ColorsImportant;
struct Pix *pixels;
}
BitMap;
#pragma pack(pop)
I am trying to copy the screen to a bitmap file, I found this write XImage to .bmp file in C thread. I tried the code provided myself, but I can not make the code work. It can save a img file, but won't be able to open it. Anything wrong I am doing here?
#include <iostream>
#include <X11/Xlib.h>
#include <cstring>
#include<stdio.h>
typedef unsigned short WORD; // 2bytes
typedef unsigned long DWORD; //4bytes
typedef long LONG;
using namespace std;
void saveXImageToBitmap(XImage *pImage);
int main()
{
Display *display;
int screen;
Window root;
display = XOpenDisplay(0);
screen = DefaultScreen(display);
root = RootWindow(display, screen);
XImage *img = XGetImage(display,root,0,0,400,400,XAllPlanes(),ZPixmap);
if (img != NULL)
{
saveXImageToBitmap(img);
//save image here
}
return 0;
}
#pragma pack(push, 1)
typedef struct BITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
};
#pragma pack(pop)
#pragma pack (push,1)
typedef struct BITMAPINFOHEADER{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
};
#pragma pack(pop)
void saveXImageToBitmap(XImage *pImage)
{
BITMAPFILEHEADER bmpFileHeader;
BITMAPINFOHEADER bmpInfoHeader;
FILE *fp;
static int cnt = 0;
int dummy;
char filePath[255];
memset(&bmpFileHeader, 0, sizeof(BITMAPFILEHEADER));
memset(&bmpInfoHeader, 0, sizeof(BITMAPINFOHEADER));
bmpFileHeader.bfType = 0x4D42;
bmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + pImage->width*pImage->height*4;
bmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bmpFileHeader.bfReserved1 = 0;
bmpFileHeader.bfReserved2 = 0;
bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfoHeader.biWidth = pImage->width;
bmpInfoHeader.biHeight = pImage->height;
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = 32;
dummy = (pImage->width * 3) % 4;
if((4-dummy)==4)
dummy=0;
else
dummy=4-dummy;
bmpInfoHeader.biSizeImage = ((pImage->width*3)+dummy)*pImage->height;
bmpInfoHeader.biCompression = 0;
bmpInfoHeader.biXPelsPerMeter = 0;
bmpInfoHeader.biYPelsPerMeter = 0;
bmpInfoHeader.biClrUsed = 0;
bmpInfoHeader.biClrImportant = 0;
sprintf(filePath, "bitmap%d.bmp", cnt++);
fp = fopen(filePath,"wb");
if(fp == NULL)
return;
fwrite(&bmpFileHeader, sizeof(bmpFileHeader), 1, fp);
fwrite(&bmpInfoHeader, sizeof(bmpInfoHeader), 1, fp);
fwrite(pImage->data, 4*pImage->width*pImage->height, 1, fp);
fclose(fp);
}
I figured it out, the struct BITMAPFILEHEADER size should be 14 based on bitmap file format, the types I was using was wrong. please check the revised code for answer
#include <iostream>
#include <X11/Xlib.h>
#include <cstring>
#include<stdio.h>
using namespace std;
void saveXImageToBitmap(XImage *pImage);
int main()
{
Display *display;
int screen;
Window root;
display = XOpenDisplay(0);
screen = DefaultScreen(display);
root = RootWindow(display, screen);
XWindowAttributes gwa;
XGetWindowAttributes(display, root, &gwa);
int width = gwa.width;
int height = gwa.height;
XImage *img = XGetImage(display,root,0,0,width,height,XAllPlanes(),ZPixmap);
if (img != NULL)
{
saveXImageToBitmap(img);
//save image here
}
return 0;
}
#pragma pack (1)
typedef struct BITMAPFILEHEADER
{
short bfType;
int bfSize;
short bfReserved1;
short bfReserved2;
int bfOffBits;
};
typedef struct BITMAPINFOHEADER
{
int biSize;
int biWidth;
int biHeight;
short biPlanes;
short biBitCount;
int biCompression;
int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
int biClrUsed;
int biClrImportant;
};
void saveXImageToBitmap(XImage *pImage)
{
BITMAPFILEHEADER bmpFileHeader;
BITMAPINFOHEADER bmpInfoHeader;
FILE *fp;
static int cnt = 0;
int dummy;
char filePath[255];
memset(&bmpFileHeader, 0, sizeof(BITMAPFILEHEADER));
memset(&bmpInfoHeader, 0, sizeof(BITMAPINFOHEADER));
bmpFileHeader.bfType = 0x4D42;
bmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
bmpFileHeader.bfReserved1 = 0;
bmpFileHeader.bfReserved2 = 0;
int biBitCount =32;
int dwBmpSize = ((pImage->width * biBitCount + 31) / 32) * 4 * pImage->height;
printf("size of short:%d\r\n",(int)sizeof(short));
printf("size of int:%d\r\n",(int)sizeof(int));
printf("size of long:%d\r\n",(int)sizeof(long));
printf("dwBmpSize:%d\r\n",(int)dwBmpSize);
printf("BITMAPFILEHEADER:%d\r\n",(int)sizeof(BITMAPFILEHEADER));
printf("BITMAPINFOHEADER:%d\r\n",(int)sizeof(BITMAPINFOHEADER));
bmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwBmpSize;
bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfoHeader.biWidth = pImage->width;
bmpInfoHeader.biHeight = pImage->height;
bmpInfoHeader.biPlanes = 1;
bmpInfoHeader.biBitCount = biBitCount;
bmpInfoHeader.biSizeImage = 0;
bmpInfoHeader.biCompression = 0;
bmpInfoHeader.biXPelsPerMeter = 0;
bmpInfoHeader.biYPelsPerMeter = 0;
bmpInfoHeader.biClrUsed = 0;
bmpInfoHeader.biClrImportant = 0;
sprintf(filePath, "bitmap%d.bmp", cnt++);
fp = fopen(filePath,"wb");
if(fp == NULL)
return;
fwrite(&bmpFileHeader, sizeof(bmpFileHeader), 1, fp);
fwrite(&bmpInfoHeader, sizeof(bmpInfoHeader), 1, fp);
fwrite(pImage->data, dwBmpSize, 1, fp);
fclose(fp);
}
I am trying to create .bmp file (filled with one colour for testing purposes).
Here is code that I'm using:
#include <stdio.h>
#define BI_RGB 0
typedef unsigned int UINT;
typedef unsigned long DWORD;
typedef long int LONG;
typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef struct tagBITMAPFILEHEADER {
UINT bfType;
DWORD bfSize;
UINT bfReserved1;
UINT bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER {
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;
typedef struct COLORREF_RGB
{
BYTE cRed;
BYTE cGreen;
BYTE cBlue;
}COLORREF_RGB;
int main(int argc, char const *argv[])
{
BITMAPINFOHEADER bih;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biWidth = 600;
bih.biHeight = 600;
bih.biSizeImage = bih.biWidth * bih.biHeight * 3;
bih.biPlanes = 1;
bih.biBitCount = 24;
bih.biCompression = BI_RGB;
bih.biXPelsPerMeter = 2835;
bih.biYPelsPerMeter = 2835;
bih.biClrUsed = 0;
bih.biClrImportant = 0;
COLORREF_RGB rgb;
rgb.cRed = 0;
rgb.cGreen = 0;
rgb.cBlue = 0;
BITMAPFILEHEADER bfh;
bfh.bfType = 0x424D;
bfh.bfReserved1 = 0;
bfh.bfReserved2 = 0;
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + bih.biSize;
bfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
bih.biWidth * bih.biHeight * 4;
FILE *f;
f = fopen("test.bmp","wb");
fwrite(&bfh, sizeof(BITMAPFILEHEADER), 1, f);
fwrite(&bih, sizeof(BITMAPINFOHEADER), 1, f);
int i,j;
for(i = 0; i < bih.biHeight; i++)
{
for(j = 0; j < bih.biWidth; j++)
{
fwrite(&rgb,sizeof(COLORREF_RGB),1,f);
}
}
fclose(f);
return 0;
}
and jet every time I compile and run it I get error saying that its not valid BMP image. I double checked all values in multiple references and still can't find error here.
Did I misunderstood something and what am I doing wrong here?
Also not sure if important but I am using Ubuntu 14.04 to compile this.
EDIT
Found one more issue :
bfh.bfType = 0x424D;
should be
bfh.bfType = 0x4D42;
But still can't see image.
First of all, you set:
bfSize Specifies the size of the file, in bytes.
to invalid value, your code resulted into 1440112 while size of file is actually 1080112
bfh.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
bih.biWidth * bih.biHeight * sizeof(COLORREF_RGB);
Because sizeof(COLORREF_RGB) is actually 4 not 3.
Another mistake is that size of your structs and types:
expected size actual size*
typedef unsigned int UINT; // 2 4
typedef unsigned long DWORD; // 4 8
typedef long int LONG; // 4 8
typedef unsigned short WORD; // 2 2
typedef unsigned char BYTE; // 1 1
* I'm using gcc on x86_64 architecture
Your offsets just don't match with offsets on wikipedia, reference you are using was probably written for 16 bit compiler on 16 bit OS (as pointed out by cup in a comment) so it assumes int to be 2B type.
Using values from stdint.h worked for me (guide on stdint.h for Visual Studio here):
#include <stdint.h>
typedef uint16_t UINT;
typedef uint32_t DWORD;
typedef int32_t LONG;
typedef uint16_t WORD;
typedef uint8_t BYTE;
And last but not least you have to turn off memory alignment as suggested by Weather Vane.
I believe your field sizes to be incorrect, try this
#pragma pack(push, 1)
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
#pragma pack(pop)
You are trying to map a C structure to some externally-defined binary format There are a number of problems with this:
Size
typedef unsigned int UINT;
typedef unsigned long DWORD;
typedef long int LONG;
typedef unsigned short WORD;
typedef unsigned char BYTE;
The C language only specify the minimum sizes of these types. Their actual sizes can and do vary between different compilers and operating systems. The sizes and offset of the members in your structures may not be what you expect. The only size that you can rely on (on almost any system that you are likely to encounter these days) is char being 8 bits.
Padding
typedef struct tagBITMAPFILEHEADER {
UINT bfType;
DWORD bfSize;
UINT bfReserved1;
UINT bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
It is common for DWORD to be twice as large as a UINT, and in fact your program depends on it. This usually means that the compiler will introduce padding between bfType and bfSize to give the latter appropriate alignment for its type. The .bmp format has no such padding.
Order
BITMAPFILEHEADER bfh;
bfh.bfType = 0x424D;
...
fwrite(&bfh, sizeof(BITMAPFILEHEADER), 1, f);
Another problem is that the C language does not specify the endianess of the types. The .bfType member may be stored as [42][4D] (Big-Endian) or [4D][42] (Little-Endian) in memory. The .bmp format specifically requires the values to be stored in Little-Endian order.
Solution
You might be able to solve some of these problems by using compiler-specific extensions (such as #pragma's or compiler switches), but probably not all of them.
The only way to properly write an externally-defined binary format, is to use an array of unsigned char and write the values a byte at a time. Personally, I would write a set of helper functions for specific types:
void w32BE (unsigned char *p, unsigned long ul)
{
p[0] = (ul >> 24) & 0xff;
p[1] = (ul >> 16) & 0xff;
p[2] = (ul >> 8) & 0xff;
p[3] = (ul ) & 0xff;
}
void w32LE (unsigned char *p, unsigned long ul)
{
p[0] = (ul ) & 0xff;
p[1] = (ul >> 8) & 0xff;
p[2] = (ul >> 16) & 0xff;
p[3] = (ul >> 24) & 0xff;
}
/* And so on */
and some functions for writing the entire .bmp file or sections of it:
int function write_header (FILE *f, BITMAPFILEHEADER bfh)
{
unsigned char buf[14];
w16LE (buf , bfh.bfType);
w32LE (buf+ 2, bfh.bfSize);
w16LE (buf+ 6, bfh.bfReserved1);
w16LE (buf+ 8, bfh.bfReserved2);
w32LE (buf+10, bfh.bfOffBits);
return fwrite (buf, sizeof buf, 1, f);
}
This is my first time working with bitmaps, and I've gotten pretty much most of what i need figured out already. I just need to figure out how to
1) print the first 16 pixels
Please help :) I am trying get a good grasp of working with the bmp format.
#include <stdio.h>
typedef struct __attribute__((__packed__)) {
unsigned char fileMarker1;
unsigned char fileMarker2;
unsigned int bfSize;
uint16_t unused1;
uint16_t unused2;
unsigned int imageDataOffset;
} FILEHEADER;
typedef struct __attribute__((__packed__)) {
unsigned int biSize;
int width;
int height;
uint16_t planes;
uint16_t bitPix;
unsigned int biCompression;
unsigned int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
unsigned int biClrUsed;
unsigned int biClrImportant;
} INFOHEADER;
typedef struct __attribute__((__packed__)) {
unsigned char b;
unsigned char g;
unsigned char r;
} IMAGE;
int main(void) {
FILEHEADER fh;
INFOHEADER ih;
FILE *img = fopen("sample.bmp", "rb");
fread(&fh, sizeof(unsigned char), sizeof(FILEHEADER), img);
fread(&ih, sizeof(unsigned char), sizeof(INFOHEADER), img);
printf("width: <%d>\nheight: <%d>\n", ih.width, ih.height);
printf("planes: <%d>\n", ih.planes) ;
printf("Bits per pixel: <%d>", ih.bitPix );
return 0;
}
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.)