Reading/Writing PPM image C++, new image is broken

1.4k views Asked by At

I found some C++ code here on SO for reading / writing images. I would like to improve it so I can rotate etc. images. However, at the beginning I have some problems. When I write the image, it seems that my read function read only a piece of it, since it writes to file only a piece of the original image. Please see my code and input, output images.

    #include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main(int argc, char **argv)
{
    ifstream in;
    in.open("OldImage.ppm", std::ios::binary);

    ofstream out;

    std::string magic_number;
    int width, height, maxColVal, i, j;

    in >> magic_number;
    in >> width >> height >> maxColVal;
    in.get();

    char **image;
    image = new char* [width];

    for(i=0; i<width; i++)
    {
        image[i] = new char [height];

        for(j=0; j<height; j++)
        {
            in >> image[i][j];
        }
    }

    out.open("NewImage.ppm", std::ios::binary);
    out << "P3"     << "\n"
        << width       << " "
        << height      << "\n"
        << maxColVal   << "\n"
        ;

    for(i=0; i<width; i++)
    {
        for(j=0; j<height; j++)
        {
            out << image[i][j];
        }
    }

    in.clear();
    in.close();

    out.clear();
    out.close();

    return 0;
}

Input image: https://www.dropbox.com/s/c0103eyhxzimk0j/OldImage.ppm?dl=0

Output image: https://www.dropbox.com/s/429i114c05gb8au/NewImage.ppm?dl=0

2

There are 2 answers

0
meuh On

According to this doc there are 2 forms of ppm image file: raw and plain. You seem to be assuming the normal raw format but you are using magic number P3 which is for plain ppm. Try P6.

Also, your height and width loops should be the other way round, but this doesnt affect the result. Presumably it is part of your code to rotate the image.

1
anatolyg On

ppm files have 3 values (R, G and B) for each pixel. Your code assumes there is only 1 value (intensity?). Try reading and writing pgm files (with "magic_number" equal to P2).

Alternatively, read all the 3 values for each pixel:

typedef char (*row_ptr)[3];
// I don't know how to express the following without a typedef
char (**image)[3] = new row_ptr[height];
...
for(i=0; i<height; i++)
{
    image[i] = new char[width][3];

    for(j=0; j<width; j++)
    {
        for(colour=0; colour<3; colour++)
        {
            in >> image[i][j][colour];
        }
    }
}

Note that I switched the places of width and height, so the code matches the order of the pixels in the file. It would also be good to use meaningful names like x and y for coordinates, instead of confusing names like i or j.