Home > Software engineering >  How to read binary data from file after read sucessfully the ascii header in the file
How to read binary data from file after read sucessfully the ascii header in the file

Time:04-18

I am trying read the Netpbm image format, following the specification explained expected result

but I am getting this result instead:

enter image description here

For the binary format for PGM and PPM images, when I try open the image, I got a segmentation fault error when I try increment count at some point in the execution of the loop. I think somehow the size of vector<int> p is ending bigger than the expected product width x height.

the code for the PGM format:

if(*this->magicNumber == "P5") {
  this->pixels = new Matrix<int>(this->width, this->height);

  vector<int> p;
  while(getline(file, line_pixels)) {
    if(line_pixels.size() > 0 && line_pixels.at(0) != '#') {
      string number;
      stringstream ss(line_pixels);
      while(getline(ss, number)) {
        unsigned char data = (unsigned char)number.at(0);
        p.push_back((int)data);
      }
    }
  }

  int count = 0;
  for(int i=0; i<height; i  ) {
    for(int j=0; j<width; j  ) {
      this->pixels->set(i, j, p[count  ]);
    }
  }
}

the code for the PPM format:

if(*this->magicNumber == "P6") {
  this->pixels = new Matrix<struct Pixel>(this->width, this->height);

  vector<int> p;
  while(getline(file, line_pixels)) {
    if(line_pixels.size() > 0 && line_pixels.at(0) != '#') {
      string byte;
      stringstream ss(line_pixels);
      while(getline(ss, byte)) {
        unsigned char data = (unsigned char)byte.at(0);
        p.push_back((int)data);
      }
    }
  }

  int count = 0;
  for(int i=0; i<height; i  ) {
    for(int j=0; j<width; j  ) {
      struct Pixel pixel;
      pixel.r = p[count  ];
      pixel.g = p[count  ];
      pixel.b = p[count  ];
      this->pixels->set(i, j, pixel);
    }
  }
}

Anyone can give a hint of what I am doing wrong here?

CodePudding user response:

while(getline(file, line_pixels)) {

std::getline reads from the input stream until a newline character is read.

A file is a file. It contains bytes. Whether you believe the file contains text, or binary, is purely a matter of interpretation.

Text lines are terminated by a newline character. That's what std::getline does: it reads bytes from a file until it reads a newline character. Whatever gets read, goes into the std::string parameter.

This would be very confusing if your intent is to read some binary data, like an image. A byte containing the same value as a newline character can occur naturally in a binary file like an image file, representing the appropriate pixel values. Using std::getline to read non-textual data always ends in tears.

This would only make sense in one situation: if you already know, in advance, the the binary data you intend to read here ends with a byte that just happens to be the newline character, and that newline character appears nowhere else.

But, of course, in an image file, you have no such guarantees, whatsoever.

When reading image data you are typically expected to read a specific amount of bytes from the file.

Here, you know, in advance, the size of your image and its format. Based on that you can calculate using a simple mathematical formula how many bytes you expect to read.

And that happens to be what std::istream's read() method does: read the specific number of bytes from a file. This link provides more information.

You need to replace all shown code that improperly uses getline with one that uses read().

  • Related