Reputation: 23
Here's the code:
#include <stdio.h>
#include <stdlib.h>
void main(void)
{
char path_bmp [100];
char path_txt [100];
int w; //width
int h; //height
int wc; //width counter
int hc; //height counter
FILE *bfp; //BMP pointer
FILE *tfp; //TXT pointer
puts("BMP path");
gets(path_bmp);
puts("Resulting TXT path");
gets(path_txt);
bfp = fopen(path_bmp, "r");
tfp = fopen(path_txt, "w");
fseek(bfp, 18, SEEK_SET);
fscanf(bfp, "%i", &w);
fseek(bfp, 4, SEEK_CUR);
fscanf(bfp, "%i", &h);
printf("%i x %i", w, h);
char mat [w][h];
fseek(bfp, 54, SEEK_SET);
for(hc=0; hc < h; hc++)
fread(mat, 1, w, bfp);
for(hc=0; hc < h; hc++)
for(wc=0; wc < w; wc++)
{
if (mat [wc][hc] == 0)
fprintf(tfp, " ");
else
fprintf(tfp, "o");
}
fprintf(tfp, "\n");
}
What it's intended to do: It converts a .bmp into ASCII-art, not very complicated, just pretty simple black and white pics. It should read .bmp, get height and width from header, read all pixels byte by byte into matrix(mat array), then write space into text file if pixel is white and write "0" if pixel is any color but white.
What it actually does:
It is reading w and h from some wrong place.
On printf("%i x %i", w, h);
it prints out some large numbers (I use small pics for testing, like 10x6 px) and then crashes, with process returning even larger number. As far as I can see, the program is clearly reading from some garbage instead of where it should read and I can't get why (spent lots of time trying to figure it out).
Also, I have a feel that I'm doing something wrong when reading to array/writing from array, so pointing out those flaws would be greatly appreciated.
UPD: Thank you, guys, you helped me greatly!
Upvotes: 2
Views: 2200
Reputation: 1047
There appear to have some problems with your code, including some basic stuff about C. I commented some errors that I caught at a first glance, but there may be some more. I would also recommend you to take a look at the bitmap format, specially at the section that describes the padding added to the end of each line.
#include <stdio.h>
#include <stdlib.h>
void main(void)
{
char path_bmp [100];
char path_txt [100];
int w; //width
int h; //height
int wc; //width counter
int hc; //height counter
FILE *bfp; //BMP pointer
FILE *tfp; //TXT pointer
puts("BMP path");
gets(path_bmp);
puts("Resulting TXT path");
gets(path_txt);
bfp = fopen(path_bmp, "r");
tfp = fopen(path_txt, "w");
fseek(bfp, 18, SEEK_SET);
fread(&w, sizeof(int), 1, bfp); // Read the width in binary format (signed integer)
fread(&h, sizeof(int), 1, bfp); // The position indicator of the stream is advanced by the total amount of bytes read (sizeof(int)).
printf("%i x %i", w, h);
pixel mat [w][h]; //This can be a packed structure or a union, so you can read all 3 color components with one fread() call
fseek(bfp, 54, SEEK_SET);
for(hc=0; hc < h; hc++)
{
for(wc=0; wc < w; wc++)
{
/* Note that you have to read three bytes, since every pixel has 3 color components*/
fread(mat[wc][hc].red, sizeof(char), 1, bfp);
fread(mat[wc][hc].green, sizeof(char), 1, bfp);
fread(mat[wc][hc].blue, sizeof(char), 1, bfp);
}
// you need to do a fseek() here, in order to advance the padding added to the end of each line defined in .BMP format
fprintf(tfp, "\n");
}
}
Upvotes: 2
Reputation: 8053
fscanf
with %i
reads an integer as a sequence of ASCII digits, but the width & height of the BMP are stored in raw binary. Use fread
instead to read them:
fread(&w, 1, 4, bfp);
fread(&h, 1, 4, bfp);
(fseek
isn't necessary before reading the height as the previous fread
already advances the stream pointer. Which is also the case for fscanf
)
As the width & height are specified to be 4 bytes it's recommended to use int32_t
instead of int
as the type to make sure it will always fit exactly.
Upvotes: 2