IOFormat  IOF_v1.3.1_release
Create a Custom Plugin

Custom plugins can be written in C++ only.

If you want to create your own Extractor or Writer plugin, you can by following the API contained in the IOPluginAPI project:

IOPlugin APIs are versioned and each version of IOFormat is only compatible with one version of IOPlugin. All plugins developed with a different IOPlugin version of the one used by IOFormat won't be loaded.

See configuration to know the IOPlugin version compatible with this version of IOFormat.

You must add the IOPlugin Conan package to your plugin dependencies, to get the included and logging libraries. You must link against this package using the classic Conan way. If you want your plugin to be used in IOFormat, it must be declared as a SHARED library in CMake.

add_library(${PROJECT_NAME} SHARED ${PLUGIN_SOURCES})
target_link_libraries(${PROJECT_NAME} CONAN_PKG::IOPlugin)

An IOFormat plugin must implement the matching plugin interface: ExtractorPlugin or WriterPlugin, depending on the type of plugin you want to make. When the class is done, you must use a plugin-defining macro in order to make it usable by the plugin system of IOFormat. These macros depend on the plugin type:

  • IOPLUGIN_DECLARE_EXTRACTOR_PLUGIN(PluginClass) for Extractor plugins.
  • IOPLUGIN_DECLARE_WRITER_PLUGIN(PluginClass) for Writer plugins.

The plugin class should be done in a source file (*.cpp or *.cxx) instead of a header file, because we only want to export the instance.

Example for an extractor plugin:

using namespace iolink;
class TestPlugin : public ExtractorPlugin
{
// override the interface's methods
};
IOPLUGIN_DECLARE_EXTRACTOR_PLUGIN(TestPlugin)

TestPlugin, in this example, is the entry point for the extractor plugin. It's up to the methods openDataAccess and openFile of this class to instanciate and return the appropriate view according to the format of the opened file.

Have a look on the code example provided with the IOPlugin API.

For example: calling openDataAccess onto PNG plugin will require the instanciation of an object derived from ImageView, since PNG is only able to manage 2D Images. On the other hand, a TIFF plugin could possibly be either an object derived from ImageView or from MultiImageView, depending of the file content. A TIFF file can contain either an image, thus an ImageView, or a list of independant frames, thus a MultiImageView.

Implementation guidelines

There are some guidelines common to the two types of plugins:

  • Never override the api method, it is already returning the API version of the IOplugin version you are using to create your plugin.
  • Logging methods have a default implementation, so if you do not override them, initLogger will do nothing, and logLevel will always return LogLevel::OFF.

Extractors

Factories

There are two different View factories in the ExtractorPlugin interface that you can implement in your custom plugin. First, openFile that takes a path to the source file, and openDataAccess that takes a DataAccess from which to decode from. The openDataAccess variant also takes a format argument that enables the selection of the format to use to decode the accessor's data. This format is automatically selected using the path's extension in the openFile variant.

When one of these variants is not supported by your custom plugin, just make the method throw an Error describing that the feature is not supported.

Preliminary checks and operations

For both cases, a serie of checks and operations should be done immediately:

  • Check that the given format string parameter to adapt your extraction method to the current situation (i.e. when a plugin handles many different formats).
  • Check that the given path or dataAccess is valid. Data must exist and be available for reading and most of the time for seeking in the case of streams.
  • Check the data content by starting to extract some basic information which will help to determine the type of View that your plugin should create and return:
    • type of the data (UINT8, UINT16, UINT32, ...)
    • number of frames (if supported by the format)
    • number of dimensions of the frame(s)
    • shape of the frame(s)
  • Extract the information to fill the properties immediately. You should extract these informations as soon as possible, and not "on the fly", for thread-safety reasons.
  • Extract the tree of metadata. For some cases it is better to extract all metadata at the opening. And for other cases it is better to build it on-demand.

If any of these checks/operations fails, an exception will be raised.

The table below should help you determine the kind of View to return:

View type Case where this type of view should be created
ImageView A N-dimension array (e.g a 2D Image, a volume, a sequence of image...)
MultiImageView A set of images which may or may be related with each other (shape and type can be different)
LodImageView One multi-resolution image (many different resolutions of the same N-Dimensional image)
DataFrameView Tabular Data

Up to you to return the view type corresponding the better to extracted data and which matches your needs.

Writers

Factories

There are two Writer factories in the WriterPlugin interface, all taking the source View as the first argument. The openFile one uses a path to specify the writer's output, and will infer the format to use from the file's extension. The openDataAccess variant use a DataAccess as its output with its format specified with a format parameter.

When one of these variants is not supported by your custom plugin, just make the method throw an Error describing that the feature is not supported.

Input adaptation

Ideally, your custom writer should support any kind of View as an entry, as long as it fits the underlying format. For example a plugin encoding to an image format could take any ImageView as input. In the image case, the underlying format usually support one particular data layout, but a good plugin should accept different layouts, as long as they are easily adaptable, without damaging the content and without guessing the user intentions. For example, when a plugin uses a format that stores color data in an interleaved order, if the user gives a planar ImageView (one with a CHANNEL dimension) as input, it should adapt it, instead of throwing an error saying that the view is unsupported. Another example is MultiImageView instances, that can be stacked to feed a volume or sequence format, if it is possible.

As long as there is one possibility to adapt the data to match the writer inputs, the plugin should try. However, when there is more than one possibility to adapt the data, the plugin shall raise an exception to ask the user to make a decision.

Performances

In order to provide better features and performances, writers created by your custom plugin should not write all the output in one call. An approach using chunked write calls should be preferred. It will avoid hangs-on and blocking operations when using non-filesystem accessors.