I'm porting some C code that loads sprites from files containing multiple bitmaps. Basically the code fopens the file, fgetcs some header info, then freads the bitmap data. I can see that the fgetcs are returning proper data, but the outcome of the fread is null. Here's the code - fname does exist, the path is correct, fil is non-zero, num is the number of sprites in the file (encoded into the header, little-endian), pak is an array of sprites, sprite is a typedef of width, height and bits, and new_sprite inits one for you.
FILE *fil;
uint8 *buffu;
uint8 read;
int32 x,num;
int32 w,h,c;
fil = fopen(fname, "rb");
if (!fil) return NULL;
num = fgetc(fil);
num += fgetc(fil)*256;
if (num > max) max = num;
for (x=0;x<max;x++) {
// header
w=fgetc(fil);
w+=fgetc(fil)*256;
h=fgetc(fil);
h+=fgetc(fil)*256;
fgetc(fil); // stuff we don't use
fgetc(fil);
fgetc(fil);
fgetc(fil);
// body
buffu = (uint8*)malloc(w * h);
read=fread(buffu,1,w*h,fil);
pak->spr[x]=new_sprite(w,h);
memcpy(pak->spr[x]->data, buffu, w*h);
// done
free(buffu);
}
I've stepped through this code line by line, and I can see that w and h are getting set up properly, and read=4096, which is the right number of bits. However, buffer is "" after the fread, so of course memcpy does nothing useful and my pak is filled with empty sprites.
My apologies for what is surely a totally noob question, but I normally use Cocoa so this pure-C file handling is new to me. I looked all over for examples of fread, and they all look like the one here - which apparently works fine on Win32.
Since fgetc seems to work, you could try this as a test
int each;
int byte;
//body
buffu = malloc(w * h);
for (each = 0; each < w*h; each++) {
byte = fgetc(fil);
if ( byte == EOF) {
printf("End of file\n");
break;
}
buffu[each] = (uint8)byte;
printf ("byte: %d each: %d\n", byte, each);
}
pak->spr[x]=new_sprite(w,h);
memcpy(pak->spr[x]->data, buffu, w*h);
// done
You say:
However, buffer is "" after the fread, so of course memcpy does nothing useful
But that is not true at all. memcpy() is not a string function, it will copy the requested number of bytes. Every time. If that isn't "useful", then something else is wrong.
Your buffer, when treated as a string (which it is not, it's a bunch of binary data) will look like an empty string if the first byte happens to be 0. The remaining 4095 bytes can be whatever, to C's string printing functions it will look "empty".
I have a very simple function that saves a PPM image:
void WriteCImage(CImage *cimg, char *filename)
{
FILE *fp;
int i,n;
fp = fopen(filename,"w");
fprintf(fp,"P6\n");
fprintf(fp,"%d %d\n",cimg->C[0]->ncols,cimg->C[0]->nrows);
fprintf(fp,"255\n");
n = cimg->C[0]->ncols*cimg->C[0]->nrows;
for (i=0; i < n; i++)
{
fputc(cimg->C[0]->val[i],fp);
fputc(cimg->C[1]->val[i],fp);
fputc(cimg->C[2]->val[i],fp);
}
fclose(fp);
}
as you can see, this function receives a matrix (in CImage format) and writes the image data in the ASCII file. It seems correct, but every time I copy a grayscale image to a PPM image I have problems. Look at the code:
//that's a PGM grayscale image
gt = ReadImage(argv[1]);
//creating an RGB image with same dimensions of the PGM image
nwcimg = CreateCImage(gt->nrows,gt->ncols);
n=gt->nrows*gt->ncols;
//iterate through the PGM image
for(index=0;index<n;index++)
{
// just a copy of the grayscale image value to all 3 layeres
//of the PPM (RGB) image
nwcimg->C[0]->val[index]=gt->val[index];
nwcimg->C[1]->val[index]=gt->val[index];
nwcimg->C[2]->val[index]=gt->val[index];
}
WriteCImage(nwcimg,"gt-copied.ppm");
DestroyCImage(&nwcimg);
DestroyImage(>);
what problem i have? well, the code seems correct and simple. But when the cimage matrix/vector is written as a file, i can see that the two pictures are not the same. Seems like the pixels of the PGM image are 'shifted' or 'mirrored' in the copied image.
You can see the Image File and The RGB copy
Shouldn't
for(index=0;index<n;index++) {
nwcimg->C[0]->val[index]=gt->val[index];
nwcimg->C[1]->val[index]=gt->val[index];
nwcimg->C[2]->val[index]=gt->val[index];
be
for(index=0;index<n;index) {
nwcimg->C[0]->val[index]=gt->val[index++];
nwcimg->C[1]->val[index]=gt->val[index++];
nwcimg->C[2]->val[index]=gt->val[index++];
? The for loop in your file writer writes 3 bytes per loop. The loop in your reader consumes only 1 byte per loop then copies it into three separate arrays.
I want to implement a simple command line based image editor. The program will
provide a text based menu, which provides several functions for user to manipulate a windows
bitmap (.bmp) image file. The menu will include load image, rotate image, mirror image, save image
and quit options. The load image option will be used to open and read pixel values from a given
bitmap file. This option will also print out the basic properties, such as dimensions and total size, of the given file. The rotate and mirror options will manipulate previously read pixel values. An image
must be loaded before applying these options. The save option will save the pixel values in the
memory to a bitmap file with a given filename.
Which approach do you recommend for me about this project and about bitmap file structure?
It would be very appreciated if you give me advice even about one particular topic for example load the file.
libbmp will make your program all but trivial to implement.
If you really want to use C then try the libbmp library http://code.google.com/p/libbmp/
However, I'd recommend using C#, then the task would be trivial with the System.Drawing namespace.
This function is used for loading a bmp file to memory.
you have to declare first a header file with bmp structure
BMP* load_BMP(char *filename);
BMP *bmp; // local integer for file loaded
FILE *in; // pointer for file opening
int rowsize;
int row, col, color, i;
unsigned char b;
in=fopen(filename,"rb"); // open binary file
if (in==NULL)
{
printf("Problem in opening file %s.\n",filename);
return NULL;
}
bmp=(BMP*) malloc(sizeof(BMP)); //memory allocation
if (bmp==NULL)
{
printf("Not enough memory to load the image.\n");
return NULL;
}
fread(bmp->BM,2,1,in);
if (bmp->BM[0]!='B' || bmp->BM[1]!='M')
{
printf("Bad BMP image file.\n");
free(bmp);
return NULL;
}
fread(&bmp->fileSize,4,1,in);
fread(&bmp->Reserved1,2,1,in);
fread(&bmp->Reserved2,2,1,in);
fread(&bmp->imageOffset,4,1,in);
fread(&bmp->imageHeaderSize,4,1,in);
fread(&bmp->imageWidth,4,1,in);
rowsize=4*((3*bmp->imageWidth+3)/4); //calculate rowsize because of padding
fread(&bmp->imageHeight,4,1,in);
fread(&bmp->colorPlanes,2,1,in);
fread(&bmp->compressionMethod,4,1,in);
fread(&bmp->imageSize,4,1,in);
fread(&bmp->hPPM,4,1,in);
fread(&bmp->vPPM,4,1,in);
fread(&bmp->paletteColors,4,1,in);
fread(&bmp->paletteImportantColors,4,1,in);
bmp->data=(unsigned char*) malloc(bmp->imageSize); //allocate memory for image data array
if (bmp->data==NULL)
{
printf("There is not enough memory to load the image\n");
free(bmp);
return NULL;
}
for(row=0;row<bmp->imageHeight;row++) //read picture data
{
for(col=0;col<bmp->imageWidth;col++)
for(color=0;color<=2;color++)
fread(&bmp->data[row*rowsize+3*col+color],
sizeof(unsigned char),1,in);
//read extra bytes for end of row padding
for(i=0;i<rowsize-3*bmp->imageWidth;i++)
fread(&b,1,1,in);
}
fclose(in);
return bmp;
}
I am writing a C program, which will retrieve the information (header information, pixel information) from a bitmap image, and use that information to create another bitmap image (the new image will obviously be same as the original).
The problem is that, in some cases, extra bytes get added (on their own) to the new image, due to which the image is not formed properly.
In another case, some bytes get missing in the new image, due to which image formation itself fails.
(This happens while writing the pixel information. the bitmap header information gets written properly to the new file.)
I have debugged the code but I couldn't find out what is causing this.
I'll be glad if somebody could tell me what the error is.
//creating a bitmap file
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<math.h>
long extract(FILE *,long ,int );
long extract(FILE *fp1,long offset,int size)
{
unsigned char *ptr;
unsigned char temp='0';
long value=0L;
int i;
//to initialize the ptr
ptr=&temp;
//sets the file pointer at specific position i.e. after the offset
fseek(fp1,offset,SEEK_SET);
//now fgetcing (size) values starting from the offset
for(i=1;i<=size;i++)
{
fread(ptr,sizeof(char),1,fp1);
value=(long)(value+(*ptr)*(pow(256,(i-1)))); //combining the values one after another in a single variable
}
return value;
}
int main()
{
int row,col;
int i,j,k;
int dataoffset,offset;
char magicnum[2];
FILE *fp1,*fp4;
clrscr();
if((fp1=fopen("stripes.bmp","rb"))==NULL)
{
printf("\a\nCant open the image.\nSystem is exiting.");
exit(0);
}
if((fp4=fopen("op.bmp","a"))==NULL)
{
printf("\n\aError while creating a file.\nSystem is exiting ..... ");
exit(0);
}
fputc((int)extract(fp1,0L,1),fp4);
fputc((int)extract(fp1,1L,1),fp4);
fputc((int)extract(fp1,2L,1),fp4);
fputc((int)extract(fp1,3L,1),fp4);
fputc((int)extract(fp1,4L,1),fp4);
fputc((int)extract(fp1,5L,1),fp4);
fputc((int)extract(fp1,6L,1),fp4);
fputc((int)extract(fp1,7L,1),fp4);
fputc((int)extract(fp1,8L,1),fp4);
fputc((int)extract(fp1,9L,1),fp4);
fputc((int)extract(fp1,10L,1),fp4);
fputc((int)extract(fp1,11L,1),fp4);
fputc((int)extract(fp1,12L,1),fp4);
fputc((int)extract(fp1,13L,1),fp4);
fputc((int)extract(fp1,14L,1),fp4);
fputc((int)extract(fp1,15L,1),fp4);
fputc((int)extract(fp1,16L,1),fp4);
fputc((int)extract(fp1,17L,1),fp4);
fputc((int)extract(fp1,18L,1),fp4);
fputc((int)extract(fp1,19L,1),fp4);
fputc((int)extract(fp1,20L,1),fp4);
fputc((int)extract(fp1,21L,1),fp4);
fputc((int)extract(fp1,22L,1),fp4);
fputc((int)extract(fp1,23L,1),fp4);
fputc((int)extract(fp1,24L,1),fp4);
fputc((int)extract(fp1,25L,1),fp4);
fputc((int)extract(fp1,26L,1),fp4);
fputc((int)extract(fp1,27L,1),fp4);
fputc((int)extract(fp1,28L,1),fp4);
fputc((int)extract(fp1,29L,1),fp4);
fputc((int)extract(fp1,30L,1),fp4);
fputc((int)extract(fp1,31L,1),fp4);
fputc((int)extract(fp1,32L,1),fp4);
fputc((int)extract(fp1,33L,1),fp4);
fputc((int)extract(fp1,34L,1),fp4);
fputc((int)extract(fp1,35L,1),fp4);
fputc((int)extract(fp1,36L,1),fp4);
fputc((int)extract(fp1,37L,1),fp4);
fputc((int)extract(fp1,38L,1),fp4);
fputc((int)extract(fp1,39L,1),fp4);
fputc((int)extract(fp1,40L,1),fp4);
fputc((int)extract(fp1,41L,1),fp4);
fputc((int)extract(fp1,42L,1),fp4);
fputc((int)extract(fp1,43L,1),fp4);
fputc((int)extract(fp1,44L,1),fp4);
fputc((int)extract(fp1,45L,1),fp4);
fputc((int)extract(fp1,46L,1),fp4);
fputc((int)extract(fp1,47L,1),fp4);
fputc((int)extract(fp1,48L,1),fp4);
fputc((int)extract(fp1,49L,1),fp4);
fputc((int)extract(fp1,50L,1),fp4);
fputc((int)extract(fp1,51L,1),fp4);
fputc((int)extract(fp1,52L,1),fp4);
fputc((int)extract(fp1,53L,1),fp4);
//setting the file pointer at the beginning
rewind(fp1);
/*CHECKING WHETHER THE FILE IS IN BMP FORMAT OR NOT, WE CHECK THE MAGIC NUMBER OF THE FILE, MAGIC NUMBER'S OFFSET IS 0 i.e. IT'S STORED AT THE FRONT OF THE IMAGE, AND THE SIZE IS 2*/
//at first extracting the magic number
for(i=0;i<2;i++)
{
magicnum[i]=(char)extract(fp1,i,1);
}
//now checking
if((magicnum[0]=='B') && (magicnum[1]=='M'))
;
else
{
printf("\aThe image is not a bitmap image.\nSystem is exiting ... ");
exit(0);
}
//storing the header information
//get the starting position or offset of the data(pixel)
dataoffset=(int)extract(fp1,10,4);
//get the number of rows
row=(int)extract(fp1,22,4);
//get the number of columns
col=(int)extract(fp1,18,4);
//storing the data
offset=dataoffset;
for(j=0;j<col;j++)
{
for(k=0;k<row;k++)
{
for(i=0;i<=2;i++)
{
fputc((int)extract(fp1,offset++,1),fp4);
}
}
}
fcloseall();
return 0;
}
Make sure you open the output file in binary mode as well.
If you don't do that, the byte value corresponding to '\n' may be expanded to carriage return and line feed.
Consider this line:
value=(long)(value+(*ptr)*(pow(256,(i-1))));
pow is a floating point function returning a double. This means that (*ptr) is implicitly casted to double. The whole expression (value+(*ptr)*(pow(256,(i-1)))) will be a double. Now this can be larger than 2147483647 which is the largest number a long can hold (on most common 32-bit platforms), and the result when converting an out of range double to long is undefined. See what happens on this example:
#include <stdio.h>
int main(int argc, char **argv) {
int i;
for (i = 0; i < 10; i++) {
double d = 2147483647.0d + i;
printf("double=%f long=%ld\n", d, (long)d);
}
return 0;
}
Here is the output when I run it on my system: (hidden in case you want to guess or test it yourself first):
double=2147483647.000000 long=2147483647
double=2147483648.000000 long=-2147483648
double=2147483649.000000 long=-2147483648
double=2147483650.000000 long=-2147483648
double=2147483651.000000 long=-2147483648
double=2147483652.000000 long=-2147483648
double=2147483653.000000 long=-2147483648
double=2147483654.000000 long=-2147483648
double=2147483655.000000 long=-2147483648
double=2147483656.000000 long=-2147483648
One way to fix it would be to change it to unsigned long instead.
Personally I'd use 1 << (8*(i-1)) instead of pow to avoid messing with floating point, but there is lots of other things that I'd do very different too, but that is probably out of scope for this question (might be a question for the code review site).
I want to delete a string from a particular position in the file. Is thre a function to do that?
Can I delete last line of a file through a function?
You have two option
To read whole file, remove what you need and write it back
If the file is big, read file sequentially, remove given part, and move content after that forward
No there is no such function that will let you do this directly on a file.
You should load up the file content in memory and modify there and write back to file.
I don't feel like looking up all the io functions, so here's pseudo-c on how to implement option 2 of ArsenMkrt's answer
char buffer[N]; // N >= 1
int str_start_pos = starting position of the string to remove
int str_end_pos = ending position of the string to remove
int file_size = the size of the file in bytes
int copy_to = str_start_pos
int copy_from = str_end_pos + 1
while(copy_from < file_size){
set_file_pos(file, copy_from)
int bytes_read = read(buffer, N, file)
copy_from += bytes_read
set_file_pos(file, copy_to)
write(buffer, file, bytes_read)
copy_to += bytes_read
}
truncate_file(file,file_size - (str_end_pos - str_start_pos + 1))
something to that effect