Reputation: 155
The following code is part of my program that tries to extract image features from a bitmap file. I need to extract information (width and height only) about the image and also make copies of it. These images are of 2048X 2168 resolution, 8-bit greyscale.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NAMELENGTH 301
long getImageInfo(FILE* Finput, long offset, int nchars){
unsigned char *ptrChar;
unsigned char dummy;
long value=0L;
int i;
dummy='0';
ptrChar=&dummy;
fseek(Finput,offset,SEEK_SET);
for (i=1; i<=nchars; i++){
fread(ptrChar,sizeof(char),1,Finput);
value += ((long) ((*ptrChar)*pow(256,(i-1))));
}
return(value);
}
void copyImageInfo(FILE* Finput, FILE* Foutput){
unsigned char *ptrChar;
unsigned char dummy;
long offset;
int i;
dummy='0';
ptrChar=&dummy;
int byte_size = ((int) getImageInfo(Finput,34,4));
/* copying header: signature, image width & height, number bit/pixel, image size, number of colors */
offset=0L;
fseek(Finput,offset,SEEK_SET);
fseek(Foutput,offset,SEEK_SET);
for (i=0; i<=54; i++){
fread(ptrChar,sizeof(char),1,Finput);
fwrite(ptrChar,sizeof(char),1,Foutput);
}
/* copying pixel data */
/* This part of the code may not be complete */
offset=54L;
fseek(Finput,offset,SEEK_SET);
fseek(Foutput,offset,SEEK_SET);
for (i=0; i<=byte_size; i++){
fread(ptrChar,sizeof(char),1,Finput);
fwrite(ptrChar,sizeof(char),1,Foutput);
}
}
int main(int argc, char *argv[]){
FILE* Finput;
FILE* Foutput;
char input_name[NAMELENGTH];
char output_name[NAMELENGTH];
char job_name[NAMELENGTH];
char history_name[NAMELENGTH];
unsigned char *ptrChar;
int pix_width,pix_height;
int bit_pixel,byte_size,ncolors;
strcpy(input_name,argv[1]); /* first argument contains path to the image file */
strcpy(job_name, argv[1]);
job_name[strlen(job_name)-4]='\0';
sprintf(history_name,"%s%s",job_name,"_hist.txt"); /* history file stores image header information */
if( (Finput=fopen(input_name,"r"))==NULL ){
fprintf(stderr,"\n ERROR: file %s could not be opened for reading\n",input_name);
exit(-1);
}
else{
fseek(Finput,0L,SEEK_END);
if (getImageInfo(Finput,0,2)!=19778) fprintf(stdout,"\n WARNING: wrong BMP signature!\n");
pix_width = ((int) getImageInfo(Finput,18,4));
pix_height = ((int) getImageInfo(Finput,22,4));
bit_pixel = ((int) getImageInfo(Finput,28,2));
byte_size = ((int) getImageInfo(Finput,34,4));
ncolors = ((int) getImageInfo(Finput,46,4));
fprintf(stdout,"\n width pixels=%d",pix_width);
fprintf(stdout,"\n height pixels=%d",pix_height);
fprintf(stdout,"\n bits per pixel=%d",bit_pixel);
fprintf(stdout,"\n image data size=%d",byte_size);
fprintf(stdout,"\n number colors=%d\n",ncolors);
/* history file */
if ( (Foutput=fopen(history_name,"a"))==NULL ){
fprintf(stderr,"\n ERROR: file %s could not be opened for appending\n",history_name);
exit(-1);
}
else{
fprintf(Foutput,"Path to Image: %s ",input_name);
fprintf(Foutput,"\n\t 18 - biWidth - width pixels=%d",pix_width);
fprintf(Foutput,"\n\t 22 - biHeight - height pixels=%d",pix_height);
fprintf(Foutput,"\n\t 28 - biBitCount - bits per pixel=%d",bit_pixel);
fprintf(Foutput,"\n\t 34 - biSizeImage - image data size=%d",byte_size);
fprintf(Foutput,"\n\t 46 - biClrUsed - number colors=%d\n",ncolors);
fclose(Foutput);
}
sprintf(output_name,"%s%s",job_name,"_copy.bmp");
if ( (Foutput=fopen(output_name,"wb"))==NULL ){
fprintf(stderr,"\n ERROR: file %s could not be opened for writing\n",output_name);
exit(-1);
}
else{
copyImageInfo(Finput,Foutput);
fclose(Foutput);
}
}
fclose(Finput);
}
Unfortunately, my original image files are in tif format. So when I convert them, I am unable to preserve some of the header file information. One online tool lets me preserve the bits-per-pixel (8 bit) but then I lose the biSizeImage (which turns to 0). Another conversion tool gets me the size correctly but image bitrate changes to 24. (link1, link2)
An example of my original tif image (temporary_link1) and the corresponding BMP image (temporary_link2)
When I run the above, I am able to copy the header information correctly but not the pixel data. If this can be copied using some other method (like for example by comparing the EOF), it may be a good alternative. I am unsure about calculating the padding and also the direction of writing.
Any guidance would be appreciated starting with the correct conversion of tif format to my required bmp format. Evidently I am new to image formatting and compression.
Output:
width pixels=2048
height pixels=2168
bits per pixel=8
image data size=0
number colors=0
Upvotes: 0
Views: 79
Reputation: 31599
getImageInfo
is incorrect. The integer values are supposed to be saved in little-endian format. It should be read as follows:
unsigned int getImageInfo(FILE *fin, long offset, int nchars)
{
fseek(fin, offset, SEEK_SET);
unsigned int value = 0;
for(int i = 0; i < nchars; i++)
{
unsigned char dummy = '0';
fread((char*)&dummy, sizeof(char), 1, fin);
value += dummy << (8 * i);
}
return value;
}
byte_size
is not guaranteed to be set to the correct value. This should be roughly equal to width * height * bit_pixel
. Use this formula.
byte_size = ((pix_width * bit_pixel + 31) / 32) * 4 * pix_height;
Moreover, 8-bit image includes color table of size 1024. This table is immediately after 54 byte header, and before the pixel data. Read it as follows:
unsigned int getImageInfo(FILE *fin, long offset, int nchars)
{
fseek(fin, offset, SEEK_SET);
unsigned int value = 0;
for(int i = 0; i < nchars; i++)
{
unsigned char dummy = '0';
fread((char*)&dummy, sizeof(char), 1, fin);
value += dummy << (8 * i);
}
return value;
}
void copyImageInfo(FILE* Finput, FILE* Foutput)
{
int w = getImageInfo(Finput, 18, 4);
int h = getImageInfo(Finput, 22, 4);
int bit_pixel = getImageInfo(Finput, 28, 2);
int byte_size = ((w * bit_pixel + 31) / 32) * 4 * h;
int ncolors = getImageInfo(Finput, 46, 4);
fprintf(stdout, "\n width pixels=%d", w);
fprintf(stdout, "\n height pixels=%d", h);
fprintf(stdout, "\n bits per pixel=%d", bit_pixel);
fprintf(stdout, "\n image data size=%d", byte_size);
fprintf(stdout, "\n number colors=%d\n", ncolors);
char header[54]; //bitmap header
char *pixels = malloc(byte_size); //pixel data
fseek(Finput, 0, SEEK_SET);
fseek(Foutput, 0, SEEK_SET);
fread(header, sizeof(header), 1, Finput);
fwrite(header, sizeof(header), 1, Foutput);
if(bit_pixel <= 8)
{
//color table
int colors_size = 4 * (1 << bit_pixel);
char *colors = malloc(colors_size);
fread(colors, 1, colors_size, Finput);
fwrite(colors, 1, colors_size, Foutput);
free(colors);
}
fread(pixels, 1, byte_size, Finput);
fwrite(pixels, 1, byte_size, Foutput);
free(pixels);
}
int main(void)
{
char input_name[] = "input.bmp";
char output_name[] = "output.bmp";
FILE *Finput = fopen(input_name, "rb");
if(!Finput)
{
fprintf(stderr, "\n ERROR: file %s\n", input_name);
exit(-1);
}
FILE *Foutput = fopen(output_name, "wb");
if(!Foutput)
{
fprintf(stderr, "\n ERROR: file %s\n", input_name);
fclose(Finput);
exit(-1);
}
if(getImageInfo(Finput, 0, 2) != 19778)
fprintf(stdout, "\n WARNING: wrong BMP signature!\n");
else
copyImageInfo(Finput, Foutput);
fclose(Foutput);
fclose(Finput);
return 0;
}
Upvotes: 1