I'd like to do this in a platform independant way, and I know libpng is a possibility, but I find it hard to figure out how. Does anyone know how to do this in a simple way?
Most image editors, like GIMP, will save jpg images with a default quality parameter of 80 or 90, but the user can tune the quality parameter if required. I’ve used a quality parameter of 100 in all examples from this article. Once you are done with an image, you can release the memory used to store its data with the stbi_image_free function.
9. width X height gray values, each in ASCII decimal, between 0 and the specified maximum value, separated by whitespace, in raster format, from top to bottom. First, save the file as “ write_pgm_img.c “. The PGM image will be saved as pgmimg.pgm.
In this article, we will discuss the C++ buffer in detail. In a normal scenario, a buffer gets created when a file is opened and buffer gets flushed when the file is closed. In C++ buffer can be created by the allocation of memory as shown below. Similarly, when the memory allocated has to be freed, the following format can be used.
Saving a 2D array in C as images in PNG, JPG or other formats would need a lot of effort to encode the data in the specified format before writing to a file. However, Netpbm format offers a simple solution with easy portability. A Netpbm format is any graphics format used and defined by the Netpbm project.
There is a C++ wrapper for libpng
called Png++
. Check it here or just google it.
They have a real C++ interface with templates and such that uses libpng
under the hood. I've found the code I have written quite expressive and high-level.
Example of "generator" which is the heart of the algorithm:
class PngGenerator : public png::generator< png::gray_pixel_1, PngGenerator>
{
typedef png::generator< png::gray_pixel_1, PngGenerator> base_t;
public:
typedef std::vector<char> line_t;
typedef std::vector<line_t> picture_t;
PngGenerator(const picture_t& iPicture) :
base_t(iPicture.front().size(), iPicture.size()),
_picture(iPicture), _row(iPicture.front().size())
{
} // PngGenerator
png::byte* get_next_row(size_t pos)
{
const line_t& aLine = _picture[pos];
for(size_t i(0), max(aLine.size()); i < max; ++i)
_row[i] = pixel_t(aLine[i] == Png::White_256);
// Pixel value can be either 0 or 1
// 0: Black, 1: White
return row_traits::get_data(_row);
} // get_next_row
private:
// To be transformed
const picture_t& _picture;
// Into
typedef png::gray_pixel_1 pixel_t;
typedef png::packed_pixel_row< pixel_t > row_t;
typedef png::row_traits< row_t > row_traits;
row_t _row; // Buffer
}; // class PngGenerator
And usage is like this:
std::ostream& Png::write(std::ostream& out)
{
PngGenerator aPng(_picture);
aPng.write(out);
return out;
}
There were some bits still missing from libpng
(interleaving options and such), but frankly I did not use them so it was okay for me.
I'd say libpng is still the easiest way. There's example read -> process -> write png program, it is fairly simple once you strip the error handling (setjmp/longjmp/png_jmpbuf) stuff. It doesn't get simpler than that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With