4

Trying to read and write to/from a PPM Image file (.ppm) in the only way I know how:

std::istream& operator >>(std::istream &inputStream, PPMObject &other)
{
    inputStream.seekg(0, ios::end);
    int size = inputStream.tellg();
    inputStream.seekg(0, ios::beg);

    other.m_Ptr = new char[size];


    while (inputStream >> other.m_Ptr >> other.width >> other.height >> other.maxColVal)
    {
        other.magicNum = (string) other.m_Ptr;
    }

    return inputStream;
}

My values correspond to the actual file. So I cheerfully attempt to write the data:

std::ostream& operator <<(std::ostream &outputStream, const PPMObject &other)
{
    outputStream << "P6"     << " "
        << other.width       << " "
        << other.height      << " "
        << other.maxColVal   << " "
       ;

    outputStream << other.m_Ptr;

    return outputStream;
}

I am making sure to open the file using std::ios::binary for both reading and writing:

int main ()
{
    PPMObject ppmObject = PPMObject();
    std::ifstream image;
    std::ofstream outFile;

    image.open("C:\\Desktop\\PPMImage.ppm", std::ios::binary);
    image >> ppmObject;

    image.clear();
    image.close();

    outFile.open("C:\\Desktop\\NewImage.ppm", std::ios::binary);
    outFile << ppmObject;

    outFile.clear();
    outFile.close();

    return 0;
}

Logic Error:

I am only writing a portion of the image. There is no problem with the header or opening the file manually.

Class public member variables:

The m_Ptr member variable is a char * and height, width maxColrVal are all integers.

Attempted Solution:

Using inputStream.read and outputStream.write to read and write data but I don't know how and what I have tried doesn't work.

Since my char * m_Ptr contains all of the pixel data. I can iterate through it:

for (int I = 0; I < other.width * other.height; I++) outputStream << other.m_Ptr[I];

But this causes a run-time error for some reason..

user4640007
  • 97
  • 1
  • 2
  • 7

1 Answers1

7

Based on http://fr.wikipedia.org/wiki/Portable_pixmap, P6 is a binary image. This reads a single image. Note that no checking is performed. This needs to be added.

std::istream& operator >>(std::istream &inputStream, PPMObject &other)
{
    inputStream >> other.magicNum;
    inputStream >> other.width >> other.height >> other.maxColVal;
    inputStream.get(); // skip the trailing white space
    size_t size = other.width * other.height * 3;
    other.m_Ptr = new char[size];
    inputStream.read(other.m_Ptr, size);
    return inputStream;
}

This code writes a single image.

std::ostream& operator <<(std::ostream &outputStream, const PPMObject &other)
{
    outputStream << "P6"     << "\n"
        << other.width       << " "
        << other.height      << "\n"
        << other.maxColVal   << "\n"
       ;
    size_t size = other.width * other.height * 3;
    outputStream.write(other.m_Ptr, size);
    return outputStream;
}

m_Ptr contains only the RGB pixel values.

I tested the code on an image I downloaded from the web (http://igm.univ-mlv.fr/~incerti/IMAGES/COLOR/Aerial.512.ppm) and using the following structure PPMObject it worked.

struct PPMObject
{
  std::string magicNum;
  int width, height, maxColVal;
  char * m_Ptr;
};
chmike
  • 20,922
  • 21
  • 83
  • 106
  • Nothing is read into other.magicNum when extracting from inputStream. – user4640007 Mar 06 '15 at 10:36
  • Is it declared as a string ? It should because we want to read "P6". – chmike Mar 06 '15 at 10:40
  • If it is an Integer, the compiler is happy. But nothing is read into the member variables. – user4640007 Mar 06 '15 at 10:44
  • That is normal because the file starts with the string "P6". Have you displayed the head of the file ? – chmike Mar 06 '15 at 10:48
  • Does your file really start with "P6" ? – chmike Mar 06 '15 at 10:52
  • Yes. It seems as though I need to allocate my m_Ptr first, then read data from inputStream. Yes I have displayed the header (otherwise the file will not open manually). – user4640007 Mar 06 '15 at 10:53
  • I tested the above code with the image for which I provide the link. It worked. I checked the binary content of the two files. There was a bug in the code to read a ppm image that I fixed. Could you test my code with my image please ? – chmike Mar 06 '15 at 11:12
  • The code as is, for the inputStream results in compilation error..I am not using C++11 or variations of the kind. The magicNum must be an integer for my compiler to run the code. Again, as is, there is no data extracted from inputStream into the member variables.. – user4640007 Mar 06 '15 at 11:30
  • If I add your size calculation (which seems to be the only difference) and overrite my allocation, the new image is a large grey chunk where the image should be. Not a black and white of the actual image -- just grey. – user4640007 Mar 06 '15 at 11:40
  • My code is not C++11. magicNum must be a string. It is not normal that you get a compilation error with my code. There must be another problem. What compiler are you using ? Could you give the error message ? Could you separate reading magicNum and the other values in two lines as I did in my code ? – chmike Mar 06 '15 at 13:29