Mike Smith
Mike Smith

Reputation: 23

Inverting colors of pixels in a BMP file in C

My problem I am having is trying to invert the colors on a simple black and white image.

enter image description here

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.

enter image description here

This is a close up of the bottom left corner.

enter image description here

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"

enter image description here

Upvotes: 0

Views: 4183

Answers (2)

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

Jo&#227;o Amaral
Jo&#227;o Amaral

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

Related Questions