IOFormat 1.12.0
Loading...
Searching...
No Matches
Fundamentals

Open an Image

Initialization

IOFormat does not necessarily need to be initialized, but it is a way to force plugins to be loaded at start-up, to avoid some latency during the first opening at runtime.

IOFORMAT_API bool init()

Retrieve view from a file path

IOFormat provides methods to directly retrieve a view from a path. The filename extension will determine the format, and thus the extractor to instantiate. Theoretically, IOFormat can handle any kind of format, so this method cannot directly return an ImageView. You will have to check first the type of view returned, and then transform it.

An important note, when opening a resource with openView, only a handle to the resource is kept, the data of the view is not copied in memory, or will be reduced to a minimum.

Concerning images, IOFormat can return three kinds of view:

  • ImageView (Readable at minimum)
  • MultiImageView (Readable at minimum)
  • LodImageView (Readable at minimum)

If a problem happened during the opening, an error will be raised.

auto view = ioformat::openView("tmp/image.tiff");
if (iolink::ImageViewProvider::isImage(view))
{
auto imgView = iolink::ImageViewProvider::toImage(view);
// process image
}
else if (iolink::MultiImageViewProvider::isMultiImage(view))
{
auto stackView = iolink::MultiImageViewProvider::toMultiImage(view);
// process multi image
}
IOFORMAT_API std::shared_ptr< iolink::View > openView(const std::string &pathFile)

Load in memory from a file path

Users can decide to directly load in memory the full content of the loaded image. That way, the view is directly created in memory, through a specific method.

For now, this functionality is only for singles-frame images. If the given file contains more than one frame, the method will rise an exception.

auto image = ioformat::readImage("tmp/image.bmp");
IOFORMAT_API std::shared_ptr< iolink::ImageView > readImage(const std::string &src, const GeneralOptions &options)
Read an image from a source path and store it in CPU memory.

Get a view from an URI

You have the possibility to load a view from a URI. This allows to load an image using different protocols (file, http, s3, ...)

Remark: In the case of HTTP, the server must support HTTP range requests.

Given URI shall start with the scheme to identify the protocol to use:

e.g.

http://....

s3://....

file://....

Two methods are available for two distinct cases:

  • URI allows to retrieve remote file extension, and thus its supposed format
  • URI does not allow to identify file format. Format must be specified at method call.
std::string uri("https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png");
auto view = ioformat::openViewFromUri(uri);
IOFORMAT_API std::shared_ptr< iolink::View > openViewFromUri(const std::string &uri, const GeneralOptions &options={})

If the file format cannot be identified with its URI, its format must be specified:

// for example, a PHP request can point toward an image, but nothing in the request indicates file format
std::string uri("http://google.com?id=1&name=wayne");
auto view = ioformat::openViewFromUri(uri, "PNG");

Credentials

Some protocols can require credentials. In this case, a separate function is provided to associate credentials with specific hosts, and must be called before any other reading/writing attempt:

ioformat.addCredentials("s3://host:9000", "user name", "password");
Global namespace which contains all methods to encode/decode data from/into different resources (file...
Definition Error.h:6

Get a view from any accessor

For any other cases, you can use an accessor as a container for your image to decode. You can have a look into the 'accessor concept' section in IOLink user-guide for more details.

Once you have an accessor to your content, IOFormat provides a method to create a view onto this accessor. On the other hand, you have to specify the format of your data.

Remark: IOLink provides a factory to create a view onto an accessor, but with raw data only (not encoded). This one is different, since data are encoded in the accessor, and only IOFormat has capacities to decode them.

// you have an accessor onto an encoded image (whatever it comes from)
std::shared_ptr<iolink::DataAccess> accessor = .... ;
// you know your data represent a PNG image
auto view = ioformat::openView(accessor, "PNG");

Open a stack of files

Using a pattern

The StackReader factory can be used to aggregate files which names follow a pattern into an ImageView. Methods from this factory usually take a pattern and the interpretation of the stacking dimension. The pattern format is quite simple: variable parts of the path are indicated with a wildcard "*". The wildcard must only be in the last segment of the pattern. For example some/dir/img_*.png is valid, where some/dir_*/img_*.png is invalid.

  • openImageFromPattern will not load anything in memory, so it is useful for out-of-core mechanics.
  • readImageFromPattern will stack the files and then load the resulting view in memory for better performance.
std::shared<iolink::ImageView> img = ioformat::StackReader::openImageFromPattern("some/dir/img_*.png", iolink::ImageDimension::SLICE);
static std::shared_ptr< iolink::ImageView > openImageFromPattern(const std::string &pattern, iolink::ImageDimension newDim)

Using a file list

A file list is a file where each line is a path to an image, StackReader::openListFile will open such a file list and create a stacked image using the listed images in order. The StackReader::loadListFile variant do all the same, and then load the stacked image in memory.

Example of an image list:

some/path/to/file.ext
some/other/path/to/file.ext

Code example to load a list file:

std::shared<iolink::ImageView> img = ioformat::StackReader::openImageFromListFile("some/dir/stack.lst", iolink::ImageDimension::SLICE);
static std::shared_ptr< iolink::ImageView > openImageFromListFile(const std::string &filePath, iolink::ImageDimension newDim)

Open a stack of resources (URI)

Images resources can ben stacked as files.

Using a list of Uri

A list of URIs is given for stacking.

std::vector<std::string> listUri = {
"file:///c:/path_to_data/image1.png",
"file:///c:/path_to_data/image2.png",
"file:///c:/path_to_data/image3.png"
};
std::shared_ptr<ImageView> stack = StackReader::openImageFromUriList(listUri.data(), listUri.size(), iolink::ImageDimension::SLICE);

Using a pattern

A pattern can also be given to identify and stack a list of URIs. But it has some limitations according to the protocol. This functionality requires the possibiliy to list the content of a remote storage.

e.g. http protocol cannot be used.

std::string pattern = "file:///c:/path_to_data/image*.png";
std::shared_ptr<ImageView> stack = StackReader::openImageFromUriPattern(pattern, iolink::ImageDimension::SLICE);

Same methods with read prefix instead of open also exist to get a stack as an in-memory ImageView.

Write as a stack of files

It is possible to export a multiImageView or a multi-dimensional image (> 3D) as a stack of files, identified with the same name followed by an unique index.

e.g. a volume (3D) can be written as a list of 2D images numbered (the last dimension is used to unstack) a MultiImageView containing 50 2D-frames can be written as a list of 50 of 2D images numbered.

Here is an example of how to export a volume into a list of files:

// a volume
std::shared<iolink::ImageView> volume = ImageViewFactory::allocate(VectorXu64{20, 30, 40}, DataTypeId::UINT8);
// export the volume as a list of TIFF files
ioformat::StackWriter::writeFromPattern(volume, "stack%%%.tif"); // 40 TIFF files are generated: stack001.tif, stack002.tif, stack003.tif...
// same thing with a different naming
ioformat::StackWriter::writeFromPattern(volume, "stack%.tif"); // 40 TIFF files are generated: stack1.tif, stack2.tif, stack3.tif...
static void writeFromPattern(std::shared_ptr< iolink::MultiImageView > multi, const std::string &outputFilePathPattern)

Write as a stack of URIs

The same way that it is possible to write a stack as a list of files, you can also export a multiImageView or a multi-dimensional image as a list of URIs.

The mechanism is the same than for files:

// write a volume as a list of resources, using an URI pattern.
ioformat::StackWriter::writeFromUriPattern(volume, "file://path_to/stack%%%.tif"); // 40 TIFF resources are generated: stack001.tif, stack002.tif, stack003.tif...
static void writeFromUriPattern(std::shared_ptr< iolink::MultiImageView > multi, const std::string &outputUriPattern, const ioformat::GeneralOptions &options={})

Export to a format

Exporting a view into a specific format means encoding your view content into this format. But each format has its own specificities, limitations, and can request some parameters (compression, color, etc.). Hence, each format needs a specific writer.

Using a Writer

If you need to export your view content into a file or stream, the easiest way is to use the dedicated method. The appropriate writer plugin will be used internally. Default options of writers will be used for encoding.

This is a simple code example:

auto image = iolink::ImageViewFactory::allocate(iolink::VectorXu64{64, 64}, iolink::DataTypeId::UINT8);
// image is encoded in PNG in the given file (extension of the file path determines the format)
ioformat::writeView(image, "tmp/image.png");
auto outputStream = iolink::StreamAccessFactory::openFile("tmp/image.raw");
ioformat::writeView(image, outputStream, "PNG"); // image is encoded in PNG and stored in the given stream
ioformat::writeView(image, outputStream, "MRC"); // image is encoded in MRC and stored in the given stream
IOFORMAT_API void writeView(std::shared_ptr< iolink::View > view, const std::string &pathFile)

Setting Options

You can use options to parametrize how a format export will run. Most of IOFormat main interface functions accept GeneralOptions as parameters.

GeneralOptions have a specificity, their key has three segment:

  • one for the plugin, with a special value of all meaning that option is intended to target all plugins.
  • one for the format, with a special value of ANY meaning that the option is intended to target any format.
  • one for the actual option's name

The first segment can be ommited, if so it will be replaced with all. The second segment can be ommited, if so it will be remplaced with ANY. So if you don't really care about filtering options by plugin or format, you can simply use the last segment: compression being equivalent to all:ANY:compression for example.

In the following code, you can see how to use options when writing a view in a JPEG file:

const iolink::VectorXu64 shape{64, 64};
auto image = iolink::ImageViewFactory::allocate(shape, iolink::DataTypeId::UINT8);
// setting the options
GeneralOptions options;
options.setInt("compression", 70);
// writing to the JPEG file
const std::string path = "tmp/toto.jpeg";
ioformat::writeView(image, path, options);

Writing to a URI

Specific methods are provided to write a view into an URI.

The case where the URI contains the extension. IOFormat can determine the encoding format from the extension:

ioformat::writeViewToUri(view, "file://C:/PATH_TO_FILE/FILE.txt", options);
IOFORMAT_API void writeViewToUri(std::shared_ptr< iolink::View > src, const std::string &dst, const GeneralOptions &options={})
Write a view into a destination URI. Scheme is used to determine the protocol to use.

The case where the URI does not contain the extension. Encoding format is provided to the method:

ioformat::writeViewToUri(view, "file://C:/PATH_TO_FILE/FILE", "PNG", options);

Helpers

IOFormat API provides some helpers.

Using formats

Some IOFormat APIs require to provide the format to encode or decode a data through a stream. This format is given as a characters string and should textually match with one of the formats supported by the internal plugins.

Example: To encode a view into a stream with JPEG format, you have to specify "JPEG" as format.

A helper exists to easily convert an extension (i.e "jpg" or "png") into a format recognized by IOFormat APIs.

The following example shows how to encode your view into a specific extension which format you don't know:

auto image = iolink::ImageViewFactory::allocate(iolink::VectorXu64{64, 64}, iolink::DataTypeId::UINT8);
auto outputStream = iolink::StreamAccessFactory::openFile("tmp/image.raw")
// you need to know the format associated to this extension
// if extension is not handled, an exception is raised
std::string format = ioformat::formatFromExtension("ali");
// you can now retrieve a writer for this format
auto writer = ioformat::openWriter(image, outputStream, format);

Configuration

Logger

IOFormat can log messages with different level of criticity:

  • LOG_OFF: No logging at all
  • LOG_CRITICAL: Severe errors that cause premature termination.
  • LOG_ERR: runtime errors or unexpected conditions.
  • LOG_WARNING: Use of deprecated APIs, poor use of API, "almost" errors, other runtime situations that are undesirable or unexpected, but not necessarily "wrong".
  • LOG_INFO: Interesting runtime events (startup/shutdown).
  • LOG_DEBUG: Detailed information on the flow through the system.
  • LOG_TRACE: Only for "tracing" the code and trying to find one part of a function specifically

User is free to select the level of messages which he's interested to display at runtime.

By default, IOFormat log level is initialized with IOLink log level. Its level can only be specified by initializing a Logger object. before any other IOFormat API call.

iolink::Logger::init(iolink::LogLevel::LOG_INFO);
ioformat::Logger::init(iolink::LogLevel::LOG_ERR);
auto view = ioformat::openView("car.png");
static void init(iolink::LogLevel level)

In the previous example, the IOLink log level is set at INFO level, and the IOFormat log level is set at the ERROR level.

iolink::Logger::init(iolink::LogLevel::LOG_INFO)
auto view = ioformat::openView("car.png");

In this other example, only the IOLink log level is set. The IOFormat log level is internally initialized at the same level as IOLink.

auto view = ioformat::openView("car.png");
ioformat::Logger::init(iolink::LogLevel::LOG_INFO);

In this last example, the IOFormat log level is set after an IOFormat API call. This last line has no effect.