diff --git a/src/Magnum/Trade/AbstractImageConverter.cpp b/src/Magnum/Trade/AbstractImageConverter.cpp index b1bf513731..2c804a793b 100644 --- a/src/Magnum/Trade/AbstractImageConverter.cpp +++ b/src/Magnum/Trade/AbstractImageConverter.cpp @@ -47,7 +47,7 @@ namespace Magnum { namespace Trade { std::string AbstractImageConverter::pluginInterface() { return /* [interface] */ -"cz.mosra.magnum.Trade.AbstractImageConverter/0.3" +"cz.mosra.magnum.Trade.AbstractImageConverter/0.3.1" /* [interface] */ ; } @@ -226,8 +226,11 @@ Containers::Array AbstractImageConverter::convertToData(const ImageView1D& return out; } -Containers::Array AbstractImageConverter::doConvertToData(const ImageView1D&) { - CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::convertToData(): 1D image conversion advertised but not implemented", nullptr); +Containers::Array AbstractImageConverter::doConvertToData(const ImageView1D& image) { + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertLevels1DToData, + "Trade::AbstractImageConverter::convertToData(): 1D image conversion advertised but not implemented", nullptr); + + return doConvertToData(Containers::arrayView({image})); } Containers::Array AbstractImageConverter::convertToData(const ImageView2D& image) { @@ -239,8 +242,11 @@ Containers::Array AbstractImageConverter::convertToData(const ImageView2D& return out; } -Containers::Array AbstractImageConverter::doConvertToData(const ImageView2D&) { - CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::convertToData(): 2D image conversion advertised but not implemented", nullptr); +Containers::Array AbstractImageConverter::doConvertToData(const ImageView2D& image) { + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertLevels2DToData, + "Trade::AbstractImageConverter::convertToData(): 2D image conversion advertised but not implemented", nullptr); + + return doConvertToData(Containers::arrayView({image})); } #ifdef MAGNUM_BUILD_DEPRECATED @@ -258,8 +264,11 @@ Containers::Array AbstractImageConverter::convertToData(const ImageView3D& return out; } -Containers::Array AbstractImageConverter::doConvertToData(const ImageView3D&) { - CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::convertToData(): 3D image conversion advertised but not implemented", nullptr); +Containers::Array AbstractImageConverter::doConvertToData(const ImageView3D& image) { + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertLevels3DToData, + "Trade::AbstractImageConverter::convertToData(): 3D image conversion advertised but not implemented", nullptr); + + return doConvertToData(Containers::arrayView({image})); } Containers::Array AbstractImageConverter::convertToData(const CompressedImageView1D& image) { @@ -271,8 +280,11 @@ Containers::Array AbstractImageConverter::convertToData(const CompressedIm return out; } -Containers::Array AbstractImageConverter::doConvertToData(const CompressedImageView1D&) { - CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::convertToData(): compressed 1D image conversion advertised but not implemented", nullptr); +Containers::Array AbstractImageConverter::doConvertToData(const CompressedImageView1D& image) { + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertCompressedLevels1DToData, + "Trade::AbstractImageConverter::convertToData(): compressed 1D image conversion advertised but not implemented", nullptr); + + return doConvertToData(Containers::arrayView({image})); } Containers::Array AbstractImageConverter::convertToData(const CompressedImageView2D& image) { @@ -284,8 +296,11 @@ Containers::Array AbstractImageConverter::convertToData(const CompressedIm return out; } -Containers::Array AbstractImageConverter::doConvertToData(const CompressedImageView2D&) { - CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::convertToData(): compressed 2D image conversion advertised but not implemented", nullptr); +Containers::Array AbstractImageConverter::doConvertToData(const CompressedImageView2D& image) { + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertCompressedLevels2DToData, + "Trade::AbstractImageConverter::convertToData(): compressed 2D image conversion advertised but not implemented", nullptr); + + return doConvertToData(Containers::arrayView({image})); } #ifdef MAGNUM_BUILD_DEPRECATED @@ -303,8 +318,11 @@ Containers::Array AbstractImageConverter::convertToData(const CompressedIm return out; } -Containers::Array AbstractImageConverter::doConvertToData(const CompressedImageView3D&) { - CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::convertToData(): compressed 3D image conversion advertised but not implemented", nullptr); +Containers::Array AbstractImageConverter::doConvertToData(const CompressedImageView3D& image) { + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertCompressedLevels3DToData, + "Trade::AbstractImageConverter::convertToData(): compressed 3D image conversion advertised but not implemented", nullptr); + + return doConvertToData(Containers::arrayView({image})); } Containers::Array AbstractImageConverter::convertToData(const ImageData1D& image) { @@ -325,6 +343,108 @@ Containers::Array AbstractImageConverter::convertToData(const ImageData3D& return image.isCompressed() ? convertToData(CompressedImageView3D(image)) : convertToData(ImageView3D(image)); } +Containers::Array AbstractImageConverter::convertToData(const Containers::ArrayView imageLevels) { + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertLevels1DToData, + "Trade::AbstractImageConverter::convertToData(): multi-level 1D image conversion not supported", nullptr); + + Containers::Array out = doConvertToData(imageLevels); + CORRADE_ASSERT(!out.deleter(), "Trade::AbstractImageConverter::convertToData(): implementation is not allowed to use a custom Array deleter", {}); + return out; +} + +Containers::Array AbstractImageConverter::convertToData(const std::initializer_list imageLevels) { + return convertToData(Containers::arrayView(imageLevels)); +} + +Containers::Array AbstractImageConverter::doConvertToData(Containers::ArrayView) { + CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::convertToData(): multi-level 1D image conversion advertised but not implemented", nullptr); +} + +Containers::Array AbstractImageConverter::convertToData(const Containers::ArrayView imageLevels) { + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertLevels2DToData, + "Trade::AbstractImageConverter::convertToData(): multi-level 2D image conversion not supported", nullptr); + + Containers::Array out = doConvertToData(imageLevels); + CORRADE_ASSERT(!out.deleter(), "Trade::AbstractImageConverter::convertToData(): implementation is not allowed to use a custom Array deleter", {}); + return out; +} + +Containers::Array AbstractImageConverter::convertToData(const std::initializer_list imageLevels) { + return convertToData(Containers::arrayView(imageLevels)); +} + +Containers::Array AbstractImageConverter::doConvertToData(Containers::ArrayView) { + CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::convertToData(): multi-level 2D image conversion advertised but not implemented", nullptr); +} + +Containers::Array AbstractImageConverter::convertToData(const Containers::ArrayView imageLevels) { + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertLevels3DToData, + "Trade::AbstractImageConverter::convertToData(): multi-level 3D image conversion not supported", nullptr); + + Containers::Array out = doConvertToData(imageLevels); + CORRADE_ASSERT(!out.deleter(), "Trade::AbstractImageConverter::convertToData(): implementation is not allowed to use a custom Array deleter", {}); + return out; +} + +Containers::Array AbstractImageConverter::convertToData(const std::initializer_list imageLevels) { + return convertToData(Containers::arrayView(imageLevels)); +} + +Containers::Array AbstractImageConverter::doConvertToData(Containers::ArrayView) { + CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::convertToData(): multi-level 3D image conversion advertised but not implemented", nullptr); +} + +Containers::Array AbstractImageConverter::convertToData(const Containers::ArrayView imageLevels) { + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertCompressedLevels1DToData, + "Trade::AbstractImageConverter::convertToData(): multi-level compressed 1D image conversion not supported", nullptr); + + Containers::Array out = doConvertToData(imageLevels); + CORRADE_ASSERT(!out.deleter(), "Trade::AbstractImageConverter::convertToData(): implementation is not allowed to use a custom Array deleter", {}); + return out; +} + +Containers::Array AbstractImageConverter::convertToData(const std::initializer_list imageLevels) { + return convertToData(Containers::arrayView(imageLevels)); +} + +Containers::Array AbstractImageConverter::doConvertToData(Containers::ArrayView) { + CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::convertToData(): multi-level compressed 1D image conversion advertised but not implemented", nullptr); +} + +Containers::Array AbstractImageConverter::convertToData(const Containers::ArrayView imageLevels) { + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertCompressedLevels2DToData, + "Trade::AbstractImageConverter::convertToData(): multi-level compressed 2D image conversion not supported", nullptr); + + Containers::Array out = doConvertToData(imageLevels); + CORRADE_ASSERT(!out.deleter(), "Trade::AbstractImageConverter::convertToData(): implementation is not allowed to use a custom Array deleter", {}); + return out; +} + +Containers::Array AbstractImageConverter::convertToData(const std::initializer_list imageLevels) { + return convertToData(Containers::arrayView(imageLevels)); +} + +Containers::Array AbstractImageConverter::doConvertToData(Containers::ArrayView) { + CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::convertToData(): multi-level compressed 2D image conversion advertised but not implemented", nullptr); +} + +Containers::Array AbstractImageConverter::convertToData(const Containers::ArrayView imageLevels) { + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertCompressedLevels3DToData, + "Trade::AbstractImageConverter::convertToData(): multi-level compressed 3D image conversion not supported", nullptr); + + Containers::Array out = doConvertToData(imageLevels); + CORRADE_ASSERT(!out.deleter(), "Trade::AbstractImageConverter::convertToData(): implementation is not allowed to use a custom Array deleter", {}); + return out; +} + +Containers::Array AbstractImageConverter::convertToData(const std::initializer_list imageLevels) { + return convertToData(Containers::arrayView(imageLevels)); +} + +Containers::Array AbstractImageConverter::doConvertToData(Containers::ArrayView) { + CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::convertToData(): multi-level compressed 3D image conversion advertised but not implemented", nullptr); +} + bool AbstractImageConverter::convertToFile(const ImageView1D& image, const Containers::StringView filename) { CORRADE_ASSERT(features() & ImageConverterFeature::Convert1DToFile, "Trade::AbstractImageConverter::convertToFile(): 1D image conversion not supported", {}); @@ -333,6 +453,12 @@ bool AbstractImageConverter::convertToFile(const ImageView1D& image, const Conta } bool AbstractImageConverter::doConvertToFile(const ImageView1D& image, const Containers::StringView filename) { + /* Prefer to go through the ToFile variant instead of ToData assuming that + it could have a more memory-efficient implementation than having to + materialize the whole output in memory first */ + if(features() >= ImageConverterFeature::ConvertLevels1DToFile) + return doConvertToFile(Containers::arrayView({image}), filename); + CORRADE_ASSERT(features() >= ImageConverterFeature::Convert1DToData, "Trade::AbstractImageConverter::convertToFile(): 1D image conversion advertised but not implemented", false); const auto data = doConvertToData(image); @@ -355,6 +481,12 @@ bool AbstractImageConverter::convertToFile(const ImageView2D& image, const Conta } bool AbstractImageConverter::doConvertToFile(const ImageView2D& image, const Containers::StringView filename) { + /* Prefer to go through the ToFile variant instead of ToData assuming that + it could have a more memory-efficient implementation than having to + materialize the whole output in memory first */ + if(features() >= ImageConverterFeature::ConvertLevels2DToFile) + return doConvertToFile(Containers::arrayView({image}), filename); + CORRADE_ASSERT(features() >= ImageConverterFeature::Convert2DToData, "Trade::AbstractImageConverter::convertToFile(): 2D image conversion advertised but not implemented", false); const auto data = doConvertToData(image); @@ -383,6 +515,12 @@ bool AbstractImageConverter::convertToFile(const ImageView3D& image, const Conta } bool AbstractImageConverter::doConvertToFile(const ImageView3D& image, const Containers::StringView filename) { + /* Prefer to go through the ToFile variant instead of ToData assuming that + it could have a more memory-efficient implementation than having to + materialize the whole output in memory first */ + if(features() >= ImageConverterFeature::ConvertLevels3DToFile) + return doConvertToFile(Containers::arrayView({image}), filename); + CORRADE_ASSERT(features() >= ImageConverterFeature::Convert3DToData, "Trade::AbstractImageConverter::convertToFile(): 3D image conversion advertised but not implemented", false); const auto data = doConvertToData(image); @@ -405,6 +543,12 @@ bool AbstractImageConverter::convertToFile(const CompressedImageView1D& image, c } bool AbstractImageConverter::doConvertToFile(const CompressedImageView1D& image, Containers::StringView filename) { + /* Prefer to go through the ToFile variant instead of ToData assuming that + it could have a more memory-efficient implementation than having to + materialize the whole output in memory first */ + if(features() >= ImageConverterFeature::ConvertCompressedLevels1DToFile) + return doConvertToFile(Containers::arrayView({image}), filename); + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertCompressed1DToData, "Trade::AbstractImageConverter::convertToFile(): compressed 1D image conversion advertised but not implemented", false); const auto data = doConvertToData(image); @@ -427,6 +571,12 @@ bool AbstractImageConverter::convertToFile(const CompressedImageView2D& image, c } bool AbstractImageConverter::doConvertToFile(const CompressedImageView2D& image, Containers::StringView filename) { + /* Prefer to go through the ToFile variant instead of ToData assuming that + it could have a more memory-efficient implementation than having to + materialize the whole output in memory first */ + if(features() >= ImageConverterFeature::ConvertCompressedLevels2DToFile) + return doConvertToFile(Containers::arrayView({image}), filename); + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertCompressed2DToData, "Trade::AbstractImageConverter::convertToFile(): compressed 2D image conversion advertised but not implemented", false); const auto data = doConvertToData(image); @@ -455,6 +605,12 @@ bool AbstractImageConverter::convertToFile(const CompressedImageView3D& image, c } bool AbstractImageConverter::doConvertToFile(const CompressedImageView3D& image, Containers::StringView filename) { + /* Prefer to go through the ToFile variant instead of ToData assuming that + it could have a more memory-efficient implementation than having to + materialize the whole output in memory first */ + if(features() >= ImageConverterFeature::ConvertCompressedLevels3DToFile) + return doConvertToFile(Containers::arrayView({image}), filename); + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertCompressed3DToData, "Trade::AbstractImageConverter::convertToFile(): compressed 3D image conversion advertised but not implemented", false); const auto data = doConvertToData(image); @@ -487,6 +643,162 @@ bool AbstractImageConverter::convertToFile(const ImageData3D& image, const Conta return image.isCompressed() ? convertToFile(CompressedImageView3D(image), filename) : convertToFile(ImageView3D(image), filename); } +bool AbstractImageConverter::convertToFile(const Containers::ArrayView imageLevels, const Containers::StringView filename) { + CORRADE_ASSERT(features() & ImageConverterFeature::ConvertLevels1DToFile, + "Trade::AbstractImageConverter::convertToFile(): multi-level 1D image conversion not supported", {}); + + return doConvertToFile(imageLevels, filename); +} + +bool AbstractImageConverter::convertToFile(const std::initializer_list imageLevels, const Containers::StringView filename) { + return convertToFile(Containers::arrayView(imageLevels), filename); +} + +bool AbstractImageConverter::doConvertToFile(const Containers::ArrayView imageLevels, const Containers::StringView filename) { + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertLevels1DToData, "Trade::AbstractImageConverter::convertToFile(): multi-level 1D image conversion advertised but not implemented", false); + + const auto data = doConvertToData(imageLevels); + /* No deleter checks as it doesn't matter here */ + if(!data) return false; + + if(!Utility::Directory::write(filename, data)) { + Error() << "Trade::AbstractImageConverter::convertToFile(): cannot write to file" << filename; + return false; + } + + return true; +} + +bool AbstractImageConverter::convertToFile(const Containers::ArrayView imageLevels, const Containers::StringView filename) { + CORRADE_ASSERT(features() & ImageConverterFeature::ConvertLevels2DToFile, + "Trade::AbstractImageConverter::convertToFile(): multi-level 2D image conversion not supported", {}); + + return doConvertToFile(imageLevels, filename); +} + +bool AbstractImageConverter::convertToFile(const std::initializer_list imageLevels, const Containers::StringView filename) { + return convertToFile(Containers::arrayView(imageLevels), filename); +} + +bool AbstractImageConverter::doConvertToFile(const Containers::ArrayView imageLevels, const Containers::StringView filename) { + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertLevels2DToData, "Trade::AbstractImageConverter::convertToFile(): multi-level 2D image conversion advertised but not implemented", false); + + const auto data = doConvertToData(imageLevels); + /* No deleter checks as it doesn't matter here */ + if(!data) return false; + + if(!Utility::Directory::write(filename, data)) { + Error() << "Trade::AbstractImageConverter::convertToFile(): cannot write to file" << filename; + return false; + } + + return true; +} + +bool AbstractImageConverter::convertToFile(const Containers::ArrayView imageLevels, const Containers::StringView filename) { + CORRADE_ASSERT(features() & ImageConverterFeature::ConvertLevels3DToFile, + "Trade::AbstractImageConverter::convertToFile(): multi-level 3D image conversion not supported", {}); + + return doConvertToFile(imageLevels, filename); +} + +bool AbstractImageConverter::convertToFile(const std::initializer_list imageLevels, const Containers::StringView filename) { + return convertToFile(Containers::arrayView(imageLevels), filename); +} + +bool AbstractImageConverter::doConvertToFile(const Containers::ArrayView imageLevels, const Containers::StringView filename) { + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertLevels3DToData, "Trade::AbstractImageConverter::convertToFile(): multi-level 3D image conversion advertised but not implemented", false); + + const auto data = doConvertToData(imageLevels); + /* No deleter checks as it doesn't matter here */ + if(!data) return false; + + if(!Utility::Directory::write(filename, data)) { + Error() << "Trade::AbstractImageConverter::convertToFile(): cannot write to file" << filename; + return false; + } + + return true; +} + +bool AbstractImageConverter::convertToFile(const Containers::ArrayView imageLevels, const Containers::StringView filename) { + CORRADE_ASSERT(features() & ImageConverterFeature::ConvertCompressedLevels1DToFile, + "Trade::AbstractImageConverter::convertToFile(): multi-level compressed 1D image conversion not supported", {}); + + return doConvertToFile(imageLevels, filename); +} + +bool AbstractImageConverter::convertToFile(const std::initializer_list imageLevels, const Containers::StringView filename) { + return convertToFile(Containers::arrayView(imageLevels), filename); +} + +bool AbstractImageConverter::doConvertToFile(const Containers::ArrayView imageLevels, Containers::StringView filename) { + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertCompressedLevels1DToData, "Trade::AbstractImageConverter::convertToFile(): multi-level compressed 1D image conversion advertised but not implemented", false); + + const auto data = doConvertToData(imageLevels); + /* No deleter checks as it doesn't matter here */ + if(!data) return false; + + if(!Utility::Directory::write(filename, data)) { + Error() << "Trade::AbstractImageConverter::convertToFile(): cannot write to file" << filename; + return false; + } + + return true; +} + +bool AbstractImageConverter::convertToFile(const Containers::ArrayView imageLevels, const Containers::StringView filename) { + CORRADE_ASSERT(features() & ImageConverterFeature::ConvertCompressedLevels2DToFile, + "Trade::AbstractImageConverter::convertToFile(): multi-level compressed 2D image conversion not supported", {}); + + return doConvertToFile(imageLevels, filename); +} + +bool AbstractImageConverter::convertToFile(const std::initializer_list imageLevels, const Containers::StringView filename) { + return convertToFile(Containers::arrayView(imageLevels), filename); +} + +bool AbstractImageConverter::doConvertToFile(const Containers::ArrayView imageLevels, Containers::StringView filename) { + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertCompressedLevels2DToData, "Trade::AbstractImageConverter::convertToFile(): multi-level compressed 2D image conversion advertised but not implemented", false); + + const auto data = doConvertToData(imageLevels); + /* No deleter checks as it doesn't matter here */ + if(!data) return false; + + if(!Utility::Directory::write(filename, data)) { + Error() << "Trade::AbstractImageConverter::convertToFile(): cannot write to file" << filename; + return false; + } + + return true; +} + +bool AbstractImageConverter::convertToFile(const Containers::ArrayView imageLevels, const Containers::StringView filename) { + CORRADE_ASSERT(features() & ImageConverterFeature::ConvertCompressedLevels3DToFile, + "Trade::AbstractImageConverter::convertToFile(): multi-level compressed 3D image conversion not supported", {}); + + return doConvertToFile(imageLevels, filename); +} + +bool AbstractImageConverter::convertToFile(const std::initializer_list imageLevels, const Containers::StringView filename) { + return convertToFile(Containers::arrayView(imageLevels), filename); +} + +bool AbstractImageConverter::doConvertToFile(const Containers::ArrayView imageLevels, Containers::StringView filename) { + CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertCompressedLevels3DToData, "Trade::AbstractImageConverter::convertToFile(): multi-level compressed 3D image conversion advertised but not implemented", false); + + const auto data = doConvertToData(imageLevels); + /* No deleter checks as it doesn't matter here */ + if(!data) return false; + + if(!Utility::Directory::write(filename, data)) { + Error() << "Trade::AbstractImageConverter::convertToFile(): cannot write to file" << filename; + return false; + } + + return true; +} + Debug& operator<<(Debug& debug, const ImageConverterFeature value) { debug << "Trade::ImageConverterFeature" << Debug::nospace; @@ -511,6 +823,18 @@ Debug& operator<<(Debug& debug, const ImageConverterFeature value) { _c(ConvertCompressed1DToData) _c(ConvertCompressed2DToData) _c(ConvertCompressed3DToData) + _c(ConvertLevels1DToFile) + _c(ConvertLevels2DToFile) + _c(ConvertLevels3DToFile) + _c(ConvertCompressedLevels1DToFile) + _c(ConvertCompressedLevels2DToFile) + _c(ConvertCompressedLevels3DToFile) + _c(ConvertLevels1DToData) + _c(ConvertLevels2DToData) + _c(ConvertLevels3DToData) + _c(ConvertCompressedLevels1DToData) + _c(ConvertCompressedLevels2DToData) + _c(ConvertCompressedLevels3DToData) #undef _c /* LCOV_EXCL_STOP */ } @@ -526,13 +850,30 @@ Debug& operator<<(Debug& debug, const ImageConverterFeatures value) { ImageConverterFeature::ConvertCompressed1D, ImageConverterFeature::ConvertCompressed2D, ImageConverterFeature::ConvertCompressed3D, + ImageConverterFeature::ConvertLevels1DToData, + ImageConverterFeature::ConvertLevels2DToData, + ImageConverterFeature::ConvertLevels3DToData, + ImageConverterFeature::ConvertCompressedLevels1DToData, + ImageConverterFeature::ConvertCompressedLevels2DToData, + ImageConverterFeature::ConvertCompressedLevels3DToData, + /* These 6 are implied by Convert[Compressed]LevelsToData, so have to + be after */ + ImageConverterFeature::ConvertLevels1DToFile, + ImageConverterFeature::ConvertLevels2DToFile, + ImageConverterFeature::ConvertLevels3DToFile, + ImageConverterFeature::ConvertCompressedLevels1DToFile, + ImageConverterFeature::ConvertCompressedLevels2DToFile, + ImageConverterFeature::ConvertCompressedLevels3DToFile, + /* These 12 are implied by Convert[Compressed]LevelsTo{File,Data}, so + have to be after */ ImageConverterFeature::Convert1DToData, ImageConverterFeature::Convert2DToData, ImageConverterFeature::Convert3DToData, ImageConverterFeature::ConvertCompressed1DToData, ImageConverterFeature::ConvertCompressed2DToData, ImageConverterFeature::ConvertCompressed3DToData, - /* These are implied by Convert[Compressed]ToData, so have to be last */ + /* These 6 are implied by Convert[Compressed]ToData, so have to be + after */ ImageConverterFeature::Convert1DToFile, ImageConverterFeature::Convert2DToFile, ImageConverterFeature::Convert3DToFile, diff --git a/src/Magnum/Trade/AbstractImageConverter.h b/src/Magnum/Trade/AbstractImageConverter.h index b098f94f96..4a639c15a9 100644 --- a/src/Magnum/Trade/AbstractImageConverter.h +++ b/src/Magnum/Trade/AbstractImageConverter.h @@ -230,7 +230,115 @@ enum class ImageConverterFeature: UnsignedInt { * Implies @ref ImageConverterFeature::ConvertCompressed3DToFile. * @m_since_latest */ - ConvertCompressed3DToData = ConvertCompressed3DToFile|(1 << 13) + ConvertCompressed3DToData = ConvertCompressed3DToFile|(1 << 13), + + /** + * Convert a set of 1D image levels to a file with + * @ref AbstractImageConverter::convertToFile(Containers::ArrayView, Containers::StringView). + * Implies @ref ImageConverterFeature::Convert1DToFile. + * @m_since_latest + */ + ConvertLevels1DToFile = Convert1DToFile|(1 << 14), + + /** + * Convert a set of 2D image levels to a file with + * @ref AbstractImageConverter::convertToFile(Containers::ArrayView, Containers::StringView). + * Implies @ref ImageConverterFeature::Convert2DToFile. + * @m_since_latest + */ + ConvertLevels2DToFile = Convert2DToFile|(1 << 14), + + /** + * Convert a set of 3D image levels to a file with + * @ref AbstractImageConverter::convertToFile(Containers::ArrayView, Containers::StringView). + * Implies @ref ImageConverterFeature::Convert3DToFile. + * @m_since_latest + */ + ConvertLevels3DToFile = Convert3DToFile|(1 << 14), + + /** + * Convert a set of compressed 1D image levels to a file with + * @ref AbstractImageConverter::convertToFile(Containers::ArrayView, Containers::StringView). + * Implies @ref ImageConverterFeature::ConvertCompressed1DToFile. + * @m_since_latest + */ + ConvertCompressedLevels1DToFile = ConvertCompressed1DToFile|(1 << 14), + + /** + * Convert a set of compressed 2D image levels to a file with + * @ref AbstractImageConverter::convertToFile(Containers::ArrayView, Containers::StringView). + * Implies @ref ImageConverterFeature::ConvertCompressed2DToFile. + * @m_since_latest + */ + ConvertCompressedLevels2DToFile = ConvertCompressed2DToFile|(1 << 14), + + /** + * Convert a set of compressed 3D image levels to a file with + * @ref AbstractImageConverter::convertToFile(Containers::ArrayView, Containers::StringView). + * Implies @ref ImageConverterFeature::ConvertCompressed3DToFile. + * @m_since_latest + */ + ConvertCompressedLevels3DToFile = ConvertCompressed3DToFile|(1 << 14), + + /** + * Convert a set of 1D image levels to raw data with + * @ref AbstractImageConverter::convertToData(Containers::ArrayView). + * Implies @ref ImageConverterFeature::ConvertLevels1DToFile and + * @relativeref{ImageConverterFeature,Convert1DToData}, which implies also + * @relativeref{ImageConverterFeature,Convert1DToFile}. + * @m_since_latest + */ + ConvertLevels1DToData = ConvertLevels1DToFile|Convert1DToData|(1 << 14), + + /** + * Convert a set of 2D image levels to raw data with + * @ref AbstractImageConverter::convertToData(Containers::ArrayView). + * Implies @ref ImageConverterFeature::ConvertLevels2DToFile and + * @relativeref{ImageConverterFeature,Convert2DToData}, which implies also + * @relativeref{ImageConverterFeature,Convert2DToFile}. + * @m_since_latest + */ + ConvertLevels2DToData = ConvertLevels2DToFile|Convert2DToData|(1 << 14), + + /** + * Convert a set of 3D image levels to raw data with + * @ref AbstractImageConverter::convertToData(Containers::ArrayView). + * Implies @ref ImageConverterFeature::ConvertLevels3DToFile and + * @relativeref{ImageConverterFeature,Convert3DToData}, which implies also + * @relativeref{ImageConverterFeature,Convert3DToFile}. + * @m_since_latest + */ + ConvertLevels3DToData = ConvertLevels3DToFile|Convert3DToData|(1 << 14), + + /** + * Convert a set of compressed 1D image levels to raw data with + * @ref AbstractImageConverter::convertToData(Containers::ArrayView). + * Implies @ref ImageConverterFeature::ConvertCompressedLevels1DToFile and + * @relativeref{ImageConverterFeature,ConvertCompressed1DToData}, which + * implies also @relativeref{ImageConverterFeature,ConvertCompressed1DToFile}. + * @m_since_latest + */ + ConvertCompressedLevels1DToData = ConvertCompressedLevels1DToFile|ConvertCompressed1DToData|(1 << 14), + + /** + * Convert a set of compressed 2D image levels to raw data with + * @ref AbstractImageConverter::convertToData(Containers::ArrayView). + * Implies @ref ImageConverterFeature::ConvertCompressedLevels2DToFile and + * @relativeref{ImageConverterFeature,ConvertCompressed2DToData}, which + * implies also @relativeref{ImageConverterFeature,ConvertCompressed2DToFile}. + * @m_since_latest + */ + ConvertCompressedLevels2DToData = ConvertCompressedLevels2DToFile|ConvertCompressed2DToData|(1 << 14), + + /** + * Convert a set of compressed 3D image levels to raw data with + * @ref AbstractImageConverter::convertToData(Containers::ArrayView). + * Implies @ref ImageConverterFeature::ConvertCompressedLevels3DToFile and + * @relativeref{ImageConverterFeature,ConvertCompressed3DToData}, which + * implies also @relativeref{ImageConverterFeature,ConvertCompressed3DToFile}. + * @m_since_latest + */ + ConvertCompressedLevels3DToData = ConvertCompressedLevels3DToFile|ConvertCompressed3DToData|(1 << 14) }; /** @@ -297,10 +405,10 @@ MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, ImageConverterFlags value); Provides functionality for converting images between various formats, compressing them or saving to files. -The interface supports two main kinds of operation, with implementations -commonly advertising support for either one or the other via @ref features(): +The interface supports three main kinds of operation, with implementations +commonly advertising support for a subset of them via @ref features(): -- Saving a (compressed) 1D/2D/3D image to a file / data using +- Saving a single (compressed) 1D/2D/3D image to a file / data using @ref convertToFile() / @ref convertToData(). This is mostly for exporting the image data to a common format like JPEG or PNG in order to be used with an external tool. Advertised with @@ -317,6 +425,25 @@ commonly advertising support for either one or the other via @ref features(): @relativeref{ImageConverterFeature,ConvertCompressed2DToData} / @relativeref{ImageConverterFeature,ConvertCompressed3DToData} for compressed input images. +- Saving a set of (compressed) 1D/2D/3D image levels to a file / data using + @ref convertToFile() / @ref convertToData(). Common use case is to save + already pregenerated levels instead of having to create them during load. + Advertised with @ref ImageConverterFeature::ConvertLevels1DToFile / + @relativeref{ImageConverterFeature,ConvertLevels2DToFile} / + @relativeref{ImageConverterFeature,ConvertLevels3DToFile} or + @ref ImageConverterFeature::ConvertLevels1DToData / + @relativeref{ImageConverterFeature,ConvertLevels2DToData} / + @relativeref{ImageConverterFeature,ConvertLevels3DToData} and + @ref ImageConverterFeature::ConvertCompressedLevels1DToFile / + @relativeref{ImageConverterFeature,ConvertCompressedLevels2DToFile} / + @relativeref{ImageConverterFeature,ConvertCompressedLevels3DToFile} or + @ref ImageConverterFeature::ConvertCompressedLevels1DToData + @relativeref{ImageConverterFeature,ConvertCompressedLevels2DToData} / + @relativeref{ImageConverterFeature,ConvertCompressedLevels3DToData} for + compressed input images. Note that if a plugin advertises those, it's also + capable of saving single images --- in that case the single-image + @ref convertToFile() / @ref convertToData() delegates to the multi-level + variant with just a single image. - Performing an operation on the image data itself using @ref convert(), from which you get an @ref ImageData back again. This includes operations like pixel format conversion or for example resampling. Advertised with @@ -417,15 +544,27 @@ checked by the implementation: - The function @ref doConvertToData(const ImageView2D&) is called only if @ref ImageConverterFeature::Convert2DToData is supported and equivalently for the 1D and 3D case. +- The function @ref doConvertToData(Containers::ArrayView) + is called only if @ref ImageConverterFeature::ConvertLevels2DToData is + supported and equivalently for the 1D and 3D case. - The function @ref doConvertToData(const CompressedImageView2D&) is called only if @ref ImageConverterFeature::ConvertCompressed2DToData is supported and equivalently for the 1D and 3D case. +- The function @ref doConvertToData(Containers::ArrayView) + is called only if @ref ImageConverterFeature::ConvertCompressedLevels2DToData + is supported and equivalently for the 1D and 3D case. - The function @ref doConvertToFile(const ImageView2D&, Containers::StringView) is called only if @ref ImageConverterFeature::Convert2DToFile is supported and equivalently for the 1D and 3D case. +- The function @ref doConvertToFile(Containers::ArrayView, Containers::StringView) + is called only if @ref ImageConverterFeature::ConvertLevels2DToFile is + supported and equivalently for the 1D and 3D case. - The function @ref doConvertToFile(const CompressedImageView2D&, Containers::StringView) is called only if @ref ImageConverterFeature::ConvertCompressed2DToFile is supported and equivalently for the 1D and 3D case. +- The function @ref doConvertToFile(Containers::ArrayView, Containers::StringView) + is called only if @ref ImageConverterFeature::ConvertCompressedLevels2DToFile + is supported and equivalently for the 1D and 3D case. @m_class{m-block m-warning} @@ -642,6 +781,10 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract * @ref convert(const ImageView1D&) or * @ref convert(const CompressedImageView1D&). See documentation of * these two functions for details. + * + * This overload is not provided for multi-level conversion as the + * view list creation can be done more optimally on the application + * side. * @see @ref ImageData::isCompressed() */ Containers::Optional convert(const ImageData1D& image); @@ -654,6 +797,10 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract * @ref convert(const ImageView2D&) or * @ref convert(const CompressedImageView2D&). See documentation of * these two functions for details. + * + * This overload is not provided for multi-level conversion as the + * view list creation can be done more optimally on the application + * side. * @see @ref ImageData::isCompressed() */ Containers::Optional convert(const ImageData2D& image); @@ -666,6 +813,10 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract * @ref convert(const ImageView3D&) or * @ref convert(const CompressedImageView3D&). See documentation of * these two functions for details. + * + * This overload is not provided for multi-level conversion as the + * view list creation can be done more optimally on the application + * side. * @see @ref ImageData::isCompressed() */ Containers::Optional convert(const ImageData3D& image); @@ -674,8 +825,9 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract * @brief Convert a 1D image to a raw data * @m_since_latest * - * Available only if @ref ImageConverterFeature::Convert1DToData is - * supported. Returns data on success, @cpp nullptr @ce otherwise. + * Available only if @ref ImageConverterFeature::Convert1DToData or + * @ref ImageConverterFeature::ConvertLevels1DToData is supported. + * Returns data on success, @cpp nullptr @ce otherwise. * @see @ref features(), @ref convertToData(const CompressedImageView1D&), * @ref convertToData(const ImageData1D&), @ref convert(), * @ref convertToFile() @@ -686,8 +838,9 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract * @brief Convert a 2D image to a raw data * @m_since_latest * - * Available only if @ref ImageConverterFeature::Convert2DToData is - * supported. Returns data on success, @cpp nullptr @ce otherwise. + * Available only if @ref ImageConverterFeature::Convert2DToData or + * @ref ImageConverterFeature::ConvertLevels2DToData is supported. + * Returns data on success, @cpp nullptr @ce otherwise. * @see @ref features(), @ref convertToData(const CompressedImageView2D&), * @ref convertToData(const ImageData2D&), @ref convert(), * @ref convertToFile() @@ -707,8 +860,9 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract * @brief Convert a 3D image to a raw data * @m_since_latest * - * Available only if @ref ImageConverterFeature::Convert3DToData is - * supported. Returns data on success, @cpp nullptr @ce otherwise. + * Available only if @ref ImageConverterFeature::Convert3DToData or + * @ref ImageConverterFeature::ConvertLevels3DToData is supported. + * Returns data on success, @cpp nullptr @ce otherwise. * @see @ref features(), @ref convertToData(const CompressedImageView3D&), * @ref convertToData(const ImageData3D&), @ref convert(), * @ref convertToFile() @@ -720,7 +874,8 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract * @m_since_latest * * Available only if @ref ImageConverterFeature::ConvertCompressed1DToData - * is supported. Returns data on success, @cpp nullptr @ce otherwise. + * or @ref ImageConverterFeature::ConvertCompressedLevels1DToData is + * supported. Returns data on success, @cpp nullptr @ce otherwise. * @see @ref features(), @ref convertToData(const ImageView1D&), * @ref convertToData(const ImageData1D&), @ref convert(), * @ref convertToFile() @@ -732,7 +887,8 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract * @m_since_latest * * Available only if @ref ImageConverterFeature::ConvertCompressed2DToData - * is supported. Returns data on success, @cpp nullptr @ce otherwise. + * or @ref ImageConverterFeature::ConvertCompressedLevels2DToData is + * supported. Returns data on success, @cpp nullptr @ce otherwise. * @see @ref features(), @ref convertToData(const ImageView2D&), * @ref convertToData(const ImageData2D&), @ref convert(), * @ref convertToFile() @@ -753,7 +909,8 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract * @m_since_latest * * Available only if @ref ImageConverterFeature::ConvertCompressed3DToData - * is supported. Returns data on success, @cpp nullptr @ce otherwise. + * or @ref ImageConverterFeature::ConvertCompressedLevels3DToData is + * supported. Returns data on success, @cpp nullptr @ce otherwise. * @see @ref features(), @ref convertToData(const ImageView3D&), * @ref convertToData(const ImageData3D&), @ref convert(), * @ref convertToFile() @@ -805,6 +962,102 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract */ Containers::Array convertToData(const ImageData3D& image); + /** + * @brief Convert a set of 1D image levels to a raw data + * @m_since_latest + * + * Available only if @ref ImageConverterFeature::ConvertLevels1DToData + * is supported. Note that certain converters may impose size and order + * restrictions on the images, see documentation of a particular plugin + * for more information. Returns data on success, @cpp nullptr @ce + * otherwise. + * @see @ref features(), @ref convertToData(Containers::ArrayView), + * @ref convert(), @ref convertToFile() + */ + Containers::Array convertToData(Containers::ArrayView imageLevels); + /** @overload */ + Containers::Array convertToData(std::initializer_list imageLevels); + + /** + * @brief Convert a set of 2D image levels to a raw data + * @m_since_latest + * + * Available only if @ref ImageConverterFeature::ConvertLevels2DToData + * is supported. Note that certain converters may impose size and order + * restrictions on the images, see documentation of a particular plugin + * for more information. Returns data on success, @cpp nullptr @ce + * otherwise. + * @see @ref features(), @ref convertToData(Containers::ArrayView), + * @ref convert(), @ref convertToFile() + */ + Containers::Array convertToData(Containers::ArrayView imageLevels); + /** @overload */ + Containers::Array convertToData(std::initializer_list imageLevels); + + /** + * @brief Convert a set of 3D image levels to a raw data + * @m_since_latest + * + * Available only if @ref ImageConverterFeature::ConvertLevels3DToData + * is supported. Note that certain converters may impose size and order + * restrictions on the images, see documentation of a particular plugin + * for more information. Returns data on success, @cpp nullptr @ce + * otherwise. + * @see @ref features(), @ref convertToData(Containers::ArrayView), + * @ref convert(), @ref convertToFile() + */ + Containers::Array convertToData(Containers::ArrayView imageLevels); + /** @overload */ + Containers::Array convertToData(std::initializer_list imageLevels); + + /** + * @brief Convert a set of compressed 1D image levels to a raw data + * @m_since_latest + * + * Available only if @ref ImageConverterFeature::ConvertCompressedLevels1DToData + * is supported. Note that certain converters may impose size and order + * restrictions on the images, see documentation of a particular plugin + * for more information. Returns data on success, @cpp nullptr @ce + * otherwise. + * @see @ref features(), @ref convertToData(Containers::ArrayView), + * @ref convert(), @ref convertToFile() + */ + Containers::Array convertToData(Containers::ArrayView imageLevels); + /** @overload */ + Containers::Array convertToData(std::initializer_list imageLevels); + + /** + * @brief Convert a set of compressed 2D image levels to a raw data + * @m_since_latest + * + * Available only if @ref ImageConverterFeature::ConvertCompressedLevels2DToData + * is supported. Note that certain converters may impose size and order + * restrictions on the images, see documentation of a particular plugin + * for more information. Returns data on success, @cpp nullptr @ce + * otherwise. + * @see @ref features(), @ref convertToData(Containers::ArrayView), + * @ref convert(), @ref convertToFile() + */ + Containers::Array convertToData(Containers::ArrayView imageLevels); + /** @overload */ + Containers::Array convertToData(std::initializer_list imageLevels); + + /** + * @brief Convert a set of compressed 3D image levels to a raw data + * @m_since_latest + * + * Available only if @ref ImageConverterFeature::ConvertCompressedLevels3DToData + * is supported. Note that certain converters may impose size and order + * restrictions on the images, see documentation of a particular plugin + * for more information. Returns data on success, @cpp nullptr @ce + * otherwise. + * @see @ref features(), @ref convertToData(Containers::ArrayView), + * @ref convert(), @ref convertToFile() + */ + Containers::Array convertToData(Containers::ArrayView images); + /** @overload */ + Containers::Array convertToData(std::initializer_list images); + /** * @brief Convert a 1D image to a file * @m_since_latest @@ -914,6 +1167,10 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract * @ref convertToFile(const ImageView1D&, Containers::StringView) or * @ref convertToFile(const CompressedImageView1D&, Containers::StringView). * See documentation of these two functions for details. + * + * This overload is not provided for multi-level conversion as the + * view list creation can be done more optimally on the application + * side. * @see @ref ImageData::isCompressed() */ bool convertToFile(const ImageData1D& image, Containers::StringView filename); @@ -926,6 +1183,10 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract * @ref convertToFile(const ImageView2D&, Containers::StringView) or * @ref convertToFile(const CompressedImageView2D&, Containers::StringView). * See documentation of these two functions for details. + * + * This overload is not provided for multi-level conversion as the + * view list creation can be done more optimally on the application + * side. * @see @ref ImageData::isCompressed() */ bool convertToFile(const ImageData2D& image, Containers::StringView filename); @@ -948,16 +1209,120 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract * @ref convertToFile(const ImageView3D&, Containers::StringView) or * @ref convertToFile(const CompressedImageView3D&, Containers::StringView). * See documentation of these two functions for details. + * + * This overload is not provided for multi-level conversion as the + * view list creation can be done more optimally on the application + * side. * @see @ref ImageData::isCompressed() */ bool convertToFile(const ImageData3D& image, Containers::StringView filename); + /** + * @brief Convert a set of 1D image levels to a file + * @m_since_latest + * + * Available only if @ref ImageConverterFeature::ConvertLevels1DToFile + * is supported. Note that certain converters may impose size and order + * restrictions on the images, see documentation of a particular plugin + * for more information. Returns @cpp true @ce on success, + * @cpp false @ce otherwise. + * @see @ref features(), @ref convertToFile(Containers::ArrayView, Containers::StringView), + * @ref convert(), @ref convertToData() + */ + bool convertToFile(Containers::ArrayView imageLevels, Containers::StringView filename); + /** @overload */ + bool convertToFile(std::initializer_list imageLevels, Containers::StringView filename); + + /** + * @brief Convert a set of 2D image levels to a file + * @m_since_latest + * + * Available only if @ref ImageConverterFeature::ConvertLevels2DToFile + * is supported. Note that certain converters may impose size and order + * restrictions on the images, see documentation of a particular plugin + * for more information. Returns @cpp true @ce on success, + * @cpp false @ce otherwise. + * @see @ref features(), @ref convertToFile(Containers::ArrayView, Containers::StringView), + * @ref convert(), @ref convertToData() + */ + bool convertToFile(Containers::ArrayView imageLevels, Containers::StringView filename); + /** @overload */ + bool convertToFile(std::initializer_list imageLevels, Containers::StringView filename); + + /** + * @brief Convert a set of 3D image levels to a file + * @m_since_latest + * + * Available only if @ref ImageConverterFeature::ConvertLevels3DToFile + * is supported. Note that certain converters may impose size and order + * restrictions on the images, see documentation of a particular plugin + * for more information. Returns @cpp true @ce on success, + * @cpp false @ce otherwise. + * @see @ref features(), @ref convertToFile(Containers::ArrayView, Containers::StringView), + * @ref convert(), @ref convertToData() + */ + bool convertToFile(Containers::ArrayView imageLevels, Containers::StringView filename); + /** @overload */ + bool convertToFile(std::initializer_list imageLevels, Containers::StringView filename); + + /** + * @brief Convert a set of compressed 1D image levels to a file + * @m_since_latest + * + * Available only if @ref ImageConverterFeature::ConvertCompressedLevels1DToFile + * is supported. Note that certain converters may impose size and order + * restrictions on the images, see documentation of a particular plugin + * for more information. Returns @cpp true @ce on success, + * @cpp false @ce otherwise. + * @see @ref features(), @ref convertToFile(Containers::ArrayView, Containers::StringView), + * @ref convert(), @ref convertToData() + */ + bool convertToFile(Containers::ArrayView imageLevels, Containers::StringView filename); + /** @overload */ + bool convertToFile(std::initializer_list imageLevels, Containers::StringView filename); + + /** + * @brief Convert a set of compressed 2D image levels to a file + * @m_since_latest + * + * Available only if @ref ImageConverterFeature::ConvertCompressedLevels2DToFile + * is supported. Note that certain converters may impose size and order + * restrictions on the images, see documentation of a particular plugin + * for more information. Returns @cpp true @ce on success, + * @cpp false @ce otherwise. + * @see @ref features(), @ref convertToFile(Containers::ArrayView, Containers::StringView), + * @ref convert(), @ref convertToData() + */ + bool convertToFile(Containers::ArrayView imageLevels, Containers::StringView filename); + /** @overload */ + bool convertToFile(std::initializer_list imageLevels, Containers::StringView filename); + + /** + * @brief Convert a set of compressed 3D image levels to a file + * @m_since_latest + * + * Available only if @ref ImageConverterFeature::ConvertCompressedLevels3DToFile + * is supported. Note that certain converters may impose size and order + * restrictions on the images, see documentation of a particular plugin + * for more information. Returns @cpp true @ce on success, + * @cpp false @ce otherwise. + * @see @ref features(), @ref convertToFile(Containers::ArrayView, Containers::StringView), + * @ref convert(), @ref convertToData() + */ + bool convertToFile(Containers::ArrayView imageLevels, Containers::StringView filename); + /** @overload */ + bool convertToFile(std::initializer_list imageLevels, Containers::StringView filename); + protected: /** * @brief Implementation for @ref convertToFile(const ImageView1D&, Containers::StringView) * @m_since_latest * - * If @ref ImageConverterFeature::Convert1DToData is supported, default + * If @ref ImageConverterFeature::ConvertLevels1DToFile is supported, + * default implementation calls + * @ref doConvertToFile(Containers::ArrayView, Containers::StringView) + * with just the single @p image. Otherwise, if + * @ref ImageConverterFeature::Convert1DToData is supported, default * implementation calls @ref doConvertToData(const ImageView1D&) and * saves the result to given file. It is allowed to call this function * from your @ref doConvertToFile() implementation, for example when @@ -969,7 +1334,11 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract * @brief Implementation for @ref convertToFile(const ImageView2D&, Containers::StringView) * @m_since_latest * - * If @ref ImageConverterFeature::Convert2DToData is supported, default + * If @ref ImageConverterFeature::ConvertLevels2DToFile is supported, + * default implementation calls + * @ref doConvertToFile(Containers::ArrayView, Containers::StringView) + * with just the single @p image. Otherwise, if + * @ref ImageConverterFeature::Convert2DToData is supported, default * implementation calls @ref doConvertToData(const ImageView2D&) and * saves the result to given file. It is allowed to call this function * from your @ref doConvertToFile() implementation, for example when @@ -981,7 +1350,11 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract * @brief Implementation for @ref convertToFile(const ImageView3D&, Containers::StringView) * @m_since_latest * - * If @ref ImageConverterFeature::Convert3DToData is supported, default + * If @ref ImageConverterFeature::ConvertLevels3DToFile is supported, + * default implementation calls + * @ref doConvertToFile(Containers::ArrayView, Containers::StringView) + * with just the single @p image. Otherwise, if + * @ref ImageConverterFeature::Convert3DToData is supported, default * implementation calls @ref doConvertToData(const ImageView3D&) and * saves the result to given file. It is allowed to call this function * from your @ref doConvertToFile() implementation, for example when @@ -993,8 +1366,12 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract * @brief Implementation for @ref convertToFile(const CompressedImageView1D&, Containers::StringView) * @m_since_latest * - * If @ref ImageConverterFeature::ConvertCompressed1DToData is - * supported, default implementation calls @ref doConvertToData(const CompressedImageView1D&) + * If @ref ImageConverterFeature::ConvertCompressedLevels1DToFile is + * supported, default implementation calls + * @ref doConvertToFile(Containers::ArrayView, Containers::StringView) + * with just the single @p image. Otherwise, if + * @ref ImageConverterFeature::ConvertCompressed1DToData is supported, + * default implementation calls @ref doConvertToData(const CompressedImageView1D&) * and saves the result to given file. It is allowed to call this * function from your @ref doConvertToFile() implementation, for * example when you only need to do format detection based on file @@ -1006,8 +1383,12 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract * @brief Implementation for @ref convertToFile(const CompressedImageView2D&, Containers::StringView) * @m_since_latest * - * If @ref ImageConverterFeature::ConvertCompressed2DToData is - * supported, default implementation calls @ref doConvertToData(const CompressedImageView2D&) + * If @ref ImageConverterFeature::ConvertCompressedLevels2DToFile is + * supported, default implementation calls + * @ref doConvertToFile(Containers::ArrayView, Containers::StringView) + * with just the single @p image. Otherwise, if + * @ref ImageConverterFeature::ConvertCompressed2DToData is supported, + * default implementation calls @ref doConvertToData(const CompressedImageView2D&) * and saves the result to given file. It is allowed to call this * function from your @ref doConvertToFile() implementation, for * example when you only need to do format detection based on file @@ -1019,8 +1400,12 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract * @brief Implementation for @ref convertToFile(const CompressedImageView3D&, Containers::StringView) * @m_since_latest * - * If @ref ImageConverterFeature::ConvertCompressed3DToData is - * supported, default implementation calls @ref doConvertToData(const CompressedImageView3D&) + * If @ref ImageConverterFeature::ConvertCompressedLevels3DToFile is + * supported, default implementation calls + * @ref doConvertToFile(Containers::ArrayView, Containers::StringView) + * with just the single @p image. Otherwise, if + * @ref ImageConverterFeature::ConvertCompressed3DToData is supported, + * default implementation calls @ref doConvertToData(const CompressedImageView3D&) * and saves the result to given file. It is allowed to call this * function from your @ref doConvertToFile() implementation, for * example when you only need to do format detection based on file @@ -1028,6 +1413,85 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract */ virtual bool doConvertToFile(const CompressedImageView3D& image, Containers::StringView filename); + /** + * @brief Implementation for @ref convertToFile(Containers::ArrayView, Containers::StringView) + * @m_since_latest + * + * If @ref ImageConverterFeature::ConvertLevels1DToData is supported, + * default implementation calls + * @ref doConvertToData(Containers::ArrayView) and + * saves the result to given file. It is allowed to call this function + * from your @ref doConvertToFile() implementation, for example when + * you only need to do format detection based on file extension. + */ + virtual bool doConvertToFile(Containers::ArrayView imageLevels, Containers::StringView filename); + + /** + * @brief Implementation for @ref convertToFile(Containers::ArrayView, Containers::StringView) + * @m_since_latest + * + * If @ref ImageConverterFeature::ConvertLevels1DToData is supported, + * default implementation calls + * @ref doConvertToData(Containers::ArrayView) and + * saves the result to given file. It is allowed to call this function + * from your @ref doConvertToFile() implementation, for example when + * you only need to do format detection based on file extension. + */ + virtual bool doConvertToFile(Containers::ArrayView imageLevels, Containers::StringView filename); + + /** + * @brief Implementation for @ref convertToFile(Containers::ArrayView, Containers::StringView) + * @m_since_latest + * + * If @ref ImageConverterFeature::ConvertLevels1DToData is supported, + * default implementation calls + * @ref doConvertToData(Containers::ArrayView) and + * saves the result to given file. It is allowed to call this function + * from your @ref doConvertToFile() implementation, for example when + * you only need to do format detection based on file extension. + */ + virtual bool doConvertToFile(Containers::ArrayView imageLevels, Containers::StringView filename); + + /** + * @brief Implementation for @ref convertToFile(Containers::ArrayView, Containers::StringView) + * @m_since_latest + * + * If @ref ImageConverterFeature::ConvertCompressedLevels1DToData is + * supported, default implementation calls + * @ref doConvertToData(Containers::ArrayView) + * and saves the result to given file. It is allowed to call this + * function from your @ref doConvertToFile() implementation, for + * example when you only need to do format detection based on file + * extension. + */ + virtual bool doConvertToFile(Containers::ArrayView image, Containers::StringView filename); + + /** + * @brief Implementation for @ref convertToFile(Containers::ArrayView, Containers::StringView) + * @m_since_latest + * + * If @ref ImageConverterFeature::ConvertCompressedLevels2DToData is + * supported, default implementation calls @ref doConvertToData(Containers::ArrayView) + * and saves the result to given file. It is allowed to call this + * function from your @ref doConvertToFile() implementation, for + * example when you only need to do format detection based on file + * extension. + */ + virtual bool doConvertToFile(Containers::ArrayView image, Containers::StringView filename); + + /** + * @brief Implementation for @ref convertToFile(Containers::ArrayView, Containers::StringView) + * @m_since_latest + * + * If @ref ImageConverterFeature::ConvertCompressedLevels3DToData is + * supported, default implementation calls @ref doConvertToData(Containers::ArrayView) + * and saves the result to given file. It is allowed to call this + * function from your @ref doConvertToFile() implementation, for + * example when you only need to do format detection based on file + * extension. + */ + virtual bool doConvertToFile(Containers::ArrayView image, Containers::StringView filename); + private: /** @brief Implementation for @ref features() */ virtual ImageConverterFeatures doFeatures() const = 0; @@ -1087,39 +1551,102 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract /** * @brief Implementation for @ref convertToData(const ImageView1D&) * @m_since_latest + * + * If @ref ImageConverterFeature::ConvertLevels1DToData is supported, + * default implementation calls @ref doConvertToData(Containers::ArrayView) + * with just the single @p image and propagates the result back. */ virtual Containers::Array doConvertToData(const ImageView1D& image); /** * @brief Implementation for @ref convertToData(const ImageView2D&) * @m_since_latest + * + * If @ref ImageConverterFeature::ConvertLevels2DToData is supported, + * default implementation calls @ref doConvertToData(Containers::ArrayView) + * with just the single @p image and propagates the result back. */ virtual Containers::Array doConvertToData(const ImageView2D& image); /** * @brief Implementation for @ref convertToData(const ImageView3D&) * @m_since_latest + * + * If @ref ImageConverterFeature::ConvertLevels3DToData is supported, + * default implementation calls @ref doConvertToData(Containers::ArrayView) + * with just the single @p image and propagates the result back. */ virtual Containers::Array doConvertToData(const ImageView3D& image); /** * @brief Implementation for @ref convertToData(const CompressedImageView1D&) * @m_since_latest + * + * If @ref ImageConverterFeature::ConvertCompressedLevels1DToData is + * supported, default implementation calls + * @ref doConvertToData(Containers::ArrayView) + * with just the single @p image and propagates the result back. */ virtual Containers::Array doConvertToData(const CompressedImageView1D& image); /** * @brief Implementation for @ref convertToData(const CompressedImageView2D&) * @m_since_latest + * + * If @ref ImageConverterFeature::ConvertCompressedLevels2DToData is + * supported, default implementation calls + * @ref doConvertToData(Containers::ArrayView) + * with just the single @p image and propagates the result back. */ virtual Containers::Array doConvertToData(const CompressedImageView2D& image); /** * @brief Implementation for @ref convertToData(const CompressedImageView3D&) * @m_since_latest + * + * If @ref ImageConverterFeature::ConvertCompressedLevels3DToData is + * supported, default implementation calls + * @ref doConvertToData(Containers::ArrayView) + * with just the single @p image and propagates the result back. */ virtual Containers::Array doConvertToData(const CompressedImageView3D& image); + /** + * @brief Implementation for @ref convertToData(Containers::ArrayView) + * @m_since_latest + */ + virtual Containers::Array doConvertToData(Containers::ArrayView imageLevels); + + /** + * @brief Implementation for @ref convertToData(Containers::ArrayView) + * @m_since_latest + */ + virtual Containers::Array doConvertToData(Containers::ArrayView imageLevels); + + /** + * @brief Implementation for @ref convertToData(Containers::ArrayView) + * @m_since_latest + */ + virtual Containers::Array doConvertToData(Containers::ArrayView imageLevels); + + /** + * @brief Implementation for @ref convertToData(Containers::ArrayView) + * @m_since_latest + */ + virtual Containers::Array doConvertToData(Containers::ArrayView imageLevels); + + /** + * @brief Implementation for @ref convertToData(Containers::ArrayView) + * @m_since_latest + */ + virtual Containers::Array doConvertToData(Containers::ArrayView imageLevels); + + /** + * @brief Implementation for @ref convertToData(Containers::ArrayView) + * @m_since_latest + */ + virtual Containers::Array doConvertToData(Containers::ArrayView imageLevels); + ImageConverterFlags _flags; }; diff --git a/src/Magnum/Trade/Test/AbstractImageConverterTest.cpp b/src/Magnum/Trade/Test/AbstractImageConverterTest.cpp index 55a2ea11c7..3fe379d290 100644 --- a/src/Magnum/Trade/Test/AbstractImageConverterTest.cpp +++ b/src/Magnum/Trade/Test/AbstractImageConverterTest.cpp @@ -103,6 +103,34 @@ struct AbstractImageConverterTest: TestSuite::Tester { void convertImageData2DToData(); void convertImageData3DToData(); + void convertLevels1DToData(); + void convertLevels2DToData(); + void convertLevels3DToData(); + void convertLevels1DToDataNotImplemented(); + void convertLevels2DToDataNotImplemented(); + void convertLevels3DToDataNotImplemented(); + void convertLevels1DToDataCustomDeleter(); + void convertLevels2DToDataCustomDeleter(); + void convertLevels3DToDataCustomDeleter(); + + void convertCompressedLevels1DToData(); + void convertCompressedLevels2DToData(); + void convertCompressedLevels3DToData(); + void convertCompressedLevels1DToDataNotImplemented(); + void convertCompressedLevels2DToDataNotImplemented(); + void convertCompressedLevels3DToDataNotImplemented(); + void convertCompressedLevels1DToDataCustomDeleter(); + void convertCompressedLevels2DToDataCustomDeleter(); + void convertCompressedLevels3DToDataCustomDeleter(); + + void convert1DToDataThroughLevels(); + void convert2DToDataThroughLevels(); + void convert3DToDataThroughLevels(); + + void convertCompressed1DToDataThroughLevels(); + void convertCompressed2DToDataThroughLevels(); + void convertCompressed3DToDataThroughLevels(); + void convert1DToFile(); void convert2DToFile(); void convert3DToFile(); @@ -139,6 +167,46 @@ struct AbstractImageConverterTest: TestSuite::Tester { void convertImageData2DToFile(); void convertImageData3DToFile(); + void convertLevels1DToFile(); + void convertLevels2DToFile(); + void convertLevels3DToFile(); + void convertLevels1DToFileThroughData(); + void convertLevels2DToFileThroughData(); + void convertLevels3DToFileThroughData(); + void convertLevels1DToFileThroughDataFailed(); + void convertLevels2DToFileThroughDataFailed(); + void convertLevels3DToFileThroughDataFailed(); + void convertLevels1DToFileThroughDataNotWritable(); + void convertLevels2DToFileThroughDataNotWritable(); + void convertLevels3DToFileThroughDataNotWritable(); + void convertLevels1DToFileNotImplemented(); + void convertLevels2DToFileNotImplemented(); + void convertLevels3DToFileNotImplemented(); + + void convertCompressedLevels1DToFile(); + void convertCompressedLevels2DToFile(); + void convertCompressedLevels3DToFile(); + void convertCompressedLevels1DToFileThroughData(); + void convertCompressedLevels2DToFileThroughData(); + void convertCompressedLevels3DToFileThroughData(); + void convertCompressedLevels1DToFileThroughDataFailed(); + void convertCompressedLevels2DToFileThroughDataFailed(); + void convertCompressedLevels3DToFileThroughDataFailed(); + void convertCompressedLevels1DToFileThroughDataNotWritable(); + void convertCompressedLevels2DToFileThroughDataNotWritable(); + void convertCompressedLevels3DToFileThroughDataNotWritable(); + void convertCompressedLevels1DToFileNotImplemented(); + void convertCompressedLevels2DToFileNotImplemented(); + void convertCompressedLevels3DToFileNotImplemented(); + + void convert1DToFileThroughLevels(); + void convert2DToFileThroughLevels(); + void convert3DToFileThroughLevels(); + + void convertCompressed1DToFileThroughLevels(); + void convertCompressed2DToFileThroughLevels(); + void convertCompressed3DToFileThroughLevels(); + void debugFeature(); void debugFeatures(); void debugFeaturesSupersets(); @@ -203,6 +271,34 @@ AbstractImageConverterTest::AbstractImageConverterTest() { &AbstractImageConverterTest::convertImageData2DToData, &AbstractImageConverterTest::convertImageData3DToData, + &AbstractImageConverterTest::convertLevels1DToData, + &AbstractImageConverterTest::convertLevels2DToData, + &AbstractImageConverterTest::convertLevels3DToData, + &AbstractImageConverterTest::convertLevels1DToDataNotImplemented, + &AbstractImageConverterTest::convertLevels2DToDataNotImplemented, + &AbstractImageConverterTest::convertLevels3DToDataNotImplemented, + &AbstractImageConverterTest::convertLevels1DToDataCustomDeleter, + &AbstractImageConverterTest::convertLevels2DToDataCustomDeleter, + &AbstractImageConverterTest::convertLevels3DToDataCustomDeleter, + + &AbstractImageConverterTest::convertCompressedLevels1DToData, + &AbstractImageConverterTest::convertCompressedLevels2DToData, + &AbstractImageConverterTest::convertCompressedLevels3DToData, + &AbstractImageConverterTest::convertCompressedLevels1DToDataNotImplemented, + &AbstractImageConverterTest::convertCompressedLevels2DToDataNotImplemented, + &AbstractImageConverterTest::convertCompressedLevels3DToDataNotImplemented, + &AbstractImageConverterTest::convertCompressedLevels1DToDataCustomDeleter, + &AbstractImageConverterTest::convertCompressedLevels2DToDataCustomDeleter, + &AbstractImageConverterTest::convertCompressedLevels3DToDataCustomDeleter, + + &AbstractImageConverterTest::convert1DToDataThroughLevels, + &AbstractImageConverterTest::convert2DToDataThroughLevels, + &AbstractImageConverterTest::convert3DToDataThroughLevels, + + &AbstractImageConverterTest::convertCompressed1DToDataThroughLevels, + &AbstractImageConverterTest::convertCompressed2DToDataThroughLevels, + &AbstractImageConverterTest::convertCompressed3DToDataThroughLevels, + &AbstractImageConverterTest::convert1DToFile, &AbstractImageConverterTest::convert2DToFile, &AbstractImageConverterTest::convert3DToFile, @@ -239,6 +335,46 @@ AbstractImageConverterTest::AbstractImageConverterTest() { &AbstractImageConverterTest::convertImageData2DToFile, &AbstractImageConverterTest::convertImageData3DToFile, + &AbstractImageConverterTest::convertLevels1DToFile, + &AbstractImageConverterTest::convertLevels2DToFile, + &AbstractImageConverterTest::convertLevels3DToFile, + &AbstractImageConverterTest::convertLevels1DToFileThroughData, + &AbstractImageConverterTest::convertLevels2DToFileThroughData, + &AbstractImageConverterTest::convertLevels3DToFileThroughData, + &AbstractImageConverterTest::convertLevels1DToFileThroughDataFailed, + &AbstractImageConverterTest::convertLevels2DToFileThroughDataFailed, + &AbstractImageConverterTest::convertLevels3DToFileThroughDataFailed, + &AbstractImageConverterTest::convertLevels1DToFileThroughDataNotWritable, + &AbstractImageConverterTest::convertLevels2DToFileThroughDataNotWritable, + &AbstractImageConverterTest::convertLevels3DToFileThroughDataNotWritable, + &AbstractImageConverterTest::convertLevels1DToFileNotImplemented, + &AbstractImageConverterTest::convertLevels2DToFileNotImplemented, + &AbstractImageConverterTest::convertLevels3DToFileNotImplemented, + + &AbstractImageConverterTest::convertCompressedLevels1DToFile, + &AbstractImageConverterTest::convertCompressedLevels2DToFile, + &AbstractImageConverterTest::convertCompressedLevels3DToFile, + &AbstractImageConverterTest::convertCompressedLevels1DToFileThroughData, + &AbstractImageConverterTest::convertCompressedLevels2DToFileThroughData, + &AbstractImageConverterTest::convertCompressedLevels3DToFileThroughData, + &AbstractImageConverterTest::convertCompressedLevels1DToFileThroughDataFailed, + &AbstractImageConverterTest::convertCompressedLevels2DToFileThroughDataFailed, + &AbstractImageConverterTest::convertCompressedLevels3DToFileThroughDataFailed, + &AbstractImageConverterTest::convertCompressedLevels1DToFileThroughDataNotWritable, + &AbstractImageConverterTest::convertCompressedLevels2DToFileThroughDataNotWritable, + &AbstractImageConverterTest::convertCompressedLevels3DToFileThroughDataNotWritable, + &AbstractImageConverterTest::convertCompressedLevels1DToFileNotImplemented, + &AbstractImageConverterTest::convertCompressedLevels2DToFileNotImplemented, + &AbstractImageConverterTest::convertCompressedLevels3DToFileNotImplemented, + + &AbstractImageConverterTest::convert1DToFileThroughLevels, + &AbstractImageConverterTest::convert2DToFileThroughLevels, + &AbstractImageConverterTest::convert3DToFileThroughLevels, + + &AbstractImageConverterTest::convertCompressed1DToFileThroughLevels, + &AbstractImageConverterTest::convertCompressed2DToFileThroughLevels, + &AbstractImageConverterTest::convertCompressed3DToFileThroughLevels, + &AbstractImageConverterTest::debugFeature, &AbstractImageConverterTest::debugFeatures, &AbstractImageConverterTest::debugFeaturesSupersets, @@ -326,15 +462,27 @@ void AbstractImageConverterTest::thingNotSupported() { converter.convertToData(ImageView1D{PixelFormat::RGBA8Unorm, 0, nullptr}); converter.convertToData(ImageView2D{PixelFormat::RGBA8Unorm, {}, nullptr}); converter.convertToData(ImageView3D{PixelFormat::RGBA8Unorm, {}, nullptr}); + converter.convertToData({ImageView1D{PixelFormat::RGBA8Unorm, 0, nullptr}}); + converter.convertToData({ImageView2D{PixelFormat::RGBA8Unorm, {}, nullptr}}); + converter.convertToData({ImageView3D{PixelFormat::RGBA8Unorm, {}, nullptr}}); converter.convertToData(CompressedImageView1D{CompressedPixelFormat::Bc1RGBAUnorm, 0, nullptr}); converter.convertToData(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}); converter.convertToData(CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}); + converter.convertToData({CompressedImageView1D{CompressedPixelFormat::Bc1RGBAUnorm, 0, nullptr}}); + converter.convertToData({CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}}); + converter.convertToData({CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}}); converter.convertToFile(ImageView1D{PixelFormat::RGBA8Unorm, 0, nullptr}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); converter.convertToFile(ImageView2D{PixelFormat::RGBA8Unorm, {}, nullptr}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); converter.convertToFile(ImageView3D{PixelFormat::RGBA8Unorm, {}, nullptr}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); + converter.convertToFile({ImageView1D{PixelFormat::RGBA8Unorm, 0, nullptr}}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); + converter.convertToFile({ImageView2D{PixelFormat::RGBA8Unorm, {}, nullptr}}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); + converter.convertToFile({ImageView3D{PixelFormat::RGBA8Unorm, {}, nullptr}}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); converter.convertToFile(CompressedImageView1D{CompressedPixelFormat::Bc1RGBAUnorm, 0, nullptr}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); converter.convertToFile(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); converter.convertToFile(CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); + converter.convertToFile({CompressedImageView1D{CompressedPixelFormat::Bc1RGBAUnorm, 0, nullptr}}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); + converter.convertToFile({CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); + converter.convertToFile({CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convert(): 1D image conversion not supported\n" "Trade::AbstractImageConverter::convert(): 2D image conversion not supported\n" @@ -345,15 +493,27 @@ void AbstractImageConverterTest::thingNotSupported() { "Trade::AbstractImageConverter::convertToData(): 1D image conversion not supported\n" "Trade::AbstractImageConverter::convertToData(): 2D image conversion not supported\n" "Trade::AbstractImageConverter::convertToData(): 3D image conversion not supported\n" + "Trade::AbstractImageConverter::convertToData(): multi-level 1D image conversion not supported\n" + "Trade::AbstractImageConverter::convertToData(): multi-level 2D image conversion not supported\n" + "Trade::AbstractImageConverter::convertToData(): multi-level 3D image conversion not supported\n" "Trade::AbstractImageConverter::convertToData(): compressed 1D image conversion not supported\n" "Trade::AbstractImageConverter::convertToData(): compressed 2D image conversion not supported\n" "Trade::AbstractImageConverter::convertToData(): compressed 3D image conversion not supported\n" + "Trade::AbstractImageConverter::convertToData(): multi-level compressed 1D image conversion not supported\n" + "Trade::AbstractImageConverter::convertToData(): multi-level compressed 2D image conversion not supported\n" + "Trade::AbstractImageConverter::convertToData(): multi-level compressed 3D image conversion not supported\n" "Trade::AbstractImageConverter::convertToFile(): 1D image conversion not supported\n" "Trade::AbstractImageConverter::convertToFile(): 2D image conversion not supported\n" "Trade::AbstractImageConverter::convertToFile(): 3D image conversion not supported\n" + "Trade::AbstractImageConverter::convertToFile(): multi-level 1D image conversion not supported\n" + "Trade::AbstractImageConverter::convertToFile(): multi-level 2D image conversion not supported\n" + "Trade::AbstractImageConverter::convertToFile(): multi-level 3D image conversion not supported\n" "Trade::AbstractImageConverter::convertToFile(): compressed 1D image conversion not supported\n" "Trade::AbstractImageConverter::convertToFile(): compressed 2D image conversion not supported\n" - "Trade::AbstractImageConverter::convertToFile(): compressed 3D image conversion not supported\n"); + "Trade::AbstractImageConverter::convertToFile(): compressed 3D image conversion not supported\n" + "Trade::AbstractImageConverter::convertToFile(): multi-level compressed 1D image conversion not supported\n" + "Trade::AbstractImageConverter::convertToFile(): multi-level compressed 2D image conversion not supported\n" + "Trade::AbstractImageConverter::convertToFile(): multi-level compressed 3D image conversion not supported\n"); } void AbstractImageConverterTest::convert1D() { @@ -1090,6 +1250,372 @@ void AbstractImageConverterTest::convertImageData3DToData() { TestSuite::Compare::Container); } +void AbstractImageConverterTest::convertLevels1DToData() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels1DToData; } + Containers::Array doConvertToData(Containers::ArrayView imageLevels) override { + return Containers::Array{nullptr, std::size_t(imageLevels[0].size().product()*imageLevels.size())}; + } + } converter; + + Containers::Array actual = converter.convertToData({ + ImageView1D{PixelFormat::RGBA8Unorm, 4, Containers::ArrayView{nullptr, 96}}, + ImageView1D{PixelFormat::RGBA8Unorm, 0, nullptr}, + ImageView1D{PixelFormat::RGBA8Unorm, 0, nullptr}, + }); + CORRADE_COMPARE(actual.size(), 4*3); +} + +void AbstractImageConverterTest::convertLevels2DToData() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels2DToData; } + Containers::Array doConvertToData(Containers::ArrayView imageLevels) override { + return Containers::Array{nullptr, std::size_t(imageLevels[0].size().product()*imageLevels.size())}; + } + } converter; + + Containers::Array actual = converter.convertToData({ + ImageView2D{PixelFormat::RGBA8Unorm, {4, 6}, Containers::ArrayView{nullptr, 96}}, + ImageView2D{PixelFormat::RGBA8Unorm, {}, nullptr}, + ImageView2D{PixelFormat::RGBA8Unorm, {}, nullptr} + }); + CORRADE_COMPARE(actual.size(), 24*3); +} + +void AbstractImageConverterTest::convertLevels3DToData() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels3DToData; } + Containers::Array doConvertToData(Containers::ArrayView imageLevels) override { + return Containers::Array{nullptr, std::size_t(imageLevels[0].size().product()*imageLevels.size())}; + } + } converter; + + Containers::Array actual = converter.convertToData({ + ImageView3D{PixelFormat::RGBA8Unorm, {4, 6, 2}, Containers::ArrayView{nullptr, 96}}, + ImageView3D{PixelFormat::RGBA8Unorm, {}, nullptr}, + ImageView3D{PixelFormat::RGBA8Unorm, {}, nullptr} + }); + CORRADE_COMPARE(actual.size(), 48*3); +} + +void AbstractImageConverterTest::convertLevels1DToDataNotImplemented() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels1DToData; } + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToData({ImageView1D{PixelFormat::RGBA8Unorm, 0, nullptr}}); + CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToData(): multi-level 1D image conversion advertised but not implemented\n"); +} + +void AbstractImageConverterTest::convertLevels2DToDataNotImplemented() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels2DToData; } + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToData({ImageView2D{PixelFormat::RGBA8Unorm, {}, nullptr}}); + CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToData(): multi-level 2D image conversion advertised but not implemented\n"); +} + +void AbstractImageConverterTest::convertLevels3DToDataNotImplemented() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels3DToData; } + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToData({ImageView3D{PixelFormat::RGBA8Unorm, {}, nullptr}}); + CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToData(): multi-level 3D image conversion advertised but not implemented\n"); +} + +void AbstractImageConverterTest::convertLevels1DToDataCustomDeleter() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels1DToData; } + Containers::Array doConvertToData(Containers::ArrayView) override { + return Containers::Array{nullptr, 0, [](char*, std::size_t) {}}; + } + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToData({ImageView1D{PixelFormat::RGBA8Unorm, {}, nullptr}}); + CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToData(): implementation is not allowed to use a custom Array deleter\n"); +} + +void AbstractImageConverterTest::convertLevels2DToDataCustomDeleter() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels2DToData; } + Containers::Array doConvertToData(Containers::ArrayView) override { + return Containers::Array{nullptr, 0, [](char*, std::size_t) {}}; + } + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToData({ImageView2D{PixelFormat::RGBA8Unorm, {}, nullptr}}); + CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToData(): implementation is not allowed to use a custom Array deleter\n"); +} + +void AbstractImageConverterTest::convertLevels3DToDataCustomDeleter() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels3DToData; } + Containers::Array doConvertToData(Containers::ArrayView) override { + return Containers::Array{nullptr, 0, [](char*, std::size_t) {}}; + } + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToData({ImageView3D{PixelFormat::RGBA8Unorm, {}, nullptr}}); + CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToData(): implementation is not allowed to use a custom Array deleter\n"); +} + +void AbstractImageConverterTest::convertCompressedLevels1DToData() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels1DToData; } + Containers::Array doConvertToData(Containers::ArrayView imageLevels) override { + return Containers::Array{nullptr, std::size_t(imageLevels[0].size().product()*imageLevels.size())}; + } + } converter; + + Containers::Array actual = converter.convertToData({ + CompressedImageView1D{CompressedPixelFormat::Bc1RGBAUnorm, 16, Containers::ArrayView{nullptr, 64}}, + CompressedImageView1D{CompressedPixelFormat::Bc1RGBAUnorm, 0, nullptr}, + CompressedImageView1D{CompressedPixelFormat::Bc1RGBAUnorm, 0, nullptr} + }); + CORRADE_COMPARE(actual.size(), 16*3); +} + +void AbstractImageConverterTest::convertCompressedLevels2DToData() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels2DToData; } + Containers::Array doConvertToData(Containers::ArrayView imageLevels) override { + return Containers::Array{nullptr, std::size_t(imageLevels[0].size().product()*imageLevels.size())}; + } + } converter; + + Containers::Array actual = converter.convertToData({ + CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {16, 8}, Containers::ArrayView{nullptr, 64}}, + CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}, + CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr} + }); + CORRADE_COMPARE(actual.size(), 128*3); +} + +void AbstractImageConverterTest::convertCompressedLevels3DToData() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels3DToData; } + Containers::Array doConvertToData(Containers::ArrayView imageLevels) override { + return Containers::Array{nullptr, std::size_t(imageLevels[0].size().product()*imageLevels.size())}; + } + } converter; + + Containers::Array actual = converter.convertToData({ + CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {16, 8, 2}, Containers::ArrayView{nullptr, 64}}, + CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}, + CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr} + }); + CORRADE_COMPARE(actual.size(), 256*3); +} + +void AbstractImageConverterTest::convertCompressedLevels1DToDataNotImplemented() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels1DToData; } + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToData({CompressedImageView1D{CompressedPixelFormat::Bc1RGBAUnorm, 0, nullptr}}); + CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToData(): multi-level compressed 1D image conversion advertised but not implemented\n"); +} + +void AbstractImageConverterTest::convertCompressedLevels2DToDataNotImplemented() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels2DToData; } + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToData({CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}}); + CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToData(): multi-level compressed 2D image conversion advertised but not implemented\n"); +} + +void AbstractImageConverterTest::convertCompressedLevels3DToDataNotImplemented() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels3DToData; } + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToData({CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}}); + CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToData(): multi-level compressed 3D image conversion advertised but not implemented\n"); +} + +void AbstractImageConverterTest::convertCompressedLevels1DToDataCustomDeleter() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels1DToData; } + Containers::Array doConvertToData(Containers::ArrayView) override { + return Containers::Array{nullptr, 0, [](char*, std::size_t) {}}; + } + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToData({CompressedImageView1D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}}); + CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToData(): implementation is not allowed to use a custom Array deleter\n"); +} + +void AbstractImageConverterTest::convertCompressedLevels2DToDataCustomDeleter() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels2DToData; } + Containers::Array doConvertToData(Containers::ArrayView) override { + return Containers::Array{nullptr, 0, [](char*, std::size_t) {}}; + } + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToData({CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}}); + CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToData(): implementation is not allowed to use a custom Array deleter\n"); +} + +void AbstractImageConverterTest::convertCompressedLevels3DToDataCustomDeleter() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels3DToData; } + Containers::Array doConvertToData(Containers::ArrayView) override { + return Containers::Array{nullptr, 0, [](char*, std::size_t) {}}; + } + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToData({CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}}); + CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToData(): implementation is not allowed to use a custom Array deleter\n"); +} + +void AbstractImageConverterTest::convert1DToDataThroughLevels() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels1DToData; } + Containers::Array doConvertToData(Containers::ArrayView imageLevels) override { + return Containers::Array{nullptr, std::size_t(imageLevels[0].size().product()*imageLevels.size())}; + } + } converter; + + Containers::Array actual = converter.convertToData(ImageView1D{PixelFormat::RGBA8Unorm, 4, Containers::ArrayView{nullptr, 96}}); + CORRADE_COMPARE(actual.size(), 4); +} + +void AbstractImageConverterTest::convert2DToDataThroughLevels() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels2DToData; } + Containers::Array doConvertToData(Containers::ArrayView imageLevels) override { + return Containers::Array{nullptr, std::size_t(imageLevels[0].size().product()*imageLevels.size())}; + } + } converter; + + Containers::Array actual = converter.convertToData(ImageView2D{PixelFormat::RGBA8Unorm, {4, 6}, Containers::ArrayView{nullptr, 96}}); + CORRADE_COMPARE(actual.size(), 24); +} + +void AbstractImageConverterTest::convert3DToDataThroughLevels() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels3DToData; } + Containers::Array doConvertToData(Containers::ArrayView imageLevels) override { + return Containers::Array{nullptr, std::size_t(imageLevels[0].size().product()*imageLevels.size())}; + } + } converter; + + Containers::Array actual = converter.convertToData(ImageView3D{PixelFormat::RGBA8Unorm, {4, 6, 2}, Containers::ArrayView{nullptr, 96}}); + CORRADE_COMPARE(actual.size(), 48); +} + +void AbstractImageConverterTest::convertCompressed1DToDataThroughLevels() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels1DToData; } + Containers::Array doConvertToData(Containers::ArrayView imageLevels) override { + return Containers::Array{nullptr, std::size_t(imageLevels[0].size().product()*imageLevels.size())}; + } + } converter; + + Containers::Array actual = converter.convertToData(CompressedImageView1D{CompressedPixelFormat::Bc1RGBAUnorm, 16, Containers::ArrayView{nullptr, 64}}); + CORRADE_COMPARE(actual.size(), 16); +} + +void AbstractImageConverterTest::convertCompressed2DToDataThroughLevels() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels2DToData; } + Containers::Array doConvertToData(Containers::ArrayView imageLevels) override { + return Containers::Array{nullptr, std::size_t(imageLevels[0].size().product()*imageLevels.size())}; + } + } converter; + + Containers::Array actual = converter.convertToData(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {16, 8}, Containers::ArrayView{nullptr, 64}}); + CORRADE_COMPARE(actual.size(), 128); +} + +void AbstractImageConverterTest::convertCompressed3DToDataThroughLevels() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels3DToData; } + Containers::Array doConvertToData(Containers::ArrayView imageLevels) override { + return Containers::Array{nullptr, std::size_t(imageLevels[0].size().product()*imageLevels.size())}; + } + } converter; + + Containers::Array actual = converter.convertToData(CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {16, 8, 2}, Containers::ArrayView{nullptr, 64}}); + CORRADE_COMPARE(actual.size(), 256); +} + void AbstractImageConverterTest::convert1DToFile() { struct: AbstractImageConverter { ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::Convert1DToFile; } @@ -1714,18 +2240,755 @@ void AbstractImageConverterTest::convertImageData3DToFile() { "C", TestSuite::Compare::FileToString); } -void AbstractImageConverterTest::debugFeature() { - std::ostringstream out; +void AbstractImageConverterTest::convertLevels1DToFile() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels1DToFile; } + bool doConvertToFile(Containers::ArrayView imageLevels, Containers::StringView filename) override { + return Utility::Directory::write(filename, Containers::arrayView( + {char(imageLevels[0].size()[0]), char(imageLevels.size())})); + } + } converter; - Debug{&out} << ImageConverterFeature::ConvertCompressed2D << ImageConverterFeature(0xdeadbeef); - CORRADE_COMPARE(out.str(), "Trade::ImageConverterFeature::ConvertCompressed2D Trade::ImageConverterFeature(0xdeadbeef)\n"); -} + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); -void AbstractImageConverterTest::debugFeatures() { - std::ostringstream out; + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); - Debug{&out} << (ImageConverterFeature::Convert2DToData|ImageConverterFeature::ConvertCompressed2DToFile) << ImageConverterFeatures{}; - CORRADE_COMPARE(out.str(), "Trade::ImageConverterFeature::Convert2DToData|Trade::ImageConverterFeature::ConvertCompressed2DToFile Trade::ImageConverterFeatures{}\n"); + CORRADE_VERIFY(converter.convertToFile({ + ImageView1D{PixelFormat::RGBA8Unorm, 0xf0, {nullptr, 0xf0*4}}, + ImageView1D{PixelFormat::RGBA8Unorm, 0, nullptr} + }, filename)); + CORRADE_COMPARE_AS(filename, + "\xf0\x02", TestSuite::Compare::FileToString); +} + +void AbstractImageConverterTest::convertLevels2DToFile() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels2DToFile; } + bool doConvertToFile(Containers::ArrayView imageLevels, Containers::StringView filename) override { + return Utility::Directory::write(filename, Containers::arrayView( + {char(imageLevels[0].size().x()), char(imageLevels[0].size().y()), char(imageLevels.size())})); + } + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + CORRADE_VERIFY(converter.convertToFile({ + ImageView2D{PixelFormat::RGBA8Unorm, {0xf0, 0x0d}, {nullptr, 0xf0*0x0d*4}}, + ImageView2D{PixelFormat::RGBA8Unorm, {}, nullptr} + }, filename)); + CORRADE_COMPARE_AS(filename, + "\xf0\x0d\x02", TestSuite::Compare::FileToString); +} + +void AbstractImageConverterTest::convertLevels3DToFile() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels3DToFile; } + bool doConvertToFile(Containers::ArrayView imageLevels, Containers::StringView filename) override { + return Utility::Directory::write(filename, Containers::arrayView( + {char(imageLevels[0].size().x()), char(imageLevels[0].size().y()), char(imageLevels[0].size().z()), char(imageLevels.size())})); + } + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + CORRADE_VERIFY(converter.convertToFile({ + ImageView3D{PixelFormat::RGBA8Unorm, {0xf0, 0x0d, 0x1e}, {nullptr, 0xf0*0x0d*0x1e*4}}, + ImageView3D{PixelFormat::RGBA8Unorm, {}, nullptr} + }, filename)); + CORRADE_COMPARE_AS(filename, + "\xf0\x0d\x1e\x02", TestSuite::Compare::FileToString); +} + +void AbstractImageConverterTest::convertLevels1DToFileThroughData() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels1DToData; } + + Containers::Array doConvertToData(Containers::ArrayView imageLevels) override { + return Containers::array({char(imageLevels[0].size()[0]), char(imageLevels.size())}); + }; + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + /* doConvertToFile() should call doConvertToData() */ + CORRADE_VERIFY(converter.convertToFile({ + ImageView1D{PixelFormat::RGBA8Unorm, 0xfe, {nullptr, 0xfe*4}}, + ImageView1D{PixelFormat::RGBA8Unorm, 0, nullptr} + }, filename)); + CORRADE_COMPARE_AS(filename, + "\xfe\x02", TestSuite::Compare::FileToString); +} + +void AbstractImageConverterTest::convertLevels2DToFileThroughData() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels2DToData; } + + Containers::Array doConvertToData(Containers::ArrayView imageLevels) override { + return Containers::array({char(imageLevels[0].size().x()), char(imageLevels[0].size().y()), char(imageLevels.size())}); + }; + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + /* doConvertToFile() should call doConvertToData() */ + CORRADE_VERIFY(converter.convertToFile({ + ImageView2D(PixelFormat::RGBA8Unorm, {0xfe, 0xed}, {nullptr, 0xfe*0xed*4}), + ImageView2D{PixelFormat::RGBA8Unorm, {}, nullptr} + }, filename)); + CORRADE_COMPARE_AS(filename, + "\xfe\xed\x02", TestSuite::Compare::FileToString); +} + +void AbstractImageConverterTest::convertLevels3DToFileThroughData() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels3DToData; } + + Containers::Array doConvertToData(Containers::ArrayView imageLevels) override { + return Containers::array({char(imageLevels[0].size().x()), char(imageLevels[0].size().y()), char(imageLevels[0].size().z()), char(imageLevels.size())}); + }; + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + /* doConvertToFile() should call doConvertToData() */ + CORRADE_VERIFY(converter.convertToFile({ + ImageView3D{PixelFormat::RGBA8Unorm, {0xfe, 0xed, 0xe9}, {nullptr, 0xfe*0xed*0xe9*4}}, + ImageView3D{PixelFormat::RGBA8Unorm, {}, nullptr} + }, filename)); + CORRADE_COMPARE_AS(filename, + "\xfe\xed\xe9\x02", TestSuite::Compare::FileToString); +} + +void AbstractImageConverterTest::convertLevels1DToFileThroughDataFailed() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels1DToData; } + + Containers::Array doConvertToData(Containers::ArrayView) override { + return {}; + }; + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + /* Function should fail, no file should get written and no error output + should be printed (the base implementation assumes the plugin does it) */ + std::ostringstream out; + Error redirectError{&out}; + CORRADE_VERIFY(!converter.convertToFile({ImageView1D{PixelFormat::RGBA8Unorm, 0, nullptr}}, filename)); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + CORRADE_COMPARE(out.str(), ""); +} + +void AbstractImageConverterTest::convertLevels2DToFileThroughDataFailed() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels2DToData; } + + Containers::Array doConvertToData(Containers::ArrayView) override { + return {}; + }; + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + /* Function should fail, no file should get written and no error output + should be printed (the base implementation assumes the plugin does it) */ + std::ostringstream out; + Error redirectError{&out}; + CORRADE_VERIFY(!converter.convertToFile({ImageView2D{PixelFormat::RGBA8Unorm, {}, nullptr}}, filename)); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + CORRADE_COMPARE(out.str(), ""); +} + +void AbstractImageConverterTest::convertLevels3DToFileThroughDataFailed() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels3DToData; } + + Containers::Array doConvertToData(Containers::ArrayView) override { + return {}; + }; + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + /* Function should fail, no file should get written and no error output + should be printed (the base implementation assumes the plugin does it) */ + std::ostringstream out; + Error redirectError{&out}; + CORRADE_VERIFY(!converter.convertToFile({ImageView3D{PixelFormat::RGBA8Unorm, {}, nullptr}}, filename)); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + CORRADE_COMPARE(out.str(), ""); +} + +void AbstractImageConverterTest::convertLevels1DToFileThroughDataNotWritable() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels1DToData; } + Containers::Array doConvertToData(Containers::ArrayView) override { + return Containers::array({'\x00'}); + }; + } converter; + + std::ostringstream out; + Error redirectError{&out}; + CORRADE_VERIFY(!converter.convertToFile({ImageView1D{PixelFormat::RGBA8Unorm, 0, nullptr}}, "/some/path/that/does/not/exist")); + CORRADE_COMPARE(out.str(), + "Utility::Directory::write(): can't open /some/path/that/does/not/exist\n" + "Trade::AbstractImageConverter::convertToFile(): cannot write to file /some/path/that/does/not/exist\n"); +} + +void AbstractImageConverterTest::convertLevels2DToFileThroughDataNotWritable() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels2DToData; } + + Containers::Array doConvertToData(Containers::ArrayView) override { + return Containers::array({'\x00'}); + }; + } converter; + + std::ostringstream out; + Error redirectError{&out}; + CORRADE_VERIFY(!converter.convertToFile({ImageView2D{PixelFormat::RGBA8Unorm, {}, nullptr}}, "/some/path/that/does/not/exist")); + CORRADE_COMPARE(out.str(), + "Utility::Directory::write(): can't open /some/path/that/does/not/exist\n" + "Trade::AbstractImageConverter::convertToFile(): cannot write to file /some/path/that/does/not/exist\n"); +} + +void AbstractImageConverterTest::convertLevels3DToFileThroughDataNotWritable() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels3DToData; } + + Containers::Array doConvertToData(Containers::ArrayView) override { + return Containers::array({'\x00'}); + }; + } converter; + + std::ostringstream out; + Error redirectError{&out}; + CORRADE_VERIFY(!converter.convertToFile({ImageView3D{PixelFormat::RGBA8Unorm, {}, nullptr}}, "/some/path/that/does/not/exist")); + CORRADE_COMPARE(out.str(), + "Utility::Directory::write(): can't open /some/path/that/does/not/exist\n" + "Trade::AbstractImageConverter::convertToFile(): cannot write to file /some/path/that/does/not/exist\n"); +} + +void AbstractImageConverterTest::convertLevels1DToFileNotImplemented() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels1DToFile; } + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToFile({ImageView1D{PixelFormat::RGBA8Unorm, 0, nullptr}}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); + CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToFile(): multi-level 1D image conversion advertised but not implemented\n"); +} + +void AbstractImageConverterTest::convertLevels2DToFileNotImplemented() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels2DToFile; } + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToFile({ImageView2D{PixelFormat::RGBA8Unorm, {}, nullptr}}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); + CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToFile(): multi-level 2D image conversion advertised but not implemented\n"); +} + +void AbstractImageConverterTest::convertLevels3DToFileNotImplemented() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels3DToFile; } + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToFile({ImageView3D{PixelFormat::RGBA8Unorm, {}, nullptr}}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); + CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToFile(): multi-level 3D image conversion advertised but not implemented\n"); +} + +void AbstractImageConverterTest::convertCompressedLevels1DToFile() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels1DToFile; } + bool doConvertToFile(Containers::ArrayView imageLevels, Containers::StringView filename) override { + return Utility::Directory::write(filename, Containers::arrayView( + {char(imageLevels[0].size()[0]), char(imageLevels.size())})); + } + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + CORRADE_VERIFY(converter.convertToFile({ + CompressedImageView1D{CompressedPixelFormat::Bc1RGBAUnorm, 0xd0, {nullptr, 64}}, + CompressedImageView1D{CompressedPixelFormat::Bc1RGBAUnorm, 0, nullptr} + }, filename)); + CORRADE_COMPARE_AS(filename, + "\xd0\x02", TestSuite::Compare::FileToString); +} + +void AbstractImageConverterTest::convertCompressedLevels2DToFile() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels2DToFile; } + bool doConvertToFile(Containers::ArrayView imageLevels, Containers::StringView filename) override { + return Utility::Directory::write(filename, Containers::arrayView( + {char(imageLevels[0].size().x()), char(imageLevels[0].size().y()), char(imageLevels.size())})); + } + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + CORRADE_VERIFY(converter.convertToFile({ + CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {0xd0, 0x0d}, {nullptr, 64}}, + CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr} + }, filename)); + CORRADE_COMPARE_AS(filename, + "\xd0\x0d\x02", TestSuite::Compare::FileToString); +} + +void AbstractImageConverterTest::convertCompressedLevels3DToFile() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels3DToFile; } + bool doConvertToFile(Containers::ArrayView imageLevels, Containers::StringView filename) override { + return Utility::Directory::write(filename, Containers::arrayView( + {char(imageLevels[0].size().x()), char(imageLevels[0].size().y()), char(imageLevels[0].size().z()), char(imageLevels.size())})); + } + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + CORRADE_VERIFY(converter.convertToFile({ + CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {0xd0, 0x0d, 0x1e}, {nullptr, 64}}, + CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr} + }, filename)); + CORRADE_COMPARE_AS(filename, + "\xd0\x0d\x1e\x02", TestSuite::Compare::FileToString); +} + +void AbstractImageConverterTest::convertCompressedLevels1DToFileThroughData() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels1DToData; } + + Containers::Array doConvertToData(Containers::ArrayView imageLevels) override { + return Containers::array({char(imageLevels[0].size()[0]), char(imageLevels.size())}); + }; + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + /* doConvertToFile() should call doConvertToData() */ + CORRADE_VERIFY(converter.convertToFile({ + CompressedImageView1D{CompressedPixelFormat::Bc1RGBAUnorm, 0xb0, {nullptr, 64}}, + CompressedImageView1D{CompressedPixelFormat::Bc1RGBAUnorm, 0, nullptr} + }, filename)); + CORRADE_COMPARE_AS(filename, + "\xb0\x02", TestSuite::Compare::FileToString); +} + +void AbstractImageConverterTest::convertCompressedLevels2DToFileThroughData() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels2DToData; } + + Containers::Array doConvertToData(Containers::ArrayView imageLevels) override { + return Containers::array({char(imageLevels[0].size().x()), char(imageLevels[0].size().y()), char(imageLevels.size())}); + }; + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + /* doConvertToFile() should call doConvertToData() */ + CORRADE_VERIFY(converter.convertToFile({ + CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {0xb0, 0xd9}, {nullptr, 64}}, + CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr} + }, filename)); + CORRADE_COMPARE_AS(filename, + "\xb0\xd9\x02", TestSuite::Compare::FileToString); +} + +void AbstractImageConverterTest::convertCompressedLevels3DToFileThroughData() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels3DToData; } + + Containers::Array doConvertToData(Containers::ArrayView imageLevels) override { + return Containers::array({char(imageLevels[0].size().x()), char(imageLevels[0].size().y()), char(imageLevels[0].size().z()), char(imageLevels.size())}); + }; + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + /* doConvertToFile() should call doConvertToData() */ + CORRADE_VERIFY(converter.convertToFile({ + CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {0xb0, 0xd1, 0xe5}, {nullptr, 64}}, + CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr} + }, filename)); + CORRADE_COMPARE_AS(filename, + "\xb0\xd1\xe5\x02", TestSuite::Compare::FileToString); +} + +void AbstractImageConverterTest::convertCompressedLevels1DToFileThroughDataFailed() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels1DToData; } + + Containers::Array doConvertToData(Containers::ArrayView) override { + return {}; + }; + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + /* Function should fail, no file should get written and no error output + should be printed (the base implementation assumes the plugin does it) */ + std::ostringstream out; + Error redirectError{&out}; + CORRADE_VERIFY(!converter.convertToFile({CompressedImageView1D{CompressedPixelFormat::Bc1RGBAUnorm, 0, nullptr}}, filename)); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + CORRADE_COMPARE(out.str(), ""); +} + +void AbstractImageConverterTest::convertCompressedLevels2DToFileThroughDataFailed() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels2DToData; } + + Containers::Array doConvertToData(Containers::ArrayView) override { + return {}; + }; + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + /* Function should fail, no file should get written and no error output + should be printed (the base implementation assumes the plugin does it) */ + std::ostringstream out; + Error redirectError{&out}; + CORRADE_VERIFY(!converter.convertToFile({CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}}, filename)); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + CORRADE_COMPARE(out.str(), ""); +} + +void AbstractImageConverterTest::convertCompressedLevels3DToFileThroughDataFailed() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels3DToData; } + + Containers::Array doConvertToData(Containers::ArrayView) override { + return {}; + }; + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + /* Function should fail, no file should get written and no error output + should be printed (the base implementation assumes the plugin does it) */ + std::ostringstream out; + Error redirectError{&out}; + CORRADE_VERIFY(!converter.convertToFile({CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}}, filename)); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + CORRADE_COMPARE(out.str(), ""); +} + +void AbstractImageConverterTest::convertCompressedLevels1DToFileThroughDataNotWritable() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels1DToData; } + + Containers::Array doConvertToData(Containers::ArrayView) override { + return Containers::array({'\x00'}); + }; + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToFile({CompressedImageView1D{CompressedPixelFormat::Bc1RGBAUnorm, 0, nullptr}}, "/some/path/that/does/not/exist"); + CORRADE_COMPARE(out.str(), + "Utility::Directory::write(): can't open /some/path/that/does/not/exist\n" + "Trade::AbstractImageConverter::convertToFile(): cannot write to file /some/path/that/does/not/exist\n"); +} + +void AbstractImageConverterTest::convertCompressedLevels2DToFileThroughDataNotWritable() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels2DToData; } + + Containers::Array doConvertToData(Containers::ArrayView) override { + return Containers::array({'\x00'}); + }; + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToFile({CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}}, "/some/path/that/does/not/exist"); + CORRADE_COMPARE(out.str(), + "Utility::Directory::write(): can't open /some/path/that/does/not/exist\n" + "Trade::AbstractImageConverter::convertToFile(): cannot write to file /some/path/that/does/not/exist\n"); +} + +void AbstractImageConverterTest::convertCompressedLevels3DToFileThroughDataNotWritable() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels3DToData; } + + Containers::Array doConvertToData(Containers::ArrayView) override { + return Containers::array({'\x00'}); + }; + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToFile({CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}}, "/some/path/that/does/not/exist"); + CORRADE_COMPARE(out.str(), + "Utility::Directory::write(): can't open /some/path/that/does/not/exist\n" + "Trade::AbstractImageConverter::convertToFile(): cannot write to file /some/path/that/does/not/exist\n"); +} + +void AbstractImageConverterTest::convertCompressedLevels1DToFileNotImplemented() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels1DToFile; } + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToFile({CompressedImageView1D{CompressedPixelFormat::Bc1RGBAUnorm, 0, nullptr}}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); + CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToFile(): multi-level compressed 1D image conversion advertised but not implemented\n"); +} + +void AbstractImageConverterTest::convertCompressedLevels2DToFileNotImplemented() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels2DToFile; } + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToFile({CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); + CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToFile(): multi-level compressed 2D image conversion advertised but not implemented\n"); +} + +void AbstractImageConverterTest::convertCompressedLevels3DToFileNotImplemented() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels3DToFile; } + } converter; + + std::ostringstream out; + Error redirectError{&out}; + converter.convertToFile({CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {}, nullptr}}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); + CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToFile(): multi-level compressed 3D image conversion advertised but not implemented\n"); +} + +void AbstractImageConverterTest::convert1DToFileThroughLevels() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels1DToFile; } + bool doConvertToFile(Containers::ArrayView imageLevels, Containers::StringView filename) override { + return Utility::Directory::write(filename, Containers::arrayView( + {char(imageLevels[0].size()[0]), char(imageLevels.size())})); + } + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + CORRADE_VERIFY(converter.convertToFile(ImageView1D{PixelFormat::RGBA8Unorm, 0xf0, {nullptr, 0xf0*4}}, filename)); + CORRADE_COMPARE_AS(filename, + "\xf0\x01", TestSuite::Compare::FileToString); +} + +void AbstractImageConverterTest::convert2DToFileThroughLevels() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels2DToFile; } + bool doConvertToFile(Containers::ArrayView imageLevels, Containers::StringView filename) override { + return Utility::Directory::write(filename, Containers::arrayView( + {char(imageLevels[0].size().x()), char(imageLevels[0].size().y()), char(imageLevels.size())})); + } + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + CORRADE_VERIFY(converter.convertToFile(ImageView2D{PixelFormat::RGBA8Unorm, {0xf0, 0x0d}, {nullptr, 0xf0*0x0d*4}}, filename)); + CORRADE_COMPARE_AS(filename, + "\xf0\x0d\x01", TestSuite::Compare::FileToString); +} + +void AbstractImageConverterTest::convert3DToFileThroughLevels() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertLevels3DToFile; } + bool doConvertToFile(Containers::ArrayView imageLevels, Containers::StringView filename) override { + return Utility::Directory::write(filename, Containers::arrayView( + {char(imageLevels[0].size().x()), char(imageLevels[0].size().y()), char(imageLevels[0].size().z()), char(imageLevels.size())})); + } + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + CORRADE_VERIFY(converter.convertToFile(ImageView3D{PixelFormat::RGBA8Unorm, {0xf0, 0x0d, 0x1e}, {nullptr, 0xf0*0x0d*0x1e*4}}, filename)); + CORRADE_COMPARE_AS(filename, + "\xf0\x0d\x1e\x01", TestSuite::Compare::FileToString); +} + +void AbstractImageConverterTest::convertCompressed1DToFileThroughLevels() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels1DToFile; } + bool doConvertToFile(Containers::ArrayView imageLevels, Containers::StringView filename) override { + return Utility::Directory::write(filename, Containers::arrayView( + {char(imageLevels[0].size()[0]), char(imageLevels.size())})); + } + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + CORRADE_VERIFY(converter.convertToFile(CompressedImageView1D{CompressedPixelFormat::Bc1RGBAUnorm, 0xd0, {nullptr, 64}}, filename)); + CORRADE_COMPARE_AS(filename, + "\xd0\x01", TestSuite::Compare::FileToString); +} + +void AbstractImageConverterTest::convertCompressed2DToFileThroughLevels() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels2DToFile; } + bool doConvertToFile(Containers::ArrayView imageLevels, Containers::StringView filename) override { + return Utility::Directory::write(filename, Containers::arrayView( + {char(imageLevels[0].size().x()), char(imageLevels[0].size().y()), char(imageLevels.size())})); + } + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + CORRADE_VERIFY(converter.convertToFile(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {0xd0, 0x0d}, {nullptr, 64}}, filename)); + CORRADE_COMPARE_AS(filename, + "\xd0\x0d\x01", TestSuite::Compare::FileToString); +} + +void AbstractImageConverterTest::convertCompressed3DToFileThroughLevels() { + struct: AbstractImageConverter { + ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedLevels3DToFile; } + bool doConvertToFile(Containers::ArrayView imageLevels, Containers::StringView filename) override { + return Utility::Directory::write(filename, Containers::arrayView( + {char(imageLevels[0].size().x()), char(imageLevels[0].size().y()), char(imageLevels[0].size().z()), char(imageLevels.size())})); + } + } converter; + + const std::string filename = Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"); + + /* Remove previous file, if any */ + Utility::Directory::rm(filename); + CORRADE_VERIFY(!Utility::Directory::exists(filename)); + + CORRADE_VERIFY(converter.convertToFile(CompressedImageView3D{CompressedPixelFormat::Bc1RGBAUnorm, {0xd0, 0x0d, 0x1e}, {nullptr, 64}}, filename)); + CORRADE_COMPARE_AS(filename, + "\xd0\x0d\x1e\x01", TestSuite::Compare::FileToString); +} + +void AbstractImageConverterTest::debugFeature() { + std::ostringstream out; + + Debug{&out} << ImageConverterFeature::ConvertCompressed2D << ImageConverterFeature(0xdeadbeef); + CORRADE_COMPARE(out.str(), "Trade::ImageConverterFeature::ConvertCompressed2D Trade::ImageConverterFeature(0xdeadbeef)\n"); +} + +void AbstractImageConverterTest::debugFeatures() { + std::ostringstream out; + + Debug{&out} << (ImageConverterFeature::Convert2DToData|ImageConverterFeature::ConvertCompressed2DToFile) << ImageConverterFeatures{}; + CORRADE_COMPARE(out.str(), "Trade::ImageConverterFeature::Convert2DToData|Trade::ImageConverterFeature::ConvertCompressed2DToFile Trade::ImageConverterFeatures{}\n"); } void AbstractImageConverterTest::debugFeaturesSupersets() { @@ -1742,6 +3005,34 @@ void AbstractImageConverterTest::debugFeaturesSupersets() { std::ostringstream out; Debug{&out} << (ImageConverterFeature::ConvertCompressed1DToData|ImageConverterFeature::ConvertCompressed1DToFile); CORRADE_COMPARE(out.str(), "Trade::ImageConverterFeature::ConvertCompressed1DToData\n"); + + /* ConvertLevels*DToData is a superset of ConvertLevels*DToFile, so only + one should be printed */ + } { + std::ostringstream out; + Debug{&out} << (ImageConverterFeature::ConvertLevels2DToData|ImageConverterFeature::ConvertLevels2DToFile); + CORRADE_COMPARE(out.str(), "Trade::ImageConverterFeature::ConvertLevels2DToData\n"); + + /* ConvertLevels*DToData is *also* a superset of Convert*DToData, so only + one should be printed */ + } { + std::ostringstream out; + Debug{&out} << (ImageConverterFeature::ConvertLevels3DToData|ImageConverterFeature::Convert3DToData); + CORRADE_COMPARE(out.str(), "Trade::ImageConverterFeature::ConvertLevels3DToData\n"); + + /* ConvertCompressedLevels*DToData is a superset of + ConvertCompressedLevels*DToFile, so only one should be printed */ + } { + std::ostringstream out; + Debug{&out} << (ImageConverterFeature::ConvertCompressedLevels1DToData|ImageConverterFeature::ConvertCompressedLevels1DToFile); + CORRADE_COMPARE(out.str(), "Trade::ImageConverterFeature::ConvertCompressedLevels1DToData\n"); + + /* ConvertCompressedLevels*DToData is *also* a superset of + ConvertCompressed*DToData, so only one should be printed */ + } { + std::ostringstream out; + Debug{&out} << (ImageConverterFeature::ConvertCompressedLevels3DToData|ImageConverterFeature::ConvertCompressed3DToData); + CORRADE_COMPARE(out.str(), "Trade::ImageConverterFeature::ConvertCompressedLevels3DToData\n"); } } diff --git a/src/MagnumPlugins/AnyImageConverter/AnyImageConverter.cpp b/src/MagnumPlugins/AnyImageConverter/AnyImageConverter.cpp index d76db409e8..dfad2fa0ce 100644 --- a/src/MagnumPlugins/AnyImageConverter/AnyImageConverter.cpp +++ b/src/MagnumPlugins/AnyImageConverter/AnyImageConverter.cpp @@ -164,4 +164,4 @@ bool AnyImageConverter::doConvertToFile(const CompressedImageView3D&, const Cont }} CORRADE_PLUGIN_REGISTER(AnyImageConverter, Magnum::Trade::AnyImageConverter, - "cz.mosra.magnum.Trade.AbstractImageConverter/0.3") + "cz.mosra.magnum.Trade.AbstractImageConverter/0.3.1") diff --git a/src/MagnumPlugins/TgaImageConverter/TgaImageConverter.cpp b/src/MagnumPlugins/TgaImageConverter/TgaImageConverter.cpp index 6ff0395b9c..f0e9311816 100644 --- a/src/MagnumPlugins/TgaImageConverter/TgaImageConverter.cpp +++ b/src/MagnumPlugins/TgaImageConverter/TgaImageConverter.cpp @@ -91,4 +91,4 @@ Containers::Array TgaImageConverter::doConvertToData(const ImageView2D& im }} CORRADE_PLUGIN_REGISTER(TgaImageConverter, Magnum::Trade::TgaImageConverter, - "cz.mosra.magnum.Trade.AbstractImageConverter/0.3") + "cz.mosra.magnum.Trade.AbstractImageConverter/0.3.1")