简体   繁体   中英

How to read and write a ppm file?

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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM