Clone wiki

pngxx / saving

Saving JPEG and PNG images

To save a PNG or JPEG image using pngxx or jpegxx respectively, you must be able to present your raster as a pair of iterators over the underlying bytes.

The imagexx library provides functionality that allows you to create such iterators for your own image class very easily.

Here, I will assume that you have managed to attain a pair of iterators delimiting the raster's bytes.

pngxx and jpegxx each provide three overloads of a write_image() function that allow you to save the image:

  • to a file (given its name)
  • to a standard C++ std::ostream
  • via an output iterator

Constructing a raster_details object

First, we must create an imagexx::raster_details object that describes the raster we will be saving:

#include <imagexx/raster_details.hpp>
#include <pngxx/write.hpp>

std::size_t width = 1024; // the width of the raster (pixels)
std::size_t height = 768; // the height of the raster (pixels)
imagexx::pixel_format fmt = imagexx::rgba; // the type of pixel

imagexx::raster_details d(fmt, width, height);

fmt can be any one of:

  • imagexx::grey
  • imagexx::grey_alpha
  • imagexx::rgb
  • imagexx::rgba

grey_alpha and rgba aren't supported by jpegxx because JPEG compression wasn't designed for images with transparency (an exception will be thrown in the call to jpegxx::write_image() if you try to save an image whose pixels have an alpha component).

Optionally, the raster_details constructor may take two additional arguments of type double that specify the physical dimensions of the image in millimeters:

imagexx::raster_details d(fmt, width, height, width_mm, height_mm);

These physical dimensions have no effect on compression or encoding. They are merely stored in the file and may be retrieved when the file is loaded again.

Saving the image to a file

If you have the name of a file to which you would like the image to be saved, the call you need to make is as follows. Here I'm assuming that you'd like to save a PNG. Simply swap "pngxx" with "jpgexx" if you'd like to save a JPEG instead.

my_iterator_type b = raster_begin();
my_iterator_type e = raster_end();
pngxx::write_image(d, "my_image.png", b, e);

In the above, d is the raster_details object we created earlier, describing the format of the pixels.

It is assumed that the bytes in the raster as presented by the iterator pair will yield pixel components appropriately for the format specified in the raster_details object. For example, if the pixel_format given is imagexx::rgb, then dereferencing the "begin" iterator should first yield a byte representing the red component of the first pixel, and then after advancing and dereferencing again, a byte representing the green component of that pixel and then the blue component, third. Then the red, green and blue components of the second pixel, then the third pixel, and so on...

Again, imagexx provides functionality to construct iterators that will be able to present pretty much any raster in this form.

The return type of this overload is void. An exception is thrown if an error occurs during the call to write_image(). See elsewhere on the wiki for the exceptions that may be thrown.

Saving an image to a std::ostream

This works exactly like the above function, except that you must pass an std::ostream instead of a file name:

std::ostream &out = get_ostream();
pngxx::write_image(d, out, b, e);

This overload returns the stream. You should check the state of the stream for failure, as well as catching any exceptions thrown.

Saving an image to an output iterator

Again, this is very similar to saving an image using the previous two overloads. However, to avoid ambiguity on overload resolution, the order of the arguments is a little different:

my_output_iterator out = get_ouput_iterator();
out = pngxx::write_image(d, b, e, out);

An output iterator is returned on success, allowing you to append data immediately following the image data stream, if needed.

Default arguments

The overloads of write_image() have some default arguments that we haven't seen yet. They differ between pngxx and jpegxx to cater for the differences in those formats.

Each overload of pngxx::write_image() has a fifth argument, compression, which is a double whose default value is 1.0. If you require faster (but poorer compression), you may try lower values. Any value outside of [0.0, 1.0] is clamped to that range.

Each overload of jpegxx::write_image() has a fifth argument, quality, which is a double whose default value is 0.8. Increase this value for better quality (but poorer performance) or decrease it for better performance (but larger file/data sizes).

Saving an image from a custom image object

imagexx provides some iterators that allow you to write PNG and JPEG images directly from your own custom image objects.