IOLink  IOL_v1.1.0_release
Getting started

Introduction

First of all, IOLink does not allow to open and decode files. It is not its purpose. See IOFormat component in IOSuite for this need.

With IOLink, you have the possibility to handle ImageViews (i.e. received from an external application as IOFormat) and also to create new ones in memory. That's all, but it is sufficient in most of the cases.

Creation of your first Image view

You can use IOFormat to retrieve a view onto a specific file. Or, you can implement your own reader (we call them extractors in IOLink) using ImageView interfaces.

But, to simply create an in-memory view, from scratch, you can use ImageViewFactory.

Factories are a set of methods, sorted for each kind of view (Image, Mesh, Sound,..., even if for now, only Images are available).

Thus, to create an in-memory Image view (called ImageView), you will use ImageViewFactory as follows:

std::shared_ptr<ImageView> image = ImageViewFactory::allocate(VectorXu64{100, 200}, DataTypeId::UINT8);

With this line of code, you requested to create an empty 2-dimensional ImageView whose size is 100 x 200, and for which each pixel is stored as a 8-bit-unsigned value.
As you can see, views are stored through shared pointers (from C++ std), and it permits to share views without any risk of wrong memory access. In memory, an area is allocated ( size in bytes = 100 x 200 x 1byte ) to store this image, and will only be released when last shared pointer on the view will be freed.

You could also request for more complex formats, for example, a three-dimensional image (a video, a volume, ...) by just indicatif the value for the new dimension:

std::shared_ptr<ImageView> image = ImageViewFactory::allocate(VectorXu64{100, 200, 15}, DataTypeId::UINT16);

This time, a memory area (size = 100 x 200 x 15 x 2bytes) is allocated.

As mentioned previously, this new image could be a video or a volume. In fact, it could be any kind of 3-dimension image. For the moment, it does not matter.

Access to image content

From your ImageView object, you have access to basic information concerning the image: dimension number, data type, shape, properties.

Note: this basic information only concern images. For a different type of data, other information would be available.

You can access to this information directly with ImageView object:

std::shared_ptr<ImageView> image = ImageViewFactory::allocate(VectorXu64{100, 200}, DataTypeId::UINT8);
uint8_t dimensionCount = image->dimension();
// dimensionCount is 2
VectorXu64 shape = image->shape();
// shape is {100,200}
DataType type = image->dataType();
// type is datatype::UINT8
std::shared_ptr<const ImageProperties> properties = image->properties();
// properties() returns a shared pointer onto an ImageProperties object (readable only by default) which contains some image properties

Read pixels

Now, you want to access to pixels value. ImageView interface does not provide the appropriate API to read image content. By default, ImageViewFactory return at least ImageViews with the READ capability, which gives the ability to read pixel by pixel, or a full region.

std::shared_ptr<ImageView> image = ImageViewFactory::allocate(VectorXu64{100, 200}, DataTypeId::UINT8);
uint8_t pixelValue;
VectorXu64 index{16, 32};
image->read(index, &pixelValue);

With this previous code, you read the pixel value at position (16,32). pixelValue variable is unsigned 8-bit typed because of view datatype. If you try to access to an invalid position (negative index, out from image), nothing prevents it for now.

You also can access to a full region from your image, as follows:

// create a small region in the image
RegionXu64 region(VectorXu64{0, 0}, VectorXu64{16, 32});
// allocate a memory buffer of region size
size_t bufferSize = region.elementCount() * image->dataType().byteCount();
std::vector<uint8_t> buffer(bufferSize);
// read the region content into the buffer
image->readRegion(region, buffer.data());

Here we access a region defined by its origin and its size in the original image. A memory buffer correctly allocated is needed before calling the 'read region' method. You can use Region helper method to know the number of pixels contained inside the wanted region.

Write pixels

The principle is mostly the same than for reading, this time with WRITE capacity.

std::shared_ptr<ImageView> image = ImageViewFactory::allocate(VectorXu64{100, 200}, DataTypeId::UINT8);
uint8_t pixelValue = 15;
VectorXu64 index{16, 32};
image->write(index, &pixelValue);

Here we wrote the pixel value 15 at position (16, 32) in our image. If you try to write at an invalid position (negative index, out from image), nothing prevents it for now.

Same thing to write into a complete region:

std::shared_ptr<ImageView> image = ImageViewFactory::allocate(VectorXu64{ 100, 200 }, DataTypeId::UINT8);
RegionXu64 region(VectorXu64{0, 0}, VectorXu64{16, 32});
size_t bufferSize = region.elementCount() * image->dataType().byteCount();
std::vector<uint8_t> buffer(bufferSize);
// write data into buffer...
image->writeRegion(region, buffer.data());

Conclusion

Now, with these examples, you can apply basic Image modifications in memory. See howto part for more specific functionalities.