This section talks about data storage and management in nGI.
Data Storage
Data storage of buffers in nGI is done mainly with the buffer
class. However, the buffer class is just one implementation of a
buffer that implements the necessary interface in order to work together
with the rest of nGI.
Implementing buffer types with different behavior is relatively easy,
and the buffer class can be taken as a template (not meant in the C++
sense) that you can use to model the new buffer type after.
In fact, we have modeled the freeimage_buffer after buffer and it is
used to connect the FreeImage library to nGI. FreeImage is a library
that provides the means to load and save images in various formats.
buffer
The buffer class is a multidimensional container that arranges
elements of a given type (monochrome, color, or something completely
different) in a linear arrangement and allows fast random access to any
element. A buffer owns its data.
The following schematic shows the logical layout of a buffer object.

A buffer can accommodate a one-dimensional buffer (height == 1 and
depth == 1), like a look-up-table, histogram or a profile, a
two-dimensional buffer (depth == 1), like an image, or a
three-dimensional buffer, like an image stack or or an image sequence.
The buffer class provides direct data access as well as indirect
access via linear iterators, three-dimensional locators and views.
Here are a few examples how you can allocate a buffer from scratch:
// make buffers of various size and type
buffer<unsigned char> empty; // empty buffer
buffer<unsigned int> a(256); // one-dimensional, zero initialized
buffer<unsigned short> b(256, 256); // two-dimensional
buffer<unsigned char> c(256, 256, 10, 255); // three dimensional, initialized to 255
You can pass zero to four arguments to the buffer constructor. If no
parameters are passed, an empty buffer is created. No storage is
allocated for the empty buffer. The first three parameters are the sizes
in the x, y and z direction, with default values of 1 for y and z. The
fourth parameter is the initialization value. Every pixel of the buffer
is initialized to this value. The initialization value defaults to 0 if
not passed.
You can also copy buffers using the copy constructor or assign buffers using the assignment operator. In both cases the buffer contents is copied pixel-by-pixel as well. In the case of assignment, the previous buffer contents are destroyed. The size of the buffer may change when assigning to it.
// copying and assignment of buffers
buffer<unsigned int> d=a; // uses the copy constructor
buffer<unsigned short> e; e=b; // uses the copy assignment operator
d = buffer<unsigned int>(); // assign an empty buffer to clear contents
You can query the width, height, depth and volume of a buffer with the following code:
// get size of buffers
size_t width = c.get_width();
size_t height = c.get_height();
size_t depth = c.get_depth();
diff_3d size = c.get_size();
// get the volume of a buffer
size_t volume = b.get_volume();
The volume of a buffer is the product of width, height and depth. The
contents of a buffer can be directly accessed via operator [] and
operator (). Both operators provide read and write access. The index
can be provided as a linear (one-dimensional) index as well as a
three-dimensional index.
// direct linear access to buffer data
for (size_t i=0; i<a.get_width(); ++i)
{
a[i] = i; // access via operator []
// could also use operator ()
}
// direct three-dimensional access to buffer data
for (size_t y=0; y<b.get_height(); ++y)
{
for (size_t x=0; x<b.get_width(); ++x)
{
a(diff_3d(x, y, 0)) = x+y; // access via operator ()
// could also use operator []
}
}
A buffer also provides indirect access to its data via
three-dimensional locators. In addition you can use three-dimensional
views to indirectly access the pixels. These concepts will be explained
in the chapters about the iterators, locators and views.
freeimage_buffer
The freeimage_buffer class is a two-dimensional container that
arranges elements of a given type in a linear way and allows fast random
access to any element.
It also is wrapped around the FreeImage open source library and allows loading from files or streams as well as saving to files or streams in various formats.
If you use the freeimage_buffer you are bound to obey to the licensing
options provided by the FreeImage library.
Accessing Data
This section talks about locators and views, which are the foundation of the data access methods used in nGI. Locators and views provide several means of indirect access to data. This indirect access to data is one of the reasons for the flexibility of nGI.
Locators
A locator is a kind of a 'three-dimensional iterator' that is used within NGI to address locations within buffers.

A locator can also be seen as an adapter to an iterator. Given a one-dimensional iterator, and shape information about the three-dimensional buffer - such as pixel_pitch, line_pitch, and plane_pitch, - a locator can be created from any iterator.
Put in a different way: if foreign data is organized in a way that you can describe it having a pixel, line and plane pitch, then you can create a locator that allows nGI to access foreign data, without first copying it.
Similar to an iterator that can move in one dimension, a locator can move in three dimensions (horizontal, vertical and planar).
In the same way as an iterator can point to some location out of bounds, a locator can also point to three dimensional locations that are out of bounds. Dereferencing a locator that is out of bounds is forbidden, and the result is undefined.
The movement in three dimensions is accomplished by using three
different pitches or strides. The first pitch - the pixel_pitch - is
used to move along the horizontal dimension. Incrementing the locator by
the pixel_pitch moves to the horizontal neighbour at the right. The
second pitch - the line_pitch - is used to move in the vertical
dimension. The line_pitch is the amount of increments needed to go
from the current line to the next (usually this is the width of the
image plus some optional padding). Incrementing the locator by the
line_pitch moves to the vertical neighbour at the top. The third
pitch - the plane_pitch - is used to move in the planar dimension. The
plane_pitch is the amount of increments needed to go from the current
plane to the next (usually this is the width of the image plus padding
multiplied by the height of the image). Incrementing the locator by the
plane_pitch moves to the planar neighbour.
Views
A view is a kind of a 'three-dimensional range' that is used within nGI to address buffers or parts of buffers.
A view consists of a three-dimensional locator that points to the begin of the data, as well as of a width, height and depth to specify the three-dimensional size of the view.

Views are used by algorithms in nGI to access the data which is stored in buffers. This provides an indirection in data access which is one of the reasons of the flexibility of data access in nGI.
A view makes use of a locator, so it provides three-dimensional navigation on top of linear data.
Since a locator can point to foreign data, a view can be used to access foreign data as well.
A view has several convenience methods that can turn itself into other, related views.
The subset method can cut out a subset of the current view by
specifying a three-dimensional coordinate offset and a three-dimensional
size.
The dimension_swap method can swap view dimensions (i.e. swap the
horizontal by the vertical dimension) by adjusting the various pitches
in the underlying locator.
The subsample method can subsample in one or more dimensions, and this
is also done by adjusting the various pitches in the underlying locator.
The reverse method can reverse the iteration direction in one or more
dimensions. Reversing is done by adjusting the position and negating the
respective pitches of the underlying iterator.
The subset, dimension_swap, subsample and reverse methods can be
chained together. This means that you could create a view that is a
subset, with a subsampling factor, swaps the horizontal and vertical
axes and accesses data it in a reverse way in certain dimensions.