Reputation: 23
My problem I am having is trying to invert the colors on a simple black and white image.
When I run my C program and perform bitwise-NOT on each of the BGR values I instead end up with an image like so. It appears to repeat, Black, Blue, Green and Red pixels for the entire image. I have read there is an extra byte for padding at the end of each pixel, which I attempt to skip over each iteration.
This is a close up of the bottom left corner.
Here is my code to read the BMP file and invert the colors of the image.
void invertImage(char fileName[]) {
struct BMP bmp;
struct DIB dib;
struct PIXEL pixel;
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("File format not supported");
exit(-1);
}
//Size of the file in bytes
fread(&bmp.filesize, 4, 1, fp);
printf("Value is %d\n", bmp.filesize);
//Go to dataoffset
fseek(fp, 4, 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);
if (dib.fileheader != 40) {
printf("File format not supported");
exit(-1);
}
fread(&dib.width, 4, 1, fp);
printf("Width is %d\n", dib.width);
fread(&dib.height, 4, 1, fp);
printf("Height is %d\n", dib.height);
fread(&dib.planes, 2, 1, fp);
printf("Color planes is %d\n", dib.planes);
//Number of bits per pixel
fread(&dib.bitsperpixel, 2, 1, fp);
printf("Pixels per bit is %d\n", dib.bitsperpixel);
fread(&dib.compression, 4, 1, fp);
printf("Compression scheme used is %d\n", dib.compression);
fread(&dib.bitmapsize, 4, 1, fp);
printf("Image size is %d\n", dib.bitmapsize);
fread(&dib.horizontalres, 4, 1, fp);
printf("Horizontal resolution is %d\n", dib.horizontalres);
fread(&dib.verticalres, 4, 1, fp);
printf("Vertical resolution is %d\n", dib.verticalres);
fread(&dib.numcolors, 4, 1, fp);
printf("Number of colors used %d\n", dib.numcolors);
fread(&dib.importantcolors, 4, 1, fp);
printf("Important colors used %d\n", dib.importantcolors);
//fseek(fp,3,SEEK_CUR);
int x = 0;
while (x < dib.width) {
int y = 0;
while (y < dib.height) {
fread(&pixel.b, 1, 1, fp);
unsigned int blue = pixel.b;
blue = ~blue;
pixel.b = (char) blue;
printf("Pixel 1 is %d\n", pixel.b);
fread(&pixel.g, 1, 1, fp);
unsigned int green = pixel.g;
green = ~green;
pixel.g = (char) green;
printf("Pixel 2 is %d\n", pixel.g);
fread(&pixel.r, 1, 1, fp);
unsigned int red = pixel.r;
red = ~red;
pixel.r = (char) red;
printf("Pixel 3 is %d\n", pixel.r);
fseek(fp, -3, SEEK_CUR);
fwrite(&pixel.b, 1, 1, fp);
fwrite(&pixel.g, 1, 1, fp);
fwrite(&pixel.r, 1, 1, fp);
fseek(fp, 1, SEEK_CUR);
y++;
}
// fseek(fp,1,SEEK_CUR);
x++;
}
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]);
}
return 0;
}
And also the structures that I use in my program.
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 {
unsigned char b;
unsigned char g;
unsigned char r;
};
This is the output minus the output from the double while loops which is just "Pixel n is 0" or "Pixel n is 255"
Upvotes: 0
Views: 4183
Reputation: 58947
You are skipping every 4th byte.
The file contains:
BGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGR...
^ start here
fread(&pixel.b, 1, 1, fp);
fread(&pixel.g, 1, 1, fp);
fread(&pixel.r, 1, 1, fp);
BGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGR...
^ now here
fseek(fp, -3, SEEK_CUR);
BGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGR...
^ now here
fwrite(&pixel.b, 1, 1, fp);
fwrite(&pixel.g, 1, 1, fp);
fwrite(&pixel.r, 1, 1, fp);
bgrBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGR...
^ now here
fseek(fp, 1, SEEK_CUR);
bgrBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGR...
^ now here - skipping the blue part of the second pixel?
To fix this, don't skip one byte after every pixel.
Upvotes: 1
Reputation: 331
It looks like your main reading loop is not taking into account the row padding as documented in https://en.wikipedia.org/wiki/BMP_file_format, specifically in the 'Pixel storage' section.
As your BMP is not multiple of 4 in width you are reading 3 extra bytes per line at the end shifting the colors of the next line.
Upvotes: 0