0

I am trying implement a c++ class to read a PGM file. I can read the header of file (magic number, width, height and max_value) without problem, but when I try read the pixel data, I got an error related to the conversion of the string with stoi.

The code I got right now:

        while(getline(file, line_pixels)) {
            if(line_pixels.size() > 0 && line_pixels.at(0) != '#') {
                std::stringstream ss(line_pixels);
                std::string value;
                while(getline(ss, value, ' ')) {
                    pixel p;
                    p.r = p.g = p.b = stoi(value) / this->max_value;
                    v.emplace_back(p);
                }
            }
        }

The error is on the line:

                    p.r = p.g = p.b = stoi(value) / this->max_value;

The program is having issues when a space is read (it should skip those). The following code is a program that can be compiled to reproduce the error:

#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>

void read(std::string file_name);

struct Pixel {
  float r, g, b;
};
typedef struct Pixel pixel;

class Image {
private:
    int max_value;
    std::vector<std::vector<pixel>> pixels;
public:
    void read(std::string file_name) {
        std::ifstream file(file_name);
        std::string line_one, line_two, line_three, line_pixels;

        char magicNumber;
        std::string width, height;

        while(getline(file, line_one)) {
            if(line_one.size() > 0 && line_one.at(0) != '#') {
                magicNumber = line_one.at(1);
                break;
            }
        }

        while(getline(file, line_two)) {
            if(line_two.size() > 0 && line_two.at(0) != '#') {
                std::stringstream ss(line_two);
                getline(ss, width, ' ');
                getline(ss, height, ' ');
                break;
            }
        }

        while(getline(file, line_three)) {
            if(line_three.size() > 0 && line_three.at(0) != '#') {
                this->max_value = stoi(line_three);
                break;
            }
        }

        if(magicNumber == '2') {
            std::vector<pixel> v;

            while(getline(file, line_pixels)) {
                if(line_pixels.size() > 0 && line_pixels.at(0) != '#') {
                    std::stringstream ss(line_pixels);
                    std::string value;
                    while(getline(ss, value, ' ')) {
                        pixel p;
                        p.r = p.g = p.b = stoi(value) / this->max_value;
                        v.emplace_back(p);
                    }
                }
            }

            int h = stoi(height), w = stoi(width);

            int index = 0;
            for(int i=0; i<h; i++) {
                std::vector<pixel> row;
                for(int j=0; j<w; j++) row.push_back(v[index++]);
                this->pixels.push_back(row);
            }
        }
    }
};

int main(int argc, char ** argv) {
    Image img;
    img.read("lena.ascii.pgm");
    return 0;
}

To test this program, I am using this pgm image. Anyone can tell me what's wrong here?

Kleber Mota
  • 8,521
  • 31
  • 94
  • 188
  • `getline(ss, value, ' ')` does not skip all spaces, it reads a number and then skips **one** space, but your file has multiple spaces between the numbers. I can't see any reason not to use `ss >> n` where `n` is an integer variable. That will skip as many spaces as necessary and it will do the integer conversion for you. – john Dec 14 '22 at 14:56

1 Answers1

0

Here's the fix for skipping spaces (I've only included the block that reads the width and height) for example:

     while (getline(file, line_two)) {
        if (line_two.size() > 0 && line_two.at(0) != '#') {
            std::stringstream ss(line_two);
            getline(ss, width, ' ');
            while (ss.peek() == ' ') // skip spaces
                ss.get();
            getline(ss, height, ' ');
            break;
        }
    }

And then to resolve the stoi issue, that is again because you have multiple spaces between the actual values, so the parsed value is empty, to fix you can simply check for a none empty string before passing it to stoi like this:

       while (getline(file, line_pixels)) {
            if (line_pixels.size() > 0 && line_pixels.at(0) != '#') {
                std::stringstream ss(line_pixels);
                std::string value;
                while (getline(ss, value, ' ')) {
                    if (value.size() > 0)
                    {
                        pixel p;
                        p.r = p.g = p.b = stoi(value) / this->max_value;
                        v.emplace_back(p);
                    }
                }
            }
        }
user20716902
  • 861
  • 1
  • 14