I try to read a ppm file aand create a new one identical. But when I open them with GIMP2 the images are not the same.
Where is the problem with my code ?
int main()
{
FILE *in, *out;
in = fopen("parrots.ppm","r");
if( in == NULL )
{
std::cout<<"Error.\n";
return 0;
}
unsigned char *buffer = NULL;
long size = 0;
fseek(in, 0, 2);
size = ftell(in);
fseek(in, 0, 0);
buffer = new unsigned char[size];
if( buffer == NULL )
{
std::cout<<"Error\n";
return 0;
}
if( fread(buffer, size, 1, in) < 0 )
{
std::cout<<"Error.\n";
return 0 ;
}
out = fopen("out.ppm","w");
if( in == NULL )
{
std::cout<<"Error.\n";
return 0;
}
if( fwrite(buffer, size, 1, out) < 0 )
{
std::cout<<"Error.\n";
return 0;
}
delete[] buffer;
fcloseall();
return 0;
}
Before that I read the ppm file in a structure and when I wrote it I get the same image but the green was more intense than in the original picture. Then I tried this simple reading and writing but I get the same result.
int main()
Missing includes.
FILE *in, *out;
C style I/O in a C++ program, why? Also, declare at point of initialization, close to first use.
in = fopen("parrots.ppm","r");
This is opening the file in text mode, which is most certainly not what you want. Use "rb"
for mode.
unsigned char *buffer = NULL;
Declare at point of initialization, close to first use.
fseek(in, 0, 2);
You are supposed to use SEEK_END
, which is not guaranteed to be defined as 2.
fseek(in, 0, 0);
See above, for SEEK_SET
not guaranteed to be defined as 0.
buffer = new unsigned char[size];
if( buffer == NULL )
By default, new
will not return a NULL
pointer, but throw a std::bad_alloc
exception. (With overallocation being the norm on most current operating systems, checking for NULL
would not protect you from out-of-memory even with malloc()
, but good to see you got into the habit of checking anyway.)
C++11 brought us smart pointers. Use them. They are an excellent tool to avoid memory leaks (one of the very few weaknesses of C++).
if( fread(buffer, size, 1, in) < 0 )
Successful use of fread
should return the number of objects written, which should be checked to be equal the third parameter (!= 1
), not < 0
.
out = fopen("out.ppm","w");
Text mode again, you want "wb"
here.
if( fwrite(buffer, size, 1, out) < 0 )
See the note about the fread
return value above. Same applies here.
fcloseall();
Not a standard function. Use fclose( in );
and fclose( out );
.
A C++11-ified solution (omitting the error checking for brevity) would look somewhat like this:
#include <iostream>
#include <fstream>
#include <memory>
int main()
{
std::ifstream in( "parrots.ppm", std::ios::binary );
std::ofstream out( "out.ppm", std::ios::binary );
in.seekg( 0, std::ios::end );
auto size = in.tellg();
in.seekg( 0 );
std::unique_ptr< char[] > buffer( new char[ size ] );
in.read( buffer.get(), size );
out.write( buffer.get(), size );
in.close();
out.close();
return 0;
}
Of course, a smart solution would do an actual filesystem copy, either through Boost.Filesystem or the standard functionality (experimental at the point of this writing).