3

I don't know how to save in lines 0 and 1 to create a figure. This is my code, which generates lines with zeros. I need to create a square or trianlge, or rectangle (doesn't matter). Just need to know how to do that properly and save to pbm (portable bitmap) as monochromatic image.

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

using namespace std;

int main()
{
ofstream file;

int width=5;
int height=5;
int tab [10][10];

file.open("graphics.pbm");
if(file.good() == true)
{
    file << "P1" << endl;
    file << "# comment" << endl;
    file << "10 10" << endl;

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

    for (int  i=0; i<width; i++)
    {
        for (int j=0; j<height; j++)
        {
            file << tab[i][j] << " ";
        }
    }

file.close();
}

return 0;
}

1 Answers1

1

Well you have some work to do... You need to specify a function for each geometry form which would fill your image.

Here an example which is more C++ like where a class Image handle the methods to compute the geometric forms such as makeFillCircle(). Image class also handles the PBM output. Remark how easy it is now to save it using std::ostream operator<< !

#include <vector>
#include <iostream>
#include <algorithm>

struct Point { 
    Point(int xx, int yy) : x(xx), y(yy) {} 
    int x; 
    int y; 
};

struct Image {
    int width;
    int height;
    std::vector<int> data; // your 2D array of pixels in a linear/flatten storage

    Image(size_t w, size_t h) : width(w), height(h), data(w * h, 0) {} // we fill data with 0s

    void makeFillCircle(const Point& p, int radius) {
        // we do not have to test every points (using bounding box)
        for (int i = std::max(0, p.x - radius); i < std::min(width-1, p.x + radius) ; i ++) {
            for (int j = std::max(0,p.y - radius); j < std::min(height-1, p.y + radius); j ++) {
                // test if pixel (i,j) is inside the circle
                if ( (p.x - i) * (p.x - i) + (p.y - j) * (p.y - j) < radius * radius ) {
                    data[i * width + j] = 1;  //If yes set pixel on 1 !
                }
            }
        }
    }
};

std::ostream& operator<<(std::ostream& os, const Image& img) {
    os << "P1\n" << img.width << " " << img.height << "\n";
    for (auto el : img.data) { os << el << " "; }
    return os;
}

int main() {
    Image img(100,100);
    img.makeFillCircle(Point(60,40), 30); // first big circle
    img.makeFillCircle(Point(20,80), 10); // second big circle
    std::cout << img << std::endl; // the output is the PBM file
}

Live Code

Result is :

two circles

And voilà... I let you the fun to create your own functions makeRectangle(), makeTriangle() for your needs ! That requires some little maths !

Edit BONUS

As asked in the comment, here a little member function which would save the image in a file. Add it in the Image class (you can also if you prefer have a free function outside the class). Since we have a ostream operator<< this is straightforward :

void save(const std::string& filename) {
    std::ofstream ofs;
    ofs.open(filename, std::ios::out);
    ofs << (*this);
    ofs.close();
}

An other way without modifying the code would be to catch the output of the program in a file with something like this on your terminal :

./main >> file.pgm

coincoin
  • 4,595
  • 3
  • 23
  • 47
  • Have no idea why debuger in Code Blocks give me errors. error: ‘el’ does not name a type error: expected primary-expression before ‘return’ error: expected ‘;’ before ‘return’ error: expected primary-expression before ‘return’ error: expected ‘)’ before ‘return’ –  Nov 07 '15 at 21:40
  • Because you did not include the flag `-std=c++11` or `-std=c++14`. You should add them :) – coincoin Nov 07 '15 at 21:42
  • Works great. I'm wondering how to save it as a pbm file to a hard drive. –  Nov 07 '15 at 21:54
  • @GallAnonim Added at the end my answer a bonus method to do that. – coincoin Nov 07 '15 at 22:01
  • Tried to save it using this: file.open("graphics.pbm"); but without success. –  Nov 07 '15 at 22:13
  • @GallAnonim in your main you should call : `img.save("graphics.pbm");` rather > – coincoin Nov 07 '15 at 22:14
  • freopen("output.pbm","w",stdout); std::cout << img << std::endl; // the output is the PBM file return 0; Solved the problem :) Big Thanks!!!!!!! –  Nov 07 '15 at 22:27
  • checked this void but gives me errors in debugger. In member function ‘void Image::save(const string&)’: error: cannot bind ‘std::basic_ostream’ lvalue to ‘std::basic_ostream&&’ initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits; _Tp = Image]’ –  Nov 08 '15 at 00:25
  • @GallAnonim Can you precise how do you call the save function please in your code ? – coincoin Nov 08 '15 at 13:34
  • freopen is the only way to change the narrow/wide orientation of a stream once it has been established by an I/O operation or by std::fwide. Solution: int main() { std::cout <<"Draw circles"; Image img(100,100); img.makeFillCircle(Point(60,40), 30); // first big circle img.makeFillCircle(Point(20,80), 10); // second big circle freopen("image.pbm","w",stdout); // save the stdout to the file std::cout << img << std::endl; // the output is the PBM file return 0; } –  Nov 16 '15 at 09:27