Magnum::Trade::BasisImageConverter class new in 2019.10

Basis Universal image converter plugin.

Creates Basis Universal compressed image files (*.basis or *.ktx2) from 2D and 2D array images with optional mip levels. You can use BasisImporter to import images in this format.

This plugin provides BasisKtxImageConverter.


This plugin depends on the Trade and Basis Universal libraries and is built if MAGNUM_WITH_BASISIMAGECONVERTER is enabled when building Magnum Plugins. To use as a dynamic plugin, load "BasisImageConverter" via Corrade::PluginManager::Manager. Current version of the plugin is tested against the v1_15_update2 tag, but could possibly compile against newer versions as well.

Additionally, if you're using Magnum as a CMake subproject, bundle the magnum-plugins and basis-universal repositories and do the following:

add_subdirectory(magnum-plugins EXCLUDE_FROM_ALL)

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

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

find_package(MagnumPlugins REQUIRED BasisImageConverter)

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

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

Behavior and limitations

The plugin recognizes ImageConverterFlag::Quiet, which will cause all conversion warnings to be suppressed.

Supported formats

The PixelFormat::R8Unorm, R8Srgb, RG8Unorm, RG8Srgb, RGB8Unorm, RGB8Srgb, RGBA8Unorm and RGBA8Srgb formats are supported.

Image types

The exporter can save 2D, 2D array, cube map and cube map array images, recognizing ImageFlag3D::Array and/or ImageFlag3D::CubeMap in passed images.

Even though the KTX container format supports 1D, 1D array and 3D images, Basis Universal doesn't. In particular, if a 2D image with ImageFlag2D::Array is passed, the conversion will fail as it's not possible to represent 1D array images without a significant loss in quality and layer cross-talk. On the other hand, if a 3D image without ImageFlag3D::Array is passed, a warning is printed and the file is saved as a 2D array image.

Multilevel images

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. Because only 2D array images are supported, depth has to have the same size in all levels. Incomplete mip chains are supported.

To generate mip levels from a single top-level image instead, you can use the mip_gen configuration option.

Implicit swizzling

If no user-specified channel mapping is supplied through the swizzle configuration option, the converter swizzles 1- and 2-channel formats before compression as follows:

  • 1-channel formats (PixelFormat::R8Unorm / PixelFormat::R8Srgb) are remapped as RRR, producing an opaque gray-scale image
  • 2-channel formats (PixelFormat::RG8Unorm / PixelFormat::RG8Srgb) are remapped as RRRG, ie. G becomes the alpha channel. This significantly improves compressed image quality because RGB and alpha get separate slices instead of the two channels being compressed into a single slice.

Setting the swizzle option to any value disables this behavior. To keep the original channel order, set swizzle=rgba.

Converting to KTX2

To create Khronos Texture 2.0 (*.ktx2) files, either load the plugin as BasisKtxImageConverter, call convertToFile() with the .ktx2 extension or pass Format::Ktx to the constructor. In all other cases, a Basis Universal (*.basis) file is created.

The extension() is "ktx2" and mimeType() "image/ktx2" if the plugin is loaded as BasisKtxImageConverter or Format::Ktx is passed to the constructor. In all other cases (and independently of what file extension is used in a call to convertToFile()), extension is "basis" and mimeType() is an empty string as the Basis Universal file format doesn't have a registered MIME type.

Loading the plugin fails with undefined symbol: pthread_create

On Linux it may happen that loading the plugin will fail with undefined symbol: pthread_create. The Basis encoder is optionally multithreaded and while linking the dynamic plugin library to pthread would resolve this particular error, the actual thread creation (if the threads configuration option is set to something else than 1) later would cause std::system_error to be thrown (or, worst case, crashing on a null function pointer call on some systems). Unfortunately there's no portable way to detect this case at runtime and fail gracefully, so the plugin requires the application to link to pthread instead. With CMake it can be done like this:

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

Thread safety

While the encoder library should behave in a way that doesn't modify any global state, in versions before 1.16 the library initialization done at plugin load time (or using initialize() when using the class witout a plugin manager) is populating global safe in a non-thread-safe way. Thus you have to ensure that the plugin isn't loaded from multiple threads at the same time, or loaded while being already used from another thread.

Plugin-specific configuration

Basis compression can be configured to produce better quality or reduce encoding time. Configuration options are equivalent to parameters of the C++ encoder API in basis_compressor. The basisu tool options mostly match the encoder API parameters and its help text provides useful descriptions of most of the parameters, their ranges and the impact on quality/speed. The full form of the configuration is shown below:

# All following options correspond to parameters of the `basis_compressor`
# C++ API and may differ from what the basisu tool exposes.

# Options
# Treat images as sRGB color data, rather than linear intensity. Leave blank
# to determine from the image format.

# More options
# The `normal_map` setting is just an alias disabling `perceptual` and
# `mip_srgb` and enabling `no_selector_rdo` & `no_endpoint_rdo`
# Remap color channels before compression. Must be empty or 4 characters
# long, valid characters are r,g,b,a. This replaced
# separate_rg_to_color_alpha, for the same effect use 'rrrg'.
# Number of threads Basis should use during compression, 0 sets it to the
# value returned by std::thread::hardware_concurrency(), 1 disables
# multithreading. This value is clamped to
# std::thread::hardware_concurrency() internally by Basis itself.

# Mipmap generation options
# Generate mipmaps from the base image. If you pass custom mip levels into
# openData, this option will be ignored. Leave blank to determine from the
# number of levels passed to convertToData.
# Filter mipmaps assuming sRGB color data, rather than linear intensity.
# Leave blank to determine from the image format.

# Backend endpoint/selector RDO codec options

# UASTC options

# KTX2 options

# Set various fields in the Basis file header

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

Base classes

class AbstractImageConverter
Base for image converter plugins.

Public types

enum class Format: Int { Basis = 1, Ktx }
Output file format.

Public static functions

static void initialize() new in Git master
Initialize Basis encoder.

Constructors, destructors, conversion operators

BasisImageConverter(Format format = Format{}) explicit
Default constructor.
BasisImageConverter(PluginManager::AbstractManager& manager, const Containers::StringView& plugin) explicit
Plugin manager constructor.

Enum documentation

enum class Magnum::Trade::BasisImageConverter::Format: Int

Output file format.


Output Basis images


Output KTX2 images

Function documentation

static void Magnum::Trade::BasisImageConverter::initialize() new in Git master

Initialize Basis encoder.

If the class is instantiated directly (not through a plugin manager), this function has to be called explicitly before using any instance.

Magnum::Trade::BasisImageConverter::BasisImageConverter(Format format = Format{}) explicit

Default constructor.

The converter outputs files in format defined by Format.