libgfx: Raster Images
Author: Michael Garland

## Raster Images

The `libgfx` library provides very basic support for storing raster image data. This is not really intended to provide the kind of support necessary for advanced image processing, but rather the basic functionality needed for saving screen snapshots, loading texture files, etc. To use this package you will first need to include the header file

        #include <gfx/raster.h>

### Image Representation

Images are implemented using the `Raster<T>` template class. The templated type `T` determines how individual pixel values are stored. There are two standard image types:

- `ByteRaster`: pixel components are represented with values of type `unsigned char`
- `FloatRaster`: pixel components are represented with values of type `float`

#### Allocating an Image

When allocating an image, you must specify its three dimensions: (1) width in pixels, (2) height in pixels, and (3) number of channels.

        Raster<T>(int width, int height, int nchannels);

Typically, the number of channels should by either 1 for grayscale images, 3 for RGB color images, or 4 for RGB images with an alpha channel.

#### Accessors

The dimensions of an image can be determined through a standard set of accessor functions:

        int width();      // Width of image (in pixels)
        int height();     // Height of image (in pixels)
        int channels();   // Number of channels in image
        int length();     // Total number of pixel values

The width, height, and channel count values are merely those specified when the image is allocated. The length of the image is the total number of pixel elements (i.e., width*height*channels).

Pixel elements can be accessed in two different ways. First of all, you can get a pointer to the single pixel at the image location (i,j) by calling the method

        T  *pixel(int i, int j);

This is the standard way to access pixels. Alternatively, you can access pixel elements using the standard C [] bracket notation. This method is generally discouraged since it exposes the underlying layout of the image. However, it can be useful if you want to visit every pixel element without regard to its location.

#### Pixel Manipulation

The `Raster` template class provides some very simple methods for manipulating the image which it stores. They are:

        void hflip();   // Flip the image from left to right
        void vflip();   // Flip the image from top to bottom

### Input/Output of Image Files

In addition to internal image representation, this package provides a simple set of functions for reading and writing external image files. The library supports the following image types:

- PNM (supported internally)
- TIFF (requires libtiff)
- JPEG (requires jpeglib)
- PNG (requires libpng)

Images can be read from files using the following functions:

        ByteRaster *read_pnm_image(const char *filename);
        ByteRaster *read_tiff_image(const char *filename);
        ByteRaster *read_png_image(const char *filename);
        ByteRaster *read_jpeg_image(const char *filename);

These functions return `NULL` if the file could not be read. This includes the case when the required external libraries are not available. Similar functions can be used to write images to files:

        bool write_pnm_image(const char *filename, const ByteRaster&);
        bool write_tiff_image(const char *filename, const ByteRaster&);
        bool write_png_image(const char *filename, const ByteRaster&);
        bool write_jpeg_image(const char *filename, const ByteRaster&);

They return `true` or `false` indicating whether the output operation succeeded or not.

The PNM output routines can output both raw (i.e., binary) and ASCII image files. Which type of file they write is controlled by the global variable

        bool will_write_raw_pnm;

Since JPEG is a lossy compression format, the behavior of the JPEG output routines is dependent upon the global variable controlling image quality

        int jpeg_output_quality;

These quality factors are integers ranging from 0-100 (with 100 being the highest quality). See the `jpeglib` documentation for further details.

For convenience, you can read/write image files with the functions

        bool write_image(const char *filename, const ByteRaster&, int type=-1);
        ByteRaster *read_image(const char *filename, int type=-1);

The file format will be inferred from the filename, unless the optional `type` argument is given. The image type should be one of `IMG_PNM`, `IMG_PNG`, `IMG_TIFF`, or `IMG_JPEG`.