Search code examples
c++imageimage-processingpgm

Writing .PGM image results in disoriented shape


I'm trying to read and re-write a PGM image, though it's resulting in disoriented shape. The right image is the original one, the left is the re-created one:

Example of problem

This is the code I'm using:

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>

using namespace std;

int main()
{
int row = 0, col = 0, num_of_rows = 0, max_val = 0;
stringstream data;
ifstream image ( "3.pgm" );

string inputLine = "";

getline ( image, inputLine );  // read the first line : P5
data << image.rdbuf();
data >> row >> col >> max_val;
cout << row << " " << col << " " << max_val << endl;
static float array[11000][5000] = {};
unsigned char pixel ;

for ( int i = 0; i < row; i++ )
{
    for ( int j = 0; j < col; j++ )
    {
        data >> pixel;
        array[j][i] = pixel;



    }
}

ofstream newfile ( "z.pgm" );
newfile << "P5 " << endl << row << " " << col << "   " << endl << max_val << endl;

for ( int i = 0; i < row; i++ )
{
    for ( int j = 0; j < col; j++ )
    {

        pixel = array[j][i];

        newfile << pixel;


    }

}

image.close();
newfile.close();
}

what am I doing wrong?

the original image header


Solution

  • @Lightness Races in Orbit is right. You need to read data as binary data. You also mixed up row and col: width is col, height is row. Also you don't need a stringstream.

    Open image as binary file:
    ifstream image("3.pgm", ios::binary);

    Read all the header info:
    image >> inputLine >> col >> row >> max_val;

    Create a row x col matrix:
    vector< vector<unsigned char> > array(row, vector<unsigned char>(col));

    Read in binary data:

    for (int i = 0; i < row; i++)
        for (int j = 0; j < col; j++)
            image.read(reinterpret_cast<char*>(&array[i][j]), 1);
    

    or

    for (int i = 0; i < row; i++)
        image.read(reinterpret_cast<char*>(&array[i][0]), col);
    

    Open output file, in binary mode:
    ofstream newfile("z.pgm", ios::binary);

    Write header info: newfile << "P5" << endl << col << " " << row << endl << max_val << endl;

    Write out binary data:

    for (int i = 0; i < row; i++)
        for (int j = 0; j < col; j++)
            newfile.write(reinterpret_cast<const char*>(&array[i][j]), 1);
    

    or

    for (int i = 0; i < row; i++)
        newfile.write(reinterpret_cast<const char*>(&array[i][0]), col);