Home > OS >  Damaged/unsupported .bmp file
Damaged/unsupported .bmp file

Time:06-09

I need to implement a Box Blur algorithm for a school project and I found this algorithm online. My issue is that i can't open the "result.bmp" file after the algorithm is done. It says the file is either corrupted or damaged and I can't seem to find the cause of this issue.

Code:

    FILE* fIn = fopen("test.bmp", "r");         // Input File name
    FILE* fOut = fopen("result.bmp", "w ");             // Output File name

    int i, j, y, x;
    unsigned char byte[54];


    for (i = 0; i < 54; i  )                        // read the 54 byte header from fIn
    {
        byte[i] = fgetc(fIn);
    }

    fwrite(byte, sizeof(unsigned char), 54, fOut);          // write the header back

    // extract image height, width and bitDepth from imageHeader 
    int height = *(int*)&byte[18];
    int width = *(int*)&byte[22];
    int bitDepth = *(int*)&byte[28];

    printf("width: %d\n", width);
    printf("height: %d\n", height);

    int size = height * width;

    unsigned char** buffer = (unsigned char**)malloc(size * sizeof(unsigned char*));
    for (int i = 0; i < size; i  )
        buffer[i] = (unsigned char*)malloc(3 * sizeof(unsigned char));

    unsigned char** out = (unsigned char**)malloc(size * sizeof(unsigned char*));
    for (int i = 0; i < size; i  )
        out[i] = (unsigned char*)malloc(3 * sizeof(unsigned char));

    for (i = 0; i < size; i  )                      
    {
        buffer[i][2] = getc(fIn);                   // blue
        buffer[i][1] = getc(fIn);                   // green
        buffer[i][0] = getc(fIn);                   // red
    }


    float v = 1.0 / 9.0;                        // initialize the blurring kernel
    float kernel[3][3] = { {v,v,v},
                        {v,v,v},
                        {v,v,v} };

    for (x = 1; x < height - 1; x  )
    {
        for (y = 1; y < width - 1; y  )
        {
            float sum0 = 0.0;
            float sum1 = 0.0;
            float sum2 = 0.0;
            for (i = -1; i <= 1; i  )
            {
                for (j = -1; j <= 1; j  )
                {
                    // matrix multiplication with kernel with every color plane
                    sum0 = sum0   (float)kernel[i   1][j   1] * buffer[(x   i) * width   (y   j)][0];
                    sum1 = sum1   (float)kernel[i   1][j   1] * buffer[(x   i) * width   (y   j)][1];
                    sum2 = sum2   (float)kernel[i   1][j   1] * buffer[(x   i) * width   (y   j)][2];
                }
            }
            out[(x)*width   (y)][0] = (unsigned char)sum0;
            out[(x)*width   (y)][1] = (unsigned char)sum1;
            out[(x)*width   (y)][2] = (unsigned char)sum2;
        }
    }


    for (i = 0; i < size; i  )                      //write image data back to the file
    {
        fputc(out[i][2], fOut);
        fputc(out[i][1], fOut);
        fputc(out[i][0], fOut);
    }

The algorithm successfully reads the width and the height of the input image, it creates the output file but the file cannot be opened.

CodePudding user response:

Your code is very close but has some issues:

  • You can calculate the byte count per line considering the 4-byte alignment with ((width * 3 3) / 4) * 4.
  • The addesses of width and height are vice versa.
  • You should not cast the return value of malloc().
  • Bmp file header is composed of BMP File header (14 bytes fixed) and DIB header (variable size). As the size of DIB header is stored in the starting 4 bytes of the DIB header, lets read the 18 bytes (= 14 4) at first, determine the remaining header size, then read the rest of DIB header.

Then the modified version will look like:

#include <stdio.h>
#include <stdlib.h>
#define INFILE "test.bmp"       // input file name
#define OUTFILE "result.bmp"    // output file name
#define HEADER1 (14   4)        // Bitmap File Header   word for header size
#define HEADER2 (124 - 4)       // DIB (Information) File Header - word for header size

int main()
{
    FILE *fIn = fopen(INFILE, "r");
    if (fIn == NULL) {
        perror(INFILE);
        exit(1);
    }
    FILE *fOut = fopen(OUTFILE, "w ");
    if (fOut == NULL) {
        perror(OUTFILE);
        exit(1);
    }

    int i, j, y, x;
    int dibsize;                                        // size of DIB Header
    unsigned char header1[HEADER1];
    unsigned char header2[HEADER2];

    fread(header1, sizeof(unsigned char), HEADER1, fIn);    // read file header   DIB header size
    dibsize = *(int *)&header1[14];                         // size of DIB header
    fwrite(header1, sizeof(unsigned char), HEADER1, fOut);  // write the header back

    fread(header2, sizeof(unsigned char), dibsize - 4, fIn);    // read remaining DIB header except for the word for the header size
    fwrite(header2, sizeof(unsigned char), dibsize - 4, fOut);  // write the header back

    // extract image height, width and bitDepth from imageHeader 
    int width = *(int *)&header2[0];
    int height = *(int *)&header2[4];
    int bitDepth = *(int *)&header2[20];
    int bytesperline = ((width * 3   3) / 4) * 4;       // bytes per line including 4-byte alignment

    printf("width: %d\n", width);
    printf("height: %d\n", height);
//  printf("bytesperline: %d\n", bytesperline);

    int size = height * width;

    unsigned char **buffer = malloc(size * sizeof(unsigned char *));
    for (int i = 0; i < size; i  )
        buffer[i] = malloc(3 * sizeof(unsigned char));

    unsigned char **out = malloc(size * sizeof(unsigned char *));
    for (int i = 0; i < size; i  )
        out[i] = malloc(3 * sizeof(unsigned char));

    for (i = 0; i < height; i  )
    {
        for (j = 0; j < width; j  )
        {
            buffer[i * width   j][2] = getc(fIn);       // blue
            buffer[i * width   j][1] = getc(fIn);       // green
            buffer[i * width   j][0] = getc(fIn);       // red
        }
        for (j = width * 3; j < bytesperline; j  )      // zero padding for 4-byte alignment
        {
            getc(fIn);
        }
    }

    float v = 1.0 / 9.0;                                // initialize the blurring kernel
    float kernel[3][3] = { {v,v,v},
                        {v,v,v},
                        {v,v,v} };

    for (x = 1; x < height - 1; x  )
    {
        for (y = 1; y < width - 1; y  )
        {
            float sum0 = 0.0;
            float sum1 = 0.0;
            float sum2 = 0.0;
            for (i = -1; i <= 1; i  )
            {
                for (j = -1; j <= 1; j  )
                {
                    // matrix multiplication with kernel with every color plane
                    sum0 = sum0   (float)kernel[i   1][j   1] * buffer[(x   i) * width   (y   j)][0];
                    sum1 = sum1   (float)kernel[i   1][j   1] * buffer[(x   i) * width   (y   j)][1];
                    sum2 = sum2   (float)kernel[i   1][j   1] * buffer[(x   i) * width   (y   j)][2];
                }
            }
            out[x * width   y][0] = (unsigned char)sum0;
            out[x * width   y][1] = (unsigned char)sum1;
            out[x * width   y][2] = (unsigned char)sum2;
        }
    }

    for (i = 0; i < height; i  )                        // write image data back to the file
    {
        for (j = 0; j < width; j  )
        {
            fputc(out[i * width   j][2], fOut);         // blue
            fputc(out[i * width   j][1], fOut);         // green
            fputc(out[i * width   j][0], fOut);         // red
        }
        for (j = width * 3; j < bytesperline; j  )      // zero padding for 4-byte alignment
        {
            fputc(0, fOut);
        }
    }

    fclose(fIn);
    fclose(fOut);
    return 0;
}
  • Related