libtad  2.1
A library that makes working with multidimensional arrays in C++ easy
libtad Reference

Tagged Array Data (TAD): Overview

TAD manages multidimensional arrays. Each array element consists of a fixed number of components. All components are of the same data type (integer or floating point). For example, an array holding image data could be a two-dimensional array with size 800x600, and each element could consist of three uint8 components representing the R, G, and B channels.

Metadata is managed using tags, which are key/value pairs where both key and value are represented as strings. An array has a global tag lists (typically describing the array data as a whole), dimension-specific tag lists (typically describing the dimensions), and component-specific tag lists (typically describing the interpretation of each component).

The libtad Library

The library works with the following classes: TAD::TagList to manage metadata, TAD::ArrayDescription to handle all metadata describing an array, TAD::ArrayContainer to handle array data of any type, and finally TAD::Array to handle arrays with a specific data type so that convenient operations on the data are possible.

All array data is shared by default when making copies of an array. If you want a copy of the data, use TAD::ArrayContainer::deepCopy() or TAD::Array::deepCopy().

Input and output are managed by the TAD::Importer and TAD::Exporter classes, and there are shortcuts TAD::load() and TAD::save() to read and write arrays in just one line of code.

TAD Manual

The tad manual contains an overview of supported file formats, the specification of the native TAD file format, and a list of common tags.

Examples

This program creates an image:

#include <tad/array.hpp>
#include <tad/io.hpp>
int main(void)
{
TAD::Array<uint8_t> image({800, 600}, 3);
for (size_t y = 0; y < image.dimension(1); y++) {
for (size_t x = 0; x < image.dimension(0); x++) {
image[{x, y}][0] = x / (image.dimension(0) - 1.0f) * 255; // red
image[{x, y}][1] = y / (image.dimension(1) - 1.0f) * 255; // green
image[{x, y}][2] = 0; // blue
}
}
TAD::save(image, "image.ppm");
return 0;
}
An Array with a specific component data type given the template parameter. This is the main class to ...
Definition: array.hpp:887
bool save(const ArrayContainer &A, const std::string &fileName, bool append=Overwrite, Error *error=nullptr, const TagList &hints=TagList())
Shortcut to write a single array to a file in a single line of code.
Definition: io.hpp:207

This example loads an image, extracts the red channel, and saves it to a file:

#include <tad/array.hpp>
#include <tad/io.hpp>
int main(void)
{
TAD::Array<uint8_t> image = TAD::load("image.ppm");
TAD::Array<uint8_t> greenChannel(image.dimensions(), 1);
for (size_t i = 0; i < greenChannel.elementCount(); i++) {
greenChannel[i][0] = image[i][1];
}
TAD::save(greenChannel, "green.pgm");
return 0;
}
const std::vector< size_t > & dimensions() const
Returns the list of dimensions.
Definition: array.hpp:419
ArrayContainer load(const std::string &fileName, const TagList &hints=TagList(), Error *error=nullptr)
Shortcut to read a single array from a file in a single line of code.
Definition: io.hpp:201

This example modifies array data using operators and alternatively TAD::forEachComponent() which works with lambdas, functors and functions. There are also variants that take two arrays as input, and variants that work on elements instead of components.

#include <tad/array.hpp>
#include <tad/foreach.hpp>
#include <tad/operators.hpp>
#include <tad/io.hpp>
uint8_t func(uint8_t a)
{
return a * a;
}
struct {
uint8_t operator()(uint8_t a)
{
return a * a;
}
} functor;
int main(void)
{
TAD::Array<uint8_t> image = TAD::load("image.ppm");
// Modify via operator
TAD::Array<uint8_t> r3 = image * image;
// Modify via lambda
TAD::Array<uint8_t> r0 = TAD::forEachComponent(image, [] (uint8_t a) -> uint8_t { return a * a; });
// Modify via function
// Modify via functor
// Save results. All are the same.
// Note that a*a will overflow an uint8_t, but that creates a nice pattern ;)
TAD::save(r0, "r0.ppm");
TAD::save(r1, "r1.ppm");
TAD::save(r2, "r2.ppm");
TAD::save(r3, "r3.ppm");
return 0;
}
Array< T > forEachComponent(const Array< T > &a, FUNC func)
Apply func to all components in array a.
Definition: foreach.hpp:38

This example shows that STL algorithms can work on TAD arrays both on component and on element level:

#include <algorithm>
#include <tad/array.hpp>
#include <tad/io.hpp>
int main(void)
{
TAD::Array<uint8_t> image = TAD::load("image.ppm");
TAD::Array<uint8_t> sorted = image.deepCopy();
std::sort(sorted.componentBegin(), sorted.componentEnd());
TAD::save(sorted, "sorted.ppm");
TAD::Array<uint8_t> answer = image.deepCopy();
std::for_each(answer.componentBegin(), answer.componentEnd(),
[](uint8_t& v) { v = 42; });
TAD::save(answer, "answer.ppm");
TAD::Array<uint8_t> orange = image.deepCopy();
std::for_each(orange.elementBegin(), orange.elementEnd(),
[](uint8_t* v) { v[0] = 255; v[1] = 128; v[2] = 64; });
TAD::save(orange, "orange.ppm");
return 0;
}
ElementIterator elementBegin() noexcept
Returns an iterator pointing to the first element.
Definition: array.hpp:1087
ComponentIterator componentEnd() noexcept
Returns an iterator pointing past the last component of the last element.
Definition: array.hpp:1085
Array deepCopy() const
Construct an array and perform deep copy of data.
Definition: array.hpp:921
ComponentIterator componentBegin() noexcept
Returns an iterator pointing to the first component of the first element.
Definition: array.hpp:1083
ElementIterator elementEnd() noexcept
Returns an iterator pointing past the last element.
Definition: array.hpp:1089