Magnum::Trade::OpenExrImageConverter class new in Git master

OpenEXR image converter plugin.

Creates OpenEXR (*.exr) files from 2D and cubemap images with optional mip levels and PixelFormat::R16F / RG16F / RGB16F / RGBA16F, PixelFormat::R32F / RG32F / RGB32F / RGBA32F or PixelFormat::R32UI / RG32UI / RGB32UI / RGBA32UI and PixelFormat::Depth32F. You can use OpenExrImporter to import images in this format.

Usage

This plugin depends on the Trade library and is built if WITH_OPENEXRIMAGECONVERTER is enabled when building Magnum Plugins. To use as a dynamic plugin, load "OpenExrImageConverter" via Corrade::PluginManager::Manager.

Additionally, if you're using Magnum as a CMake subproject, bundle the magnum-plugins and openexr repositories (pin OpenEXR at v3.0.1 at least) and do the following. OpenEXR depends on zlib and Imath, however it's capable of fetching those dependencies on its own so bundling them isn't necessary. If you want to use system-installed OpenEXR, omit the first part and point CMAKE_PREFIX_PATH to its installation dir if necessary.

# Disable unneeded functionality
set(PYILMBASE_ENABLE OFF CACHE BOOL "" FORCE)
set(IMATH_INSTALL_PKG_CONFIG OFF CACHE BOOL "" FORCE)
set(IMATH_INSTALL_SYM_LINK OFF CACHE BOOL "" FORCE)
set(OPENEXR_INSTALL OFF CACHE BOOL "" FORCE)
set(OPENEXR_INSTALL_DOCS OFF CACHE BOOL "" FORCE)
set(OPENEXR_INSTALL_EXAMPLES OFF CACHE BOOL "" FORCE)
set(OPENEXR_INSTALL_PKG_CONFIG OFF CACHE BOOL "" FORCE)
set(OPENEXR_INSTALL_TOOLS OFF CACHE BOOL "" FORCE)
set(OPENEXR_BUILD_UTILS OFF CACHE BOOL "" FORCE)
# Otherwise OpenEXR uses C++14, and before OpenEXR 3.0.2 also forces C++14 on
# all libraries that link to it.
set(OPENEXR_CXX_STANDARD 11 CACHE STRING "" FORCE)
# OpenEXR implicitly bundles Imath. However, without this only the first CMake
# run will pass and subsequent runs will fail.
set(CMAKE_DISABLE_FIND_PACKAGE_Imath ON)
# These variables may be used by other projects, so ensure they're reset back
# to their original values after. OpenEXR forces CMAKE_DEBUG_POSTFIX to _d,
# which isn't desired outside of that library.
set(_PREV_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS})
set(_PREV_BUILD_TESTING ${BUILD_TESTING})
set(BUILD_SHARED_LIBS OFF)
set(BUILD_TESTING OFF)
set(CMAKE_DEBUG_POSTFIX "" CACHE STRING "" FORCE)
add_subdirectory(openexr EXCLUDE_FROM_ALL)
set(BUILD_SHARED_LIBS ${_PREV_BUILD_SHARED_LIBS})
set(BUILD_TESTING ${_PREV_BUILD_TESTING})
unset(CMAKE_DEBUG_POSTFIX CACHE)

set(WITH_OPENEXRIMAGECONVERTER ON CACHE BOOL "" FORCE)
add_subdirectory(magnum-plugins EXCLUDE_FROM_ALL)

# So the dynamically loaded plugin gets built implicitly
add_dependencies(your-app MagnumPlugins::OpenExrImageConverter)

To use as a static plugin or as a dependency of another plugin with CMake, put FindMagnumPlugins.cmake and FindOpenEXR.cmake into your modules/ directory, request the OpenExrImageConverter component of the MagnumPlugins package and link to the MagnumPlugins::OpenExrImageConverter target:

find_package(MagnumPlugins REQUIRED OpenExrImageConverter)

# ...
target_link_libraries(your-app PRIVATE MagnumPlugins::OpenExrImageConverter)

See Downloading and building plugins, Plugin usage with CMake, Loading and using plugins and File format support for more information.

Behavior and limitations

Channel mapping

Images with PixelFormat::R16F / RG16F / RGB16F / RGBA16F, PixelFormat::R32F / RG32F / RGB32F / RGBA32F or PixelFormat::R32UI / RG32UI / RGB32UI / RGBA32UI are implicitly written to channels named R, G, B and A; images with PixelFormat::Depth32F are implicitly written to a Z channel.

If the default behavior is not sufficient, custom channel mapping can be supplied in the configuration.

Multilayer and multipart images, deep images

Channels can be prefixed with a custom layer name by specifying the layer configuration option. Combining multiple layers into a single image isn't supported right now, writing multipart files or deep images is not supported either.

Cube and lat/lon environment maps

A 2D image can be annotated as being a lat/lon environment map by setting envmap=latlon in the configuration. This requires it to have the width twice of the height.

A cube map image can be saved from an ImageView3D where each slice is one face in order +X, -X, +Y, -Y, +Z and -Z if you set envmap=cube. In this case, the image is expected to have six rectangular faces.

Creating deep images is not supported right now.

Multilevel images

Both 2D and cube map images can be saved with multiple levels by using the list variants of convertToFile() / convertToData(). Largest level is expected to be first, with each following level having width and height divided by two, rounded down. Cube map images additionally have the restrictions specified above. OpenEXR has no builtin concept of an incomplete mip chain, unspecified levels at the end result in a file with missing tiles. This may cause problems with 3rd party tools, however the OpenExrImporter detects such case and reports the file as having less levels.

Multilevel images result in a tiled OpenEXR file, with a tile size taken from the tileSize configuration option. Single-level images are implicitly written as scanline files, you can override that with the forceTiledOutput option.

Plugin-specific configuration

It's possible to tune various options mainly for channel mapping through configuration(). See below for all options and their default values:

[configuration]
# Number of threads OpenEXR should use for compression and writing. A value
# of 1 performs compression and writing serially in the calling thread, 2 adds
# one additional worker thread for compression, etc. 0 sets it to the value
# returned by std::thread::hardware_concurrency().
#
# Note that while the amount of threads can be controlled per-file, OpenEXR has
# a global thread pool and its size will remain at the largest set value until
# the plugin is unloaded. OpenExrImporter shares the same thread pool.
threads=1

# Save channels with given layer
layer=

# Map R/RG/RGB/RGBA image channels to given channel names. If the image is in a
# PixelFormat::Depth32F, depth is used instead. If the channel is not present
# in the input or if its name is empty, it's not written to the file.
r=R
g=G
b=B
a=A
depth=Z

# Set to latlong for 2D images to annotate the image as a lat/long environment
# map and to cube to save a 3D image as a cube map. If empty, no environment
# map metadata are saved.
envmap=

# Display and data window. OpenEXR allows the image to annotate a crop border
# or specify that the data are just a small portion of a bigger image. The
# display window is a four-component vector with (inclusive) Xmin, Ymin, Xmax,
# Ymax coordinates. If left empty, it's implicitly set to 0 0 width-1 height-1.
# The data window size is always set to width-1 height-1 and you can only set
# the offset. For details see the pixel space, Display Window and Data Window
# chapter of https://www.openexr.com/documentation/TechnicalIntroduction.pdf .
displayWindow=
dataOffset=0 0

# Compression. Allowed values are rle, zip, zips, piz, pxr24, b44, b44a, dwaa
# and dwab; leave it empty to write the output uncompressed. Details about
# particular compression algorithms are in the Data Compression chapter of
# https://www.openexr.com/documentation/TechnicalIntroduction.pdf .
compression=zip

# OpenEXR files with mipmaps are always tiled, single level is implicitly
# written as scanlines, unless this option is enabled. Tile size 32x32 is
# library default, larger sizes may lead to less overhead and better
# compression ratios at the cost of more unused space at smallest image
# levels.
forceTiledOutput=false
tileSize=32 32

See Editing plugin-specific configuration for more information and an example showing how to edit the configuration values.

Enabling multithreading

On Linux it may happen that setting the threads option to something else than 1 will cause std::system_error to be thrown (or, worst case, crashing with a null function pointer call on some systems). There's no way to solve this from within the dynamically loaded module itself, the application has to be linked to pthread instead. With CMake it can be done like this:

find_package(Threads REQUIRED)
target_link_libraries(your-application PRIVATE Threads::Threads)

Base classes

class AbstractImageConverter
Base for image converter plugins.

Constructors, destructors, conversion operators

OpenExrImageConverter(PluginManager::AbstractManager& manager, const std::string& plugin) explicit
Plugin manager constructor.