c++bitmappbm

How to create in ascii square, triangle, rectangle or circle with C++ and save it to portable bitmap file?


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;
}

Solution

  • 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