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
andheight
are vice versa. - You should not cast the return value of
malloc()
. - Bmp file header is composed of
BMP File header
(14 bytes fixed) andDIB 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;
}