Browse Source

Trade: refresh the AbstractImageConverter API.

First and foremost I need to expand the interface to support 3D
image conversion. But the interface was not great to begin with, so this
takes the opportunity of an API break and does several things:

 * The `export*()` names were rather strange and I don't even remember
   why I chose that name (maybe because at first I wanted to have an
   "exporter" API as a counterpart to importers?)
 * In addition, there was no way to convert a compressed image to a
   compressed image (or to an uncompressed image) and adding the two
   missing variants would be a lot of combinations. So instead the new
   convert() returns an ImageData, which can be both, and thus also
   allows the converters to produce compressed or uncompressed output
   based on some runtime setting, without having to implement two
   (four?) separate functions for that and requiring users to know
   beforehand what type of an image will be created.
 * The ImageConverterFeature enum was named in a really strange way as
   well, with ConvertCompressedImage meaning "convert to a compressed
   image" while "ConvertCompressedData" instead meant "convert a
   compressed image to a data". Utter chaos. It also all implied 2D and
   on the other hand had a redundant `Image` in the name, so I went and
   remade the whole thing. As mentioned above, two of the enums now mean
   the same thing, and are both replaced with Convert2D.
 * Finally, similarly as changes elsewhere, I took this opportunity to
   get rid of std::string in the convertToFile() APIs.
pull/504/head
Vladimír Vondruš 5 years ago
parent
commit
d4c5b3f566
  1. 24
      doc/changelog.dox
  2. 3
      doc/generated/colormaps.cpp
  3. 1
      doc/generated/easings.cpp
  4. 17
      doc/generated/primitives.cpp
  5. 3
      doc/generated/shaders.cpp
  6. 3
      src/Magnum/DebugTools/CompareImage.cpp
  7. 3
      src/Magnum/DebugTools/Screenshot.cpp
  8. 2
      src/Magnum/DebugTools/Test/ScreenshotGLTest.cpp
  9. 21
      src/Magnum/Image.h
  10. 2
      src/Magnum/TextureTools/distancefieldconverter.cpp
  11. 194
      src/Magnum/Trade/AbstractImageConverter.cpp
  12. 378
      src/Magnum/Trade/AbstractImageConverter.h
  13. 1
      src/Magnum/Trade/ImageData.h
  14. 428
      src/Magnum/Trade/Test/AbstractImageConverterTest.cpp
  15. 2
      src/Magnum/Trade/imageconverter.cpp
  16. 20
      src/MagnumPlugins/AnyImageConverter/AnyImageConverter.cpp
  17. 4
      src/MagnumPlugins/AnyImageConverter/AnyImageConverter.h
  18. 19
      src/MagnumPlugins/AnyImageConverter/Test/AnyImageConverterTest.cpp
  19. 2
      src/MagnumPlugins/MagnumFontConverter/MagnumFontConverter.cpp
  20. 12
      src/MagnumPlugins/TgaImageConverter/Test/TgaImageConverterTest.cpp
  21. 12
      src/MagnumPlugins/TgaImageConverter/TgaImageConverter.cpp
  22. 2
      src/MagnumPlugins/TgaImageConverter/TgaImageConverter.h

24
doc/changelog.dox

@ -477,6 +477,30 @@ See also:
@ref MAGNUM_BUILD_DEPRECATED is enabled, the returned type acts as a @ref MAGNUM_BUILD_DEPRECATED is enabled, the returned type acts as a
@ref Corrade::Containers::Optional but has (deprecated) implicit conversion @ref Corrade::Containers::Optional but has (deprecated) implicit conversion
to a @ref Corrade::Containers::Pointer to avoid breaking user code. to a @ref Corrade::Containers::Pointer to avoid breaking user code.
- @cpp Trade::ImageConverterFeature::ConvertImage @ce and
@cpp Trade::ImageConverterFeature::ConvertCompressedImage @ce;
@cpp Trade::AbstractImageConverter::exportToImage() @ce and
@cpp Trade::AbstractImageConverter::exportToCompressedImage() @ce are
deprecated in favor of an unifying
@ref Trade::ImageConverterFeature::Convert2D and a corresponding
@ref Trade::AbstractImageConverter::convert() that returns an
@ref Trade::ImageData2D and thus can handle both cases and follows a naming
scheme used elsewhere
- @cpp Trade::ImageConverterFeature::ConvertFile @ce,
@cpp Trade::ImageConverterFeature::ConvertCompressedFile @ce,
@cpp Trade::ImageConverterFeature::ConvertData @ce and
@cpp Trade::ImageConverterFeature::ConvertCompressedData @ce are deprecated
in favor of @ref Trade::ImageConverterFeature::Convert2DToFile,
@ref Trade::ImageConverterFeature::ConvertCompressed2DToFile,
@ref Trade::ImageConverterFeature::Convert2DToData and
@ref Trade::ImageConverterFeature::ConvertCompressed2DToData that more
clearly imply what's converted to what and make room for 3D image
conversion as well
- @cpp Trade::AbstractImageConverter::exportToData() @ce and
@cpp Trade::AbstractImageConverter::exportToFile() @ce are deprecated in
favor of @ref Trade::AbstractImageConverter::convertToData() and
@ref Trade::AbstractImageConverter::convertToFile() that follow a naming
scheme used elsewhere
- The signature of @ref Trade::AbstractSceneConverter::convertToFile() was - The signature of @ref Trade::AbstractSceneConverter::convertToFile() was
changed to have input first and output second, for consistency with other changed to have input first and output second, for consistency with other
interfaces, together with a switch to @ref Containers::StringView. The interfaces, together with a switch to @ref Containers::StringView. The

3
doc/generated/colormaps.cpp

@ -25,6 +25,7 @@
#include <Corrade/Containers/Array.h> #include <Corrade/Containers/Array.h>
#include <Corrade/Containers/StridedArrayView.h> #include <Corrade/Containers/StridedArrayView.h>
#include <Corrade/Containers/StringView.h>
#include <Corrade/Utility/Algorithms.h> #include <Corrade/Utility/Algorithms.h>
#include "Magnum/PixelFormat.h" #include "Magnum/PixelFormat.h"
@ -62,7 +63,7 @@ int main() {
{std::size_t(OutputSize.y()), std::size_t(OutputSize.x())}}; {std::size_t(OutputSize.y()), std::size_t(OutputSize.x())}};
Utility::copy(src, dst); Utility::copy(src, dst);
if(!converter->exportToFile(ImageView2D{PixelFormat::RGB8Unorm, OutputSize, data}, image.second)) if(!converter->convertToFile(ImageView2D{PixelFormat::RGB8Unorm, OutputSize, data}, image.second))
return 2; return 2;
} }
} }

1
doc/generated/easings.cpp

@ -40,6 +40,7 @@
attribute to the <svg> element if you'd ever need that. attribute to the <svg> element if you'd ever need that.
*/ */
#include <Corrade/Containers/StringStl.h>
#include <Corrade/Utility/Directory.h> #include <Corrade/Utility/Directory.h>
#include <Corrade/Utility/FormatStl.h> #include <Corrade/Utility/FormatStl.h>
#include <Corrade/Utility/String.h> #include <Corrade/Utility/String.h>

17
doc/generated/primitives.cpp

@ -26,6 +26,7 @@
#include <tuple> #include <tuple>
#include <Corrade/Containers/ArrayViewStl.h> #include <Corrade/Containers/ArrayViewStl.h>
#include <Corrade/Containers/Optional.h> #include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/StringStl.h>
#include <Corrade/PluginManager/Manager.h> #include <Corrade/PluginManager/Manager.h>
#include <Corrade/Utility/Directory.h> #include <Corrade/Utility/Directory.h>
@ -198,7 +199,7 @@ int PrimitiveVisualizer::exec() {
GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color); GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color);
Image2D result = framebuffer.read(framebuffer.viewport(), {PixelFormat::RGBA8Unorm}); Image2D result = framebuffer.read(framebuffer.viewport(), {PixelFormat::RGBA8Unorm});
converter->exportToFile(result, Utility::Directory::join("../", "primitives-" + filename)); converter->convertToFile(result, Utility::Directory::join("../", "primitives-" + filename));
} }
} }
@ -217,7 +218,7 @@ int PrimitiveVisualizer::exec() {
GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color); GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color);
Image2D result = framebuffer.read(framebuffer.viewport(), {PixelFormat::RGBA8Unorm}); Image2D result = framebuffer.read(framebuffer.viewport(), {PixelFormat::RGBA8Unorm});
converter->exportToFile(result, Utility::Directory::join("../", "primitives-" + filename)); converter->convertToFile(result, Utility::Directory::join("../", "primitives-" + filename));
} }
} }
@ -242,7 +243,7 @@ int PrimitiveVisualizer::exec() {
GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color); GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color);
Image2D result = framebuffer.read(framebuffer.viewport(), {PixelFormat::RGBA8Unorm}); Image2D result = framebuffer.read(framebuffer.viewport(), {PixelFormat::RGBA8Unorm});
converter->exportToFile(result, Utility::Directory::join("../", "primitives-" + filename)); converter->convertToFile(result, Utility::Directory::join("../", "primitives-" + filename));
} }
} }
@ -273,7 +274,7 @@ int PrimitiveVisualizer::exec() {
GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color); GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color);
Image2D result = framebuffer.read(framebuffer.viewport(), {PixelFormat::RGBA8Unorm}); Image2D result = framebuffer.read(framebuffer.viewport(), {PixelFormat::RGBA8Unorm});
converter->exportToFile(result, Utility::Directory::join("../", "primitives-" + filename)); converter->convertToFile(result, Utility::Directory::join("../", "primitives-" + filename));
} }
} }
@ -304,7 +305,7 @@ int PrimitiveVisualizer::exec() {
GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color); GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color);
Image2D result = framebuffer.read(framebuffer.viewport(), {PixelFormat::RGBA8Unorm}); Image2D result = framebuffer.read(framebuffer.viewport(), {PixelFormat::RGBA8Unorm});
converter->exportToFile(result, Utility::Directory::join("../", "primitives-" + filename)); converter->convertToFile(result, Utility::Directory::join("../", "primitives-" + filename));
} }
} }
@ -348,7 +349,7 @@ int PrimitiveVisualizer::exec() {
GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color); GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color);
Image2D result = framebuffer.read(framebuffer.viewport(), {PixelFormat::RGBA8Unorm}); Image2D result = framebuffer.read(framebuffer.viewport(), {PixelFormat::RGBA8Unorm});
converter->exportToFile(result, Utility::Directory::join("../", "primitives-" + filename)); converter->convertToFile(result, Utility::Directory::join("../", "primitives-" + filename));
} }
} }
@ -371,7 +372,7 @@ int PrimitiveVisualizer::exec() {
GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color); GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color);
Image2D result = framebuffer.read(framebuffer.viewport(), {PixelFormat::RGBA8Unorm}); Image2D result = framebuffer.read(framebuffer.viewport(), {PixelFormat::RGBA8Unorm});
converter->exportToFile(result, Utility::Directory::join("../", "primitives-" + filename)); converter->convertToFile(result, Utility::Directory::join("../", "primitives-" + filename));
} }
} }
@ -394,7 +395,7 @@ int PrimitiveVisualizer::exec() {
GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color); GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color);
Image2D result = framebuffer.read(framebuffer.viewport(), {PixelFormat::RGBA8Unorm}); Image2D result = framebuffer.read(framebuffer.viewport(), {PixelFormat::RGBA8Unorm});
converter->exportToFile(result, Utility::Directory::join("../", "primitives-" + filename)); converter->convertToFile(result, Utility::Directory::join("../", "primitives-" + filename));
} }
} }

3
doc/generated/shaders.cpp

@ -25,6 +25,7 @@
#include <Corrade/Containers/ArrayViewStl.h> #include <Corrade/Containers/ArrayViewStl.h>
#include <Corrade/Containers/Optional.h> #include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/StringStl.h>
#include <Corrade/PluginManager/Manager.h> #include <Corrade/PluginManager/Manager.h>
#include <Corrade/Utility/Directory.h> #include <Corrade/Utility/Directory.h>
@ -145,7 +146,7 @@ int ShaderVisualizer::exec() {
GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color); GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color);
Image2D result = framebuffer.read(framebuffer.viewport(), {PixelFormat::RGBA8Unorm}); Image2D result = framebuffer.read(framebuffer.viewport(), {PixelFormat::RGBA8Unorm});
converter->exportToFile(result, Utility::Directory::join("../", "shaders-" + filename)); converter->convertToFile(result, Utility::Directory::join("../", "shaders-" + filename));
} }
_importer.reset(); _importer.reset();

3
src/Magnum/DebugTools/CompareImage.cpp

@ -29,6 +29,7 @@
#include <sstream> #include <sstream>
#include <Corrade/Containers/Array.h> #include <Corrade/Containers/Array.h>
#include <Corrade/Containers/StridedArrayView.h> #include <Corrade/Containers/StridedArrayView.h>
#include <Corrade/Containers/StringStl.h> /* for Directory */
#include <Corrade/Containers/Optional.h> #include <Corrade/Containers/Optional.h>
#include <Corrade/PluginManager/Manager.h> #include <Corrade/PluginManager/Manager.h>
#include <Corrade/TestSuite/Comparator.h> #include <Corrade/TestSuite/Comparator.h>
@ -734,7 +735,7 @@ void ImageComparatorBase::saveDiagnostic(TestSuite::ComparisonStatusFlags, Utili
we're in the middle of a fail anyway (and everything will print messages we're in the middle of a fail anyway (and everything will print messages
to the output nevertheless). */ to the output nevertheless). */
Containers::Pointer<Trade::AbstractImageConverter> converter = _state->converterManager().loadAndInstantiate("AnyImageConverter"); Containers::Pointer<Trade::AbstractImageConverter> converter = _state->converterManager().loadAndInstantiate("AnyImageConverter");
if(converter && converter->exportToFile(image, filename)) if(converter && converter->convertToFile(image, filename))
out << "->" << filename; out << "->" << filename;
} }

3
src/Magnum/DebugTools/Screenshot.cpp

@ -26,6 +26,7 @@
#include "Screenshot.h" #include "Screenshot.h"
#include <Corrade/Containers/Optional.h> #include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/StringStl.h>
#include <Corrade/PluginManager/Manager.h> #include <Corrade/PluginManager/Manager.h>
#include <Corrade/Utility/DebugStl.h> #include <Corrade/Utility/DebugStl.h>
@ -78,7 +79,7 @@ bool screenshot(PluginManager::Manager<Trade::AbstractImageConverter>& manager,
return false; return false;
Image2D image = framebuffer.read(framebuffer.viewport(), {format}); Image2D image = framebuffer.read(framebuffer.viewport(), {format});
if(!converter->exportToFile(image, filename)) if(!converter->convertToFile(image, filename))
return false; return false;
Debug{} << "DebugTools::screenshot(): saved a" << format << "image of size" << image.size() << "to" << filename; Debug{} << "DebugTools::screenshot(): saved a" << format << "image of size" << image.size() << "to" << filename;

2
src/Magnum/DebugTools/Test/ScreenshotGLTest.cpp

@ -311,7 +311,7 @@ void ScreenshotGLTest::saveFailed() {
MAGNUM_VERIFY_NO_GL_ERROR(); MAGNUM_VERIFY_NO_GL_ERROR();
CORRADE_VERIFY(!succeeded); CORRADE_VERIFY(!succeeded);
CORRADE_COMPARE(out.str(), "Trade::AnyImageConverter::exportToFile(): cannot determine the format of image.poo\n"); CORRADE_COMPARE(out.str(), "Trade::AnyImageConverter::convertToFile(): cannot determine the format of image.poo\n");
} }
}}}} }}}}

21
src/Magnum/Image.h

@ -47,11 +47,6 @@ template<unsigned newDimensions, class U, unsigned dimensions, class T> StridedA
namespace Magnum { namespace Magnum {
#ifndef DOXYGEN_GENERATING_OUTPUT
/** @todo remove once AbstractImageConverter returns ImageData instead */
namespace Trade { class AbstractImageConverter; }
#endif
/** /**
@brief Image @brief Image
@ -471,14 +466,6 @@ template<UnsignedInt dimensions> class Image {
Containers::Array<char> release(); Containers::Array<char> release();
private: private:
#ifndef DOXYGEN_GENERATING_OUTPUT
/* For custom deleter checks. Not done in the constructors here because
the restriction is pointless when used outside of plugin
implementations. */
/** @todo figure out a better way (return ImageData there instead?) */
friend Trade::AbstractImageConverter;
#endif
PixelStorage _storage; PixelStorage _storage;
PixelFormat _format; PixelFormat _format;
UnsignedInt _formatExtra; UnsignedInt _formatExtra;
@ -702,14 +689,6 @@ template<UnsignedInt dimensions> class CompressedImage {
Containers::Array<char> release(); Containers::Array<char> release();
private: private:
#ifndef DOXYGEN_GENERATING_OUTPUT
/* For custom deleter checks. Not done in the constructors here because
the restriction is pointless when used outside of plugin
implementations. */
/** @todo figure out a better way (return ImageData there instead?) */
friend Trade::AbstractImageConverter;
#endif
/* To be made public once block size and block data size are stored /* To be made public once block size and block data size are stored
together with the image */ together with the image */
explicit CompressedImage(CompressedPixelStorage storage, UnsignedInt format, const VectorTypeFor<dimensions, Int>& size, Containers::Array<char>&& data) noexcept; explicit CompressedImage(CompressedPixelStorage storage, UnsignedInt format, const VectorTypeFor<dimensions, Int>& size, Containers::Array<char>&& data) noexcept;

2
src/Magnum/TextureTools/distancefieldconverter.cpp

@ -215,7 +215,7 @@ int DistanceFieldConverter::exec() {
/* Save image */ /* Save image */
Image2D result{PixelFormat::R8Unorm}; Image2D result{PixelFormat::R8Unorm};
output.image(0, result); output.image(0, result);
if(!converter->exportToFile(result, args.value("output"))) { if(!converter->convertToFile(result, args.value("output"))) {
Error() << "Cannot save file" << args.value("output"); Error() << "Cannot save file" << args.value("output");
return 5; return 5;
} }

194
src/Magnum/Trade/AbstractImageConverter.cpp

@ -28,6 +28,8 @@
#include <Corrade/Containers/Array.h> #include <Corrade/Containers/Array.h>
#include <Corrade/Containers/EnumSet.hpp> #include <Corrade/Containers/EnumSet.hpp>
#include <Corrade/Containers/Optional.h> #include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/StringView.h>
#include <Corrade/Containers/StringStl.h> /* for Directory */
#include <Corrade/Utility/Assert.h> #include <Corrade/Utility/Assert.h>
#include <Corrade/Utility/Directory.h> #include <Corrade/Utility/Directory.h>
#include <Corrade/Utility/DebugStl.h> #include <Corrade/Utility/DebugStl.h>
@ -45,7 +47,7 @@ namespace Magnum { namespace Trade {
std::string AbstractImageConverter::pluginInterface() { std::string AbstractImageConverter::pluginInterface() {
return return
/* [interface] */ /* [interface] */
"cz.mosra.magnum.Trade.AbstractImageConverter/0.2.1" "cz.mosra.magnum.Trade.AbstractImageConverter/0.3"
/* [interface] */ /* [interface] */
; ;
} }
@ -93,109 +95,181 @@ void AbstractImageConverter::clearFlags(ImageConverterFlags flags) {
setFlags(_flags & ~flags); setFlags(_flags & ~flags);
} }
Containers::Optional<Image2D> AbstractImageConverter::exportToImage(const ImageView2D& image) { Containers::Optional<ImageData2D> AbstractImageConverter::convert(const ImageView2D& image) {
CORRADE_ASSERT(features() & ImageConverterFeature::ConvertImage, CORRADE_ASSERT(features() & ImageConverterFeature::Convert2D,
"Trade::AbstractImageConverter::exportToImage(): feature not supported", {}); "Trade::AbstractImageConverter::convert(): 2D image conversion not supported", {});
Containers::Optional<Image2D> out = doExportToImage(image); Containers::Optional<ImageData2D> out = doConvert(image);
CORRADE_ASSERT(!out || !out->_data.deleter(), "Trade::AbstractImageConverter::exportToImage(): implementation is not allowed to use a custom Array deleter", {}); CORRADE_ASSERT(!out || !out->_data.deleter(), "Trade::AbstractImageConverter::convert(): implementation is not allowed to use a custom Array deleter", {});
return out; return out;
} }
Containers::Optional<Image2D> AbstractImageConverter::doExportToImage(const ImageView2D&) { Containers::Optional<ImageData2D> AbstractImageConverter::doConvert(const ImageView2D&) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::exportToImage(): feature advertised but not implemented", {}); CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::convert(): 2D image conversion advertised but not implemented", {});
}
#ifdef MAGNUM_BUILD_DEPRECATED
Containers::Optional<Image2D> AbstractImageConverter::exportToImage(const ImageView2D& image) {
Containers::Optional<ImageData2D> out = convert(image);
if(!out) return {};
if(out->isCompressed()) {
Error{} << "Trade::AbstractImageConverter::exportToImage(): implementation returned a compressed image";
return {};
}
const PixelStorage storage = out->storage();
const PixelFormat format = out->format();
const UnsignedInt formatExtra = out->formatExtra();
const UnsignedInt pixelSize = out->pixelSize();
const Vector2i size = out->size();
return Image2D{storage, format, formatExtra, pixelSize, size, out->release()};
} }
Containers::Optional<CompressedImage2D> AbstractImageConverter::exportToCompressedImage(const ImageView2D& image) { Containers::Optional<CompressedImage2D> AbstractImageConverter::exportToCompressedImage(const ImageView2D& image) {
CORRADE_ASSERT(features() & ImageConverterFeature::ConvertCompressedImage, Containers::Optional<ImageData2D> out = convert(image);
"Trade::AbstractImageConverter::exportToCompressedImage(): feature not supported", {}); if(!out) return {};
if(!out->isCompressed()) {
Error{} << "Trade::AbstractImageConverter::exportToCompressedImage(): implementation returned an uncompressed image";
return {};
}
const CompressedPixelStorage storage = out->compressedStorage();
const CompressedPixelFormat format = out->compressedFormat();
const Vector2i size = out->size();
return CompressedImage2D{storage, format, size, out->release()};
}
#endif
Containers::Optional<CompressedImage2D> out = doExportToCompressedImage(image); Containers::Optional<ImageData2D> AbstractImageConverter::convert(const CompressedImageView2D& image) {
CORRADE_ASSERT(!out || !out->_data.deleter(), "Trade::AbstractImageConverter::exportToCompressedImage(): implementation is not allowed to use a custom Array deleter", {}); CORRADE_ASSERT(features() & ImageConverterFeature::ConvertCompressed2D,
"Trade::AbstractImageConverter::convert(): compressed 2D image conversion not supported", {});
Containers::Optional<ImageData2D> out = doConvert(image);
CORRADE_ASSERT(!out || !out->_data.deleter(), "Trade::AbstractImageConverter::convert(): implementation is not allowed to use a custom Array deleter", {});
return out; return out;
} }
Containers::Optional<CompressedImage2D> AbstractImageConverter::doExportToCompressedImage(const ImageView2D&) { Containers::Optional<ImageData2D> AbstractImageConverter::doConvert(const CompressedImageView2D&) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::exportToCompressedImage(): feature advertised but not implemented", {}); CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::convert(): compressed 2D image conversion advertised but not implemented", {});
} }
Containers::Array<char> AbstractImageConverter::exportToData(const ImageView2D& image) { Containers::Optional<ImageData2D> AbstractImageConverter::convert(const ImageData2D& image) {
CORRADE_ASSERT(features() & ImageConverterFeature::ConvertData, return image.isCompressed() ? convert(CompressedImageView2D(image)) : convert(ImageView2D(image));
"Trade::AbstractImageConverter::exportToData(): feature not supported", nullptr); }
Containers::Array<char> out = doExportToData(image); Containers::Array<char> AbstractImageConverter::convertToData(const ImageView2D& image) {
CORRADE_ASSERT(!out.deleter(), "Trade::AbstractImageConverter::exportToData(): implementation is not allowed to use a custom Array deleter", {}); CORRADE_ASSERT(features() >= ImageConverterFeature::Convert2DToData,
"Trade::AbstractImageConverter::convertToData(): 2D image conversion not supported", nullptr);
Containers::Array<char> out = doConvertToData(image);
CORRADE_ASSERT(!out.deleter(), "Trade::AbstractImageConverter::convertToData(): implementation is not allowed to use a custom Array deleter", {});
return out; return out;
} }
Containers::Array<char> AbstractImageConverter::doExportToData(const ImageView2D&) { Containers::Array<char> AbstractImageConverter::doConvertToData(const ImageView2D&) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::exportToData(): feature advertised but not implemented", nullptr); CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::convertToData(): 2D image conversion advertised but not implemented", nullptr);
} }
Containers::Array<char> AbstractImageConverter::exportToData(const CompressedImageView2D& image) { #ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_ASSERT(features() & ImageConverterFeature::ConvertCompressedData, Containers::Array<char> AbstractImageConverter::exportToData(const ImageView2D& image) {
"Trade::AbstractImageConverter::exportToData(): feature not supported", nullptr); return convertToData(image);
}
#endif
Containers::Array<char> out = doExportToData(image); Containers::Array<char> AbstractImageConverter::convertToData(const CompressedImageView2D& image) {
CORRADE_ASSERT(!out.deleter(), "Trade::AbstractImageConverter::exportToData(): implementation is not allowed to use a custom Array deleter", {}); CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertCompressed2DToData,
"Trade::AbstractImageConverter::convertToData(): compressed 2D image conversion not supported", nullptr);
Containers::Array<char> out = doConvertToData(image);
CORRADE_ASSERT(!out.deleter(), "Trade::AbstractImageConverter::convertToData(): implementation is not allowed to use a custom Array deleter", {});
return out; return out;
} }
Containers::Array<char> AbstractImageConverter::doExportToData(const CompressedImageView2D&) { Containers::Array<char> AbstractImageConverter::doConvertToData(const CompressedImageView2D&) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::exportToData(): feature advertised but not implemented", nullptr); CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::convertToData(): compressed 2D image conversion advertised but not implemented", nullptr);
}
#ifdef MAGNUM_BUILD_DEPRECATED
Containers::Array<char> AbstractImageConverter::exportToData(const CompressedImageView2D& image) {
return convertToData(image);
}
#endif
Containers::Array<char> AbstractImageConverter::convertToData(const ImageData2D& image) {
return image.isCompressed() ? convertToData(CompressedImageView2D(image)) : convertToData(ImageView2D(image));
} }
#ifdef MAGNUM_BUILD_DEPRECATED
Containers::Array<char> AbstractImageConverter::exportToData(const ImageData2D& image) { Containers::Array<char> AbstractImageConverter::exportToData(const ImageData2D& image) {
return image.isCompressed() ? exportToData(CompressedImageView2D(image)) : exportToData(ImageView2D(image)); return convertToData(image);
} }
#endif
bool AbstractImageConverter::exportToFile(const ImageView2D& image, const std::string& filename) { bool AbstractImageConverter::convertToFile(const ImageView2D& image, const Containers::StringView filename) {
CORRADE_ASSERT(features() & ImageConverterFeature::ConvertFile, CORRADE_ASSERT(features() & ImageConverterFeature::Convert2DToFile,
"Trade::AbstractImageConverter::exportToFile(): feature not supported", {}); "Trade::AbstractImageConverter::convertToFile(): 2D image conversion not supported", {});
return doExportToFile(image, filename); return doConvertToFile(image, filename);
} }
bool AbstractImageConverter::doExportToFile(const ImageView2D& image, const std::string& filename) { bool AbstractImageConverter::doConvertToFile(const ImageView2D& image, const Containers::StringView filename) {
CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertData, "Trade::AbstractImageConverter::exportToFile(): feature advertised but not implemented", false); CORRADE_ASSERT(features() >= ImageConverterFeature::Convert2DToData, "Trade::AbstractImageConverter::convertToFile(): 2D image conversion advertised but not implemented", false);
const auto data = doExportToData(image); const auto data = doConvertToData(image);
/* No deleter checks as it doesn't matter here */ /* No deleter checks as it doesn't matter here */
if(!data) return false; if(!data) return false;
if(!Utility::Directory::write(filename, data)) { if(!Utility::Directory::write(filename, data)) {
Error() << "Trade::AbstractImageConverter::exportToFile(): cannot write to file" << filename; Error() << "Trade::AbstractImageConverter::convertToFile(): cannot write to file" << filename;
return false; return false;
} }
return true; return true;
} }
bool AbstractImageConverter::exportToFile(const CompressedImageView2D& image, const std::string& filename) { #ifdef MAGNUM_BUILD_DEPRECATED
CORRADE_ASSERT(features() & ImageConverterFeature::ConvertCompressedFile, bool AbstractImageConverter::exportToFile(const ImageView2D& image, const std::string& filename) {
"Trade::AbstractImageConverter::exportToFile(): feature not supported", {}); return convertToFile(image, filename);
}
#endif
bool AbstractImageConverter::convertToFile(const CompressedImageView2D& image, const Containers::StringView filename) {
CORRADE_ASSERT(features() & ImageConverterFeature::ConvertCompressed2DToFile,
"Trade::AbstractImageConverter::convertToFile(): compressed 2D image conversion not supported", {});
return doExportToFile(image, filename); return doConvertToFile(image, filename);
} }
bool AbstractImageConverter::doExportToFile(const CompressedImageView2D& image, const std::string& filename) { bool AbstractImageConverter::doConvertToFile(const CompressedImageView2D& image, Containers::StringView filename) {
CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertCompressedData, "Trade::AbstractImageConverter::exportToFile(): feature advertised but not implemented", false); CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertCompressed2DToData, "Trade::AbstractImageConverter::convertToFile(): compressed 2D image conversion advertised but not implemented", false);
const auto data = doExportToData(image); const auto data = doConvertToData(image);
/* No deleter checks as it doesn't matter here */ /* No deleter checks as it doesn't matter here */
if(!data) return false; if(!data) return false;
if(!Utility::Directory::write(filename, data)) { if(!Utility::Directory::write(filename, data)) {
Error() << "Trade::AbstractImageConverter::exportToFile(): cannot write to file" << filename; Error() << "Trade::AbstractImageConverter::convertToFile(): cannot write to file" << filename;
return false; return false;
} }
return true; return true;
} }
#ifdef MAGNUM_BUILD_DEPRECATED
bool AbstractImageConverter::exportToFile(const CompressedImageView2D& image, const std::string& filename) {
return convertToFile(image, filename);
}
#endif
bool AbstractImageConverter::convertToFile(const ImageData2D& image, const Containers::StringView filename) {
return image.isCompressed() ? convertToFile(CompressedImageView2D(image), filename) : convertToFile(ImageView2D(image), filename);
}
#ifdef MAGNUM_BUILD_DEPRECATED
bool AbstractImageConverter::exportToFile(const ImageData2D& image, const std::string& filename) { bool AbstractImageConverter::exportToFile(const ImageData2D& image, const std::string& filename) {
return image.isCompressed() ? exportToFile(CompressedImageView2D(image), filename) : exportToFile(ImageView2D(image), filename); return convertToFile(image, filename);
} }
#endif
Debug& operator<<(Debug& debug, const ImageConverterFeature value) { Debug& operator<<(Debug& debug, const ImageConverterFeature value) {
debug << "Trade::ImageConverterFeature" << Debug::nospace; debug << "Trade::ImageConverterFeature" << Debug::nospace;
@ -203,28 +277,28 @@ Debug& operator<<(Debug& debug, const ImageConverterFeature value) {
switch(value) { switch(value) {
/* LCOV_EXCL_START */ /* LCOV_EXCL_START */
#define _c(v) case ImageConverterFeature::v: return debug << "::" #v; #define _c(v) case ImageConverterFeature::v: return debug << "::" #v;
_c(ConvertImage) _c(Convert2D)
_c(ConvertCompressedImage) _c(ConvertCompressed2D)
_c(ConvertFile) _c(Convert2DToFile)
_c(ConvertCompressedFile) _c(ConvertCompressed2DToFile)
_c(ConvertData) _c(Convert2DToData)
_c(ConvertCompressedData) _c(ConvertCompressed2DToData)
#undef _c #undef _c
/* LCOV_EXCL_STOP */ /* LCOV_EXCL_STOP */
} }
return debug << "(" << Debug::nospace << reinterpret_cast<void*>(UnsignedByte(value)) << Debug::nospace << ")"; return debug << "(" << Debug::nospace << reinterpret_cast<void*>(UnsignedInt(value)) << Debug::nospace << ")";
} }
Debug& operator<<(Debug& debug, const ImageConverterFeatures value) { Debug& operator<<(Debug& debug, const ImageConverterFeatures value) {
return Containers::enumSetDebugOutput(debug, value, "Trade::ImageConverterFeatures{}", { return Containers::enumSetDebugOutput(debug, value, "Trade::ImageConverterFeatures{}", {
ImageConverterFeature::ConvertImage, ImageConverterFeature::Convert2D,
ImageConverterFeature::ConvertCompressedImage, ImageConverterFeature::ConvertCompressed2D,
ImageConverterFeature::ConvertData, ImageConverterFeature::Convert2DToData,
ImageConverterFeature::ConvertCompressedData, ImageConverterFeature::ConvertCompressed2DToData,
/* These are implied by Convert[Compressed]Data, so have to be last */ /* These are implied by Convert[Compressed]ToData, so have to be last */
ImageConverterFeature::ConvertFile, ImageConverterFeature::Convert2DToFile,
ImageConverterFeature::ConvertCompressedFile}); ImageConverterFeature::ConvertCompressed2DToFile});
} }
Debug& operator<<(Debug& debug, const ImageConverterFlag value) { Debug& operator<<(Debug& debug, const ImageConverterFlag value) {

378
src/Magnum/Trade/AbstractImageConverter.h

@ -43,44 +43,106 @@ namespace Magnum { namespace Trade {
@see @ref ImageConverterFeatures, @ref AbstractImageConverter::features() @see @ref ImageConverterFeatures, @ref AbstractImageConverter::features()
*/ */
enum class ImageConverterFeature: UnsignedByte { enum class ImageConverterFeature: UnsignedInt {
/** /**
* Conversion to image with different format with * Convert a 2D image with
* @ref AbstractImageConverter::exportToImage() * @ref AbstractImageConverter::convert(const ImageView2D&)
* @m_since_latest
*/ */
ConvertImage = 1 << 0, Convert2D = 1 << 0,
#ifdef MAGNUM_BUILD_DEPRECATED
/** /**
* Conversion to compressed image with * @copydoc ImageConverterFeature::Convert2D
* @ref AbstractImageConverter::exportToCompressedImage() * @m_deprecated_since_latest Use @ref ImageConverterFeature::Convert2D
* instead.
*/ */
ConvertCompressedImage = 1 << 1, ConvertImage CORRADE_DEPRECATED_ENUM("use ImageConverterFeature::Convert2D instead") = Convert2D,
/** /**
* Exporting to file with * @copydoc ImageConverterFeature::Convert2D
* @ref AbstractImageConverter::exportToFile(const ImageView2D&, const std::string&) * @m_deprecated_since_latest Use @ref ImageConverterFeature::Convert2D
* instead. Since @ref AbstractImageConverter::convert() is now
* capable of returning both uncompressed and compressed images, this
* feature is the same as @ref ImageConverterFeature::Convert2D, as
* opposed to @ref ImageConverterFeature::ConvertCompressed2D, which
* is about *input* images.
*/ */
ConvertFile = 1 << 2, ConvertCompressedImage CORRADE_DEPRECATED_ENUM("use ImageConverterFeature::Convert2D instead") = Convert2D,
#endif
/** /**
* Exporting to file with * Convert a compressed 2D image with
* @ref AbstractImageConverter::exportToFile(const CompressedImageView2D&, const std::string&) * @ref AbstractImageConverter::convert(const CompressedImageView2D&)
* @m_since_latest
*/ */
ConvertCompressedFile = 1 << 3, ConvertCompressed2D = 1 << 1,
/** /**
* Exporting to raw data with * Convert a 2D image to a file with
* @ref AbstractImageConverter::exportToData(const ImageView2D&). * @ref AbstractImageConverter::convertToFile(const ImageView2D&, Containers::StringView)
* Implies @ref ImageConverterFeature::ConvertFile. * @m_since_latest
*/ */
ConvertData = ConvertFile|(1 << 4), Convert2DToFile = 1 << 2,
#ifdef MAGNUM_BUILD_DEPRECATED
/** /**
* Exporting compressed image to raw data with * @copydoc ImageConverterFeature::Convert2DToFile
* @ref AbstractImageConverter::exportToData(const CompressedImageView2D&). * @m_deprecated_since_latest Use
* Implies @ref ImageConverterFeature::ConvertCompressedFile. * @ref ImageConverterFeature::Convert2DToFile instead.
*/ */
ConvertCompressedData = ConvertCompressedFile|(1 << 4) ConvertFile CORRADE_DEPRECATED_ENUM("use ImageConverterFeature::Convert2DToFile instead") = Convert2DToFile,
#endif
/**
* Convert a compressed 2D image to a file with
* @ref AbstractImageConverter::convertToFile(const CompressedImageView2D&, Containers::StringView)
* @m_since_latest
*/
ConvertCompressed2DToFile = 1 << 3,
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copydoc ImageConverterFeature::ConvertCompressed2DToFile
* @m_deprecated_since_latest Use
* @ref ImageConverterFeature::ConvertCompressed2DToFile instead.
*/
ConvertCompressedFile CORRADE_DEPRECATED_ENUM("use ImageConverterFeature::ConvertCompressed2DToFile instead") = ConvertCompressed2DToFile,
#endif
/**
* Convert a 2D image to raw data with
* @ref AbstractImageConverter::convertToData(const ImageView2D&).
* Implies @ref ImageConverterFeature::Convert2DToFile.
* @m_since_latest
*/
Convert2DToData = Convert2DToFile|(1 << 4),
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copydoc ImageConverterFeature::Convert2DToData
* @m_deprecated_since_latest Use
* @ref ImageConverterFeature::Convert2DToData instead.
*/
ConvertData CORRADE_DEPRECATED_ENUM("use ImageConverterFeature::Convert2DToData instead") = Convert2DToData,
#endif
/**
* Convert a compressed 2D image to raw data with
* @ref AbstractImageConverter::convertToData(const CompressedImageView2D&).
* Implies @ref ImageConverterFeature::ConvertCompressed2DToFile.
* @m_since_latest
*/
ConvertCompressed2DToData = ConvertCompressed2DToFile|(1 << 4),
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @copydoc ImageConverterFeature::ConvertCompressed2DToData
* @m_deprecated_since_latest Use
* @ref ImageConverterFeature::ConvertCompressed2DToData instead.
*/
ConvertCompressedData CORRADE_DEPRECATED_ENUM("use ImageConverterFeature::ConvertCompressed2DToData instead") = ConvertCompressed2DToData,
#endif
}; };
/** /**
@ -170,24 +232,24 @@ the plugin module has been unloaded.
@section Trade-AbstractImageConverter-subclassing Subclassing @section Trade-AbstractImageConverter-subclassing Subclassing
The plugin needs to implement the @ref doFeatures() function and one or more of The plugin needs to implement the @ref doFeatures() function and one or more of
@ref doExportToImage(), @ref doExportToCompressedImage(), @ref doExportToData() @ref doConvert(), @ref doConvertToData() or @ref doConvertToFile() functions
or @ref doExportToFile() functions based on what features are supported. based on what features are supported.
You don't need to do most of the redundant sanity checks, these things are You don't need to do most of the redundant sanity checks, these things are
checked by the implementation: checked by the implementation:
- The function @ref doExportToImage() is called only if - The function @ref doConvert(const ImageView2D&) is called only if
@ref ImageConverterFeature::ConvertImage is supported. @ref ImageConverterFeature::Convert2D is supported.
- The function @ref doExportToCompressedImage() is called only if - The function @ref doConvert(const CompressedImageView2D&) is called only if
@ref ImageConverterFeature::ConvertCompressedImage is supported. @ref ImageConverterFeature::ConvertCompressed2D is supported.
- The function @ref doExportToData(const ImageView2D&) is called only if - The function @ref doConvertToData(const ImageView2D&) is called only if
@ref ImageConverterFeature::ConvertData is supported. @ref ImageConverterFeature::Convert2DToData is supported.
- The function @ref doExportToData(const CompressedImageView2D&) is called - The function @ref doConvertToData(const CompressedImageView2D&) is called
only if @ref ImageConverterFeature::ConvertCompressedData is supported. only if @ref ImageConverterFeature::ConvertCompressed2DToData is supported.
- The function @ref doExportToFile(const ImageView2D&, const std::string&) is - The function @ref doConvertToFile(const ImageView2D&, Containers::StringView)
called only if @ref ImageConverterFeature::ConvertFile is supported. is called only if @ref ImageConverterFeature::Convert2DToFile is supported.
- The function @ref doExportToFile(const CompressedImageView2D&, const std::string&) - The function @ref doConvertToFile(const CompressedImageView2D&, Containers::StringView)
is called only if @ref ImageConverterFeature::ConvertCompressedFile is is called only if @ref ImageConverterFeature::ConvertCompressed2DToFile is
supported. supported.
@m_class{m-block m-warning} @m_class{m-block m-warning}
@ -292,86 +354,194 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract
void clearFlags(ImageConverterFlags flags); void clearFlags(ImageConverterFlags flags);
/** /**
* @brief Convert image to different format * @brief Convert a 2D image
* @m_since_latest
* *
* Available only if @ref ImageConverterFeature::ConvertImage is * Available only if @ref ImageConverterFeature::Convert2D is
* supported. Returns converted image on success, * supported. Returns converted image on success,
* @ref Containers::NullOpt otherwise. * @ref Containers::NullOpt otherwise. The implementation is allowed to
* @see @ref features(), @ref exportToData(), @ref exportToFile() * return both a compressed an an uncompressed image, see documentation
* of a particular converter for more information.
* @see @ref features(), @ref convert(const CompressedImageView2D&),
* @ref convert(const ImageData2D&), @ref convertToData(),
* @ref convertToFile(), @ref ImageData::isCompressed()
*/ */
Containers::Optional<Image2D> exportToImage(const ImageView2D& image); Containers::Optional<ImageData2D> convert(const ImageView2D& image);
#ifdef MAGNUM_BUILD_DEPRECATED
/** /**
* @brief Convert image to compressed format * @brief @copybrief convert(const ImageView2D&)
* @m_deprecated_since_latest Use @ref convert(const ImageView2D&)
* instead.
*/
CORRADE_DEPRECATED("use convert(const ImageView2D&) instead") Containers::Optional<Image2D> exportToImage(const ImageView2D& image);
/**
* @brief Convert a 2D image to compressed format
* @m_deprecated_since_latest Use @ref convert(const ImageView2D&)
* instead.
*/
CORRADE_DEPRECATED("use convert(const ImageView2D&) instead") Containers::Optional<CompressedImage2D> exportToCompressedImage(const ImageView2D& image);
#endif
/**
* @brief Convert a compressed 2D image
* @m_since_latest
* *
* Available only if @ref ImageConverterFeature::ConvertCompressedImage * Available only if @ref ImageConverterFeature::ConvertCompressed2D is
* is supported. Returns converted image on success, * supported. Returns converted image on success,
* @ref Containers::NullOpt otherwise. * @ref Containers::NullOpt otherwise. The implementation is allowed to
* @see @ref features(), @ref exportToData(), @ref exportToFile() * return both a compressed an an uncompressed image, see documentation
* of a particular converter for more information.
* @see @ref features(), @ref convert(const ImageView2D&),
* @ref convert(const ImageData2D&), @ref convertToData(),
* @ref convertToFile(), @ref ImageData::isCompressed()
*/ */
Containers::Optional<CompressedImage2D> exportToCompressedImage(const ImageView2D& image); Containers::Optional<ImageData2D> convert(const CompressedImageView2D& image);
/** /**
* @brief Export image to raw data * @brief Convert a 2D image data
* @m_since_latest
* *
* Available only if @ref ImageConverterFeature::ConvertData is * Based on whether the image is compressed or not, calls either
* supported. Returns data on success, zero-sized array otherwise. * @ref convert(const ImageView2D&) or
* @see @ref features(), @ref exportToImage(), * @ref convert(const CompressedImageView2D&). See documentation of
* @ref exportToFile(const ImageView2D&, const std::string&) * these two functions for details.
* @see @ref ImageData::isCompressed()
*/ */
Containers::Array<char> exportToData(const ImageView2D& image); Containers::Optional<ImageData2D> convert(const ImageData2D& image);
/** /**
* @brief Export compressed image to raw data * @brief Convert a 2D image to a raw data
* @m_since_latest
* *
* Available only if @ref ImageConverterFeature::ConvertCompressedData * Available only if @ref ImageConverterFeature::Convert2DToData is
* is supported. Returns data on success, zero-sized array otherwise. * supported. Returns data on success, @cpp nullptr @ce otherwise.
* @see @ref features(), @ref exportToCompressedImage(), * @see @ref features(), @ref convertToData(const CompressedImageView2D&),
* @ref exportToFile(const CompressedImageView2D&, const std::string&) * @ref convertToData(const ImageData2D&), @ref convert(),
* @ref convertToFile()
*/ */
Containers::Array<char> exportToData(const CompressedImageView2D& image); Containers::Array<char> convertToData(const ImageView2D& image);
#ifdef MAGNUM_BUILD_DEPRECATED
/** /**
* @brief Export image to raw data * @brief @copybrief convertToData(const ImageView2D&)
* @m_deprecated_since_latest Use @ref convertToData(const ImageView2D&)
* instead.
*/
CORRADE_DEPRECATED("use convertToData(const ImageView2D&) instead") Containers::Array<char> exportToData(const ImageView2D& image);
#endif
/**
* @brief Convert a compressed 2D image to a raw data
* @m_since_latest
*
* Available only if @ref ImageConverterFeature::ConvertCompressed2DToData
* 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()
*/
Containers::Array<char> convertToData(const CompressedImageView2D& image);
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @brief @copybrief convertToData(const CompressedImageView2D&)
* @m_deprecated_since_latest Use
* @ref convertToData(const CompressedImageView2D&) instead.
*/
CORRADE_DEPRECATED("use convertToData(const CompressedImageView2D&) instead") Containers::Array<char> exportToData(const CompressedImageView2D& image);
#endif
/**
* @brief Convert a 2D image data to a raw data
* @m_since_latest
* *
* Based on whether the image is compressed or not, calls either * Based on whether the image is compressed or not, calls either
* @ref exportToData(const ImageView2D&) or * @ref convertToData(const ImageView2D&) or
* @ref exportToData(const CompressedImageView2D&). See documentation * @ref convertToData(const CompressedImageView2D&). See documentation
* of those two functions for details. * of these two functions for details.
* @see @ref ImageData::isCompressed()
*/ */
Containers::Array<char> exportToData(const ImageData2D& image); Containers::Array<char> convertToData(const ImageData2D& image);
#ifdef MAGNUM_BUILD_DEPRECATED
/** /**
* @brief Export image to file * @brief @copybrief convertToData(const ImageData2D&)
* @m_deprecated_since_latest Use @ref convertToData(const ImageData2D&)
* instead.
*/
CORRADE_DEPRECATED("use convertToData(const ImageView2D&) instead") Containers::Array<char> exportToData(const ImageData2D& image);
#endif
/**
* @brief Convert a 2D image to a file
* @m_since_latest
* *
* Available only if @ref ImageConverterFeature::ConvertFile or * Available only if @ref ImageConverterFeature::Convert2DToFile or
* @ref ImageConverterFeature::ConvertData is supported. Returns * @ref ImageConverterFeature::Convert2DToData is supported. Returns
* @cpp true @ce on success, @cpp false @ce otherwise. * @cpp true @ce on success, @cpp false @ce otherwise.
* @see @ref features(), @ref exportToImage(), * @see @ref features(), @ref convertToFile(const CompressedImageView2D&, Containers::StringView),
* @ref exportToData(const ImageView2D&) * @ref convertToFile(const ImageData2D&, Containers::StringView),
* @ref convert(), @ref convertToData()
*/ */
bool exportToFile(const ImageView2D& image, const std::string& filename); bool convertToFile(const ImageView2D& image, Containers::StringView filename);
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @brief @copybrief convertToFile(const ImageView2D&, Containers::StringView)
* @m_deprecated_since_latest Use
* @ref convertToFile(const ImageView2D&, Containers::StringView)
* instead.
*/
CORRADE_DEPRECATED("use convertToFile(const ImageView2D&, Containers::StringView) instead") bool exportToFile(const ImageView2D& image, const std::string& filename);
#endif
/** /**
* @brief Export compressed image to file * @brief Convert a compressed 2D image to a file
* @m_since_latest
* *
* Available only if @ref ImageConverterFeature::ConvertCompressedFile * Available only if @ref ImageConverterFeature::ConvertCompressed2DToFile
* or @ref ImageConverterFeature::ConvertCompressedData is supported. * or @ref ImageConverterFeature::ConvertCompressed2DToData is
* Returns @cpp true @ce on success, @cpp false @ce otherwise. * supported. Returns @cpp true @ce on success, @cpp false @ce
* @see @ref features(), @ref exportToCompressedImage(), * otherwise.
* @ref exportToData(const CompressedImageView2D&) * @see @ref features(), @ref convertToFile(const ImageView2D&, Containers::StringView),
* @ref convertToFile(const ImageData2D&, Containers::StringView),
* @ref convert(), @ref convertToData()
*/
bool convertToFile(const CompressedImageView2D& image, Containers::StringView filename);
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @brief @copybrief convertToFile(const CompressedImageView2D&, Containers::StringView)
* @m_deprecated_since_latest Use
* @ref convertToFile(const CompressedImageView2D&, Containers::StringView)
* instead.
*/ */
bool exportToFile(const CompressedImageView2D& image, const std::string& filename); CORRADE_DEPRECATED("use convertToFile(const CompressedImageView2D&, Containers::StringView) instead") bool exportToFile(const CompressedImageView2D& image, const std::string& filename);
#endif
/** /**
* @brief Export image to file * @brief Convert a 2D image data to a file
* @m_since_latest
* *
* Based on whether the image is compressed or not, calls either * Based on whether the image is compressed or not, calls either
* @ref exportToFile(const ImageView2D&, const std::string&) or * @ref convertToFile(const ImageView2D&, Containers::StringView) or
* @ref exportToFile(const CompressedImageView2D&, const std::string&). * @ref convertToFile(const CompressedImageView2D&, Containers::StringView).
* See documentation of those two functions for details. * See documentation of these two functions for details.
* @see @ref ImageData::isCompressed()
*/ */
bool exportToFile(const ImageData2D& image, const std::string& filename); bool convertToFile(const ImageData2D& image, Containers::StringView filename);
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* @brief @copybrief convertToFile(const ImageData2D&, Containers::StringView)
* @m_deprecated_since_latest Use
* @ref convertToFile(const ImageData2D&, Containers::StringView)
* instead.
*/
CORRADE_DEPRECATED("use convertToFile(const ImageData2D&, Containers::StringView) instead") bool exportToFile(const ImageData2D& image, const std::string& filename);
#endif
private: private:
/** @brief Implementation for @ref features() */ /** @brief Implementation for @ref features() */
@ -392,35 +562,49 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract
*/ */
virtual void doSetFlags(ImageConverterFlags flags); virtual void doSetFlags(ImageConverterFlags flags);
/** @brief Implementation for @ref exportToImage() */ /**
virtual Containers::Optional<Image2D> doExportToImage(const ImageView2D& image); * @brief Implementation for @ref convert(const ImageView2D&)
* @m_since_latest
*/
virtual Containers::Optional<ImageData2D> doConvert(const ImageView2D& image);
/** @brief Implementation for @ref exportToCompressedImage() */ /**
virtual Containers::Optional<CompressedImage2D> doExportToCompressedImage(const ImageView2D& image); * @brief Implementation for @ref convert(const CompressedImageView2D&)
* @m_since_latest
*/
virtual Containers::Optional<ImageData2D> doConvert(const CompressedImageView2D& image);
/** @brief Implementation for @ref exportToData(const ImageView2D&) */ /**
virtual Containers::Array<char> doExportToData(const ImageView2D& image); * @brief Implementation for @ref convertToData(const ImageView2D&)
* @m_since_latest
*/
virtual Containers::Array<char> doConvertToData(const ImageView2D& image);
/** @brief Implementation for @ref exportToData(const CompressedImageView2D&) */ /**
virtual Containers::Array<char> doExportToData(const CompressedImageView2D& image); * @brief Implementation for @ref convertToData(const CompressedImageView2D&)
* @m_since_latest
*/
virtual Containers::Array<char> doConvertToData(const CompressedImageView2D& image);
/** /**
* @brief Implementation for @ref exportToFile(const ImageView2D&, const std::string&) * @brief Implementation for @ref convertToFile(const ImageView2D&, Containers::StringView)
* @m_since_latest
* *
* If @ref ImageConverterFeature::ConvertData is supported, default * If @ref ImageConverterFeature::Convert2DToData is supported, default
* implementation calls @ref doExportToData(const ImageView2D&) and * implementation calls @ref doConvertToData(const ImageView2D&) and
* saves the result to given file. * saves the result to given file.
*/ */
virtual bool doExportToFile(const ImageView2D& image, const std::string& filename); virtual bool doConvertToFile(const ImageView2D& image, Containers::StringView filename);
/** /**
* @brief Implementation for @ref exportToFile(const CompressedImageView2D&, const std::string&) * @brief Implementation for @ref convertToFile(const CompressedImageView2D&, Containers::StringView)
* @m_since_latest
* *
* If @ref ImageConverterFeature::ConvertCompressedData is supported, * If @ref ImageConverterFeature::ConvertCompressed2DToData is
* default implementation calls @ref doExportToData(const CompressedImageView2D&) * supported, default implementation calls @ref doConvertToData(const CompressedImageView2D&)
* and saves the result to given file. * and saves the result to given file.
*/ */
virtual bool doExportToFile(const CompressedImageView2D& image, const std::string& filename); virtual bool doConvertToFile(const CompressedImageView2D& image, Containers::StringView filename);
ImageConverterFlags _flags; ImageConverterFlags _flags;
}; };

1
src/Magnum/Trade/ImageData.h

@ -675,6 +675,7 @@ template<UnsignedInt dimensions> class ImageData {
the restriction is pointless when used outside of plugin the restriction is pointless when used outside of plugin
implementations. */ implementations. */
friend AbstractImporter; friend AbstractImporter;
friend AbstractImageConverter;
explicit ImageData(CompressedPixelStorage storage, UnsignedInt format, const VectorTypeFor<dimensions, Int>& size, Containers::Array<char>&& data, const void* importerState = nullptr) noexcept; explicit ImageData(CompressedPixelStorage storage, UnsignedInt format, const VectorTypeFor<dimensions, Int>& size, Containers::Array<char>&& data, const void* importerState = nullptr) noexcept;

428
src/Magnum/Trade/Test/AbstractImageConverterTest.cpp

@ -26,6 +26,8 @@
#include <sstream> #include <sstream>
#include <Corrade/Containers/Array.h> #include <Corrade/Containers/Array.h>
#include <Corrade/Containers/Optional.h> #include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/StringView.h>
#include <Corrade/Containers/StringStl.h>
#include <Corrade/TestSuite/Tester.h> #include <Corrade/TestSuite/Tester.h>
#include <Corrade/TestSuite/Compare/Container.h> #include <Corrade/TestSuite/Compare/Container.h>
#include <Corrade/TestSuite/Compare/FileToString.h> #include <Corrade/TestSuite/Compare/FileToString.h>
@ -53,37 +55,39 @@ struct AbstractImageConverterTest: TestSuite::Tester {
void thingNotSupported(); void thingNotSupported();
void exportToImage(); void convert2D();
void exportToImageNotImplemented(); void convert2DNotImplemented();
void exportToImageCustomDeleter(); void convert2DCustomDeleter();
void exportToCompressedImage(); void convertCompressed2D();
void exportToCompressedImageNotImplemented(); void convertCompressed2DNotImplemented();
void exportToCompressedImageCustomDeleter(); void convertCompressed2DCustomDeleter();
void exportToData(); void convertImageData2D();
void exportToDataNotImplemented();
void exportToDataCustomDeleter();
void exportCompressedToData(); void convert2DToData();
void exportCompressedToDataNotImplemented(); void convert2DToDataNotImplemented();
void exportCompressedToDataCustomDeleter(); void convert2DToDataCustomDeleter();
void exportImageDataToData(); void convertCompressed2DToData();
void convertCompressed2DToDataNotImplemented();
void convertCompressed2DToDataCustomDeleter();
void exportToFile(); void convertImageData2DToData();
void exportToFileThroughData();
void exportToFileThroughDataFailed();
void exportToFileThroughDataNotWritable();
void exportToFileNotImplemented();
void exportCompressedToFile(); void convert2DToFile();
void exportCompressedToFileThroughData(); void convert2DToFileThroughData();
void exportCompressedToFileThroughDataFailed(); void convert2DToFileThroughDataFailed();
void exportCompressedToFileThroughDataNotWritable(); void convert2DToFileThroughDataNotWritable();
void exportCompressedToFileNotImplemented(); void convert2DToFileNotImplemented();
void exportImageDataToFile(); void convertCompressed2DToFile();
void convertCompressed2DToFileThroughData();
void convertCompressed2DToFileThroughDataFailed();
void convertCompressed2DToFileThroughDataNotWritable();
void convertCompressed2DToFileNotImplemented();
void convertImageData2DToFile();
void debugFeature(); void debugFeature();
void debugFeatures(); void debugFeatures();
@ -100,37 +104,39 @@ AbstractImageConverterTest::AbstractImageConverterTest() {
&AbstractImageConverterTest::thingNotSupported, &AbstractImageConverterTest::thingNotSupported,
&AbstractImageConverterTest::exportToImage, &AbstractImageConverterTest::convert2D,
&AbstractImageConverterTest::exportToImageNotImplemented, &AbstractImageConverterTest::convert2DNotImplemented,
&AbstractImageConverterTest::exportToImageCustomDeleter, &AbstractImageConverterTest::convert2DCustomDeleter,
&AbstractImageConverterTest::convertCompressed2D,
&AbstractImageConverterTest::convertCompressed2DNotImplemented,
&AbstractImageConverterTest::convertCompressed2DCustomDeleter,
&AbstractImageConverterTest::exportToCompressedImage, &AbstractImageConverterTest::convertImageData2D,
&AbstractImageConverterTest::exportToCompressedImageNotImplemented,
&AbstractImageConverterTest::exportToCompressedImageCustomDeleter,
&AbstractImageConverterTest::exportToData, &AbstractImageConverterTest::convert2DToData,
&AbstractImageConverterTest::exportToDataNotImplemented, &AbstractImageConverterTest::convert2DToDataNotImplemented,
&AbstractImageConverterTest::exportToDataCustomDeleter, &AbstractImageConverterTest::convert2DToDataCustomDeleter,
&AbstractImageConverterTest::exportCompressedToData, &AbstractImageConverterTest::convertCompressed2DToData,
&AbstractImageConverterTest::exportCompressedToDataNotImplemented, &AbstractImageConverterTest::convertCompressed2DToDataNotImplemented,
&AbstractImageConverterTest::exportCompressedToDataCustomDeleter, &AbstractImageConverterTest::convertCompressed2DToDataCustomDeleter,
&AbstractImageConverterTest::exportImageDataToData, &AbstractImageConverterTest::convertImageData2DToData,
&AbstractImageConverterTest::exportToFile, &AbstractImageConverterTest::convert2DToFile,
&AbstractImageConverterTest::exportToFileThroughData, &AbstractImageConverterTest::convert2DToFileThroughData,
&AbstractImageConverterTest::exportToFileThroughDataFailed, &AbstractImageConverterTest::convert2DToFileThroughDataFailed,
&AbstractImageConverterTest::exportToFileThroughDataNotWritable, &AbstractImageConverterTest::convert2DToFileThroughDataNotWritable,
&AbstractImageConverterTest::exportToFileNotImplemented, &AbstractImageConverterTest::convert2DToFileNotImplemented,
&AbstractImageConverterTest::exportCompressedToFile, &AbstractImageConverterTest::convertCompressed2DToFile,
&AbstractImageConverterTest::exportCompressedToFileThroughData, &AbstractImageConverterTest::convertCompressed2DToFileThroughData,
&AbstractImageConverterTest::exportCompressedToFileThroughDataFailed, &AbstractImageConverterTest::convertCompressed2DToFileThroughDataFailed,
&AbstractImageConverterTest::exportCompressedToFileThroughDataNotWritable, &AbstractImageConverterTest::convertCompressed2DToFileThroughDataNotWritable,
&AbstractImageConverterTest::exportCompressedToFileNotImplemented, &AbstractImageConverterTest::convertCompressed2DToFileNotImplemented,
&AbstractImageConverterTest::exportImageDataToFile, &AbstractImageConverterTest::convertImageData2DToFile,
&AbstractImageConverterTest::debugFeature, &AbstractImageConverterTest::debugFeature,
&AbstractImageConverterTest::debugFeatures, &AbstractImageConverterTest::debugFeatures,
@ -209,241 +215,271 @@ void AbstractImageConverterTest::thingNotSupported() {
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
converter.exportToImage(ImageView2D{PixelFormat::R8Unorm, {4, 6}, Containers::ArrayView<char>{nullptr, 24}}); converter.convert(ImageView2D{PixelFormat::R8Unorm, {4, 6}, Containers::ArrayView<char>{nullptr, 24}});
converter.exportToCompressedImage(ImageView2D{PixelFormat::R8Unorm, {16, 8}, Containers::ArrayView<char>{nullptr, 128}}); converter.convert(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {16, 8}, {nullptr, 64}});
converter.exportToData(ImageView2D{PixelFormat::RGBA8Unorm, {4, 6}, Containers::ArrayView<char>{nullptr, 96}}); converter.convertToData(ImageView2D{PixelFormat::RGBA8Unorm, {4, 6}, Containers::ArrayView<char>{nullptr, 96}});
converter.exportToData(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {16, 8}, Containers::ArrayView<char>{nullptr, 64}}); converter.convertToData(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {16, 8}, Containers::ArrayView<char>{nullptr, 64}});
converter.exportToFile(ImageView2D{PixelFormat::RGBA8Unorm, {4, 6}, {nullptr, 96}}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); converter.convertToFile(ImageView2D{PixelFormat::RGBA8Unorm, {4, 6}, {nullptr, 96}}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"));
converter.exportToFile(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {16, 8}, {nullptr, 64}}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); converter.convertToFile(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {16, 8}, {nullptr, 64}}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"));
CORRADE_COMPARE(out.str(), CORRADE_COMPARE(out.str(),
"Trade::AbstractImageConverter::exportToImage(): feature not supported\n" "Trade::AbstractImageConverter::convert(): 2D image conversion not supported\n"
"Trade::AbstractImageConverter::exportToCompressedImage(): feature not supported\n" "Trade::AbstractImageConverter::convert(): compressed 2D image conversion not supported\n"
"Trade::AbstractImageConverter::exportToData(): feature not supported\n" "Trade::AbstractImageConverter::convertToData(): 2D image conversion not supported\n"
"Trade::AbstractImageConverter::exportToData(): feature not supported\n" "Trade::AbstractImageConverter::convertToData(): compressed 2D image conversion not supported\n"
"Trade::AbstractImageConverter::exportToFile(): feature not supported\n" "Trade::AbstractImageConverter::convertToFile(): 2D image conversion not supported\n"
"Trade::AbstractImageConverter::exportToFile(): feature not supported\n"); "Trade::AbstractImageConverter::convertToFile(): compressed 2D image conversion not supported\n");
} }
void AbstractImageConverterTest::exportToImage() { void AbstractImageConverterTest::convert2D() {
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertImage; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::Convert2D; }
Containers::Optional<Image2D> doExportToImage(const ImageView2D& image) override { Containers::Optional<ImageData2D> doConvert(const ImageView2D& image) override {
return Image2D{PixelFormat::RGBA8Unorm, image.size(), Containers::Array<char>{96}}; return ImageData2D{PixelFormat::RGBA8Unorm, image.size(), Containers::Array<char>{96}};
} }
} converter; } converter;
Containers::Optional<Image2D> actual = converter.exportToImage(ImageView2D{PixelFormat::R8Unorm, {4, 6}, Containers::ArrayView<char>{nullptr, 24}}); Containers::Optional<ImageData2D> actual = converter.convert(ImageView2D{PixelFormat::R8Unorm, {4, 6}, Containers::ArrayView<char>{nullptr, 24}});
CORRADE_VERIFY(actual); CORRADE_VERIFY(actual);
CORRADE_VERIFY(!actual->isCompressed());
CORRADE_COMPARE(actual->data().size(), 96); CORRADE_COMPARE(actual->data().size(), 96);
CORRADE_COMPARE(actual->size(), (Vector2i{4, 6})); CORRADE_COMPARE(actual->size(), (Vector2i{4, 6}));
} }
void AbstractImageConverterTest::exportToImageNotImplemented() { void AbstractImageConverterTest::convert2DNotImplemented() {
#ifdef CORRADE_NO_ASSERT #ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif #endif
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertImage; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::Convert2D; }
} converter; } converter;
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
converter.exportToImage(ImageView2D{PixelFormat::R8Unorm, {4, 6}, Containers::ArrayView<char>{nullptr, 128}}); converter.convert(ImageView2D{PixelFormat::R8Unorm, {4, 6}, Containers::ArrayView<char>{nullptr, 128}});
CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::exportToImage(): feature advertised but not implemented\n"); CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convert(): 2D image conversion advertised but not implemented\n");
} }
void AbstractImageConverterTest::exportToImageCustomDeleter() { void AbstractImageConverterTest::convert2DCustomDeleter() {
#ifdef CORRADE_NO_ASSERT #ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif #endif
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertImage; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::Convert2D; }
Containers::Optional<Image2D> doExportToImage(const ImageView2D&) override { Containers::Optional<ImageData2D> doConvert(const ImageView2D&) override {
return Image2D{PixelFormat::RGBA8Unorm, {}, Containers::Array<char>{nullptr, 0, [](char*, std::size_t) {}}}; return ImageData2D{PixelFormat::RGBA8Unorm, {}, Containers::Array<char>{nullptr, 0, [](char*, std::size_t) {}}};
} }
} converter; } converter;
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
converter.exportToImage(ImageView2D{PixelFormat::R8Unorm, {}}); converter.convert(ImageView2D{PixelFormat::R8Unorm, {}});
CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::exportToImage(): implementation is not allowed to use a custom Array deleter\n"); CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convert(): implementation is not allowed to use a custom Array deleter\n");
} }
void AbstractImageConverterTest::exportToCompressedImage() { void AbstractImageConverterTest::convertCompressed2D() {
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedImage; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressed2D; }
Containers::Optional<CompressedImage2D> doExportToCompressedImage(const ImageView2D& image) override { Containers::Optional<ImageData2D> doConvert(const CompressedImageView2D& image) override {
return CompressedImage2D{CompressedPixelFormat::Bc1RGBAUnorm, image.size(), Containers::Array<char>{64}}; return ImageData2D{image.format(), image.size(), Containers::Array<char>{64}};
} }
} converter; } converter;
Containers::Optional<CompressedImage2D> actual = converter.exportToCompressedImage(ImageView2D{PixelFormat::R8Unorm, {16, 8}, Containers::ArrayView<char>{nullptr, 128}}); Containers::Optional<ImageData2D> actual = converter.convert(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {16, 8}, Containers::ArrayView<char>{nullptr, 128}});
CORRADE_VERIFY(actual); CORRADE_VERIFY(actual);
CORRADE_VERIFY(actual->isCompressed());
CORRADE_COMPARE(actual->data().size(), 64); CORRADE_COMPARE(actual->data().size(), 64);
CORRADE_COMPARE(actual->size(), (Vector2i{16, 8})); CORRADE_COMPARE(actual->size(), (Vector2i{16, 8}));
} }
void AbstractImageConverterTest::exportToCompressedImageNotImplemented() { void AbstractImageConverterTest::convertCompressed2DNotImplemented() {
#ifdef CORRADE_NO_ASSERT #ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif #endif
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedImage; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressed2D; }
} converter; } converter;
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
converter.exportToCompressedImage(ImageView2D{PixelFormat::R8Unorm, {16, 8}, Containers::ArrayView<char>{nullptr, 128}}); converter.convert(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {16, 8}, Containers::ArrayView<char>{nullptr, 128}});
CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::exportToCompressedImage(): feature advertised but not implemented\n"); CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convert(): compressed 2D image conversion advertised but not implemented\n");
} }
void AbstractImageConverterTest::exportToCompressedImageCustomDeleter() { void AbstractImageConverterTest::convertCompressed2DCustomDeleter() {
#ifdef CORRADE_NO_ASSERT #ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif #endif
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedImage; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressed2D; }
Containers::Optional<CompressedImage2D> doExportToCompressedImage(const ImageView2D&) override { Containers::Optional<ImageData2D> doConvert(const CompressedImageView2D&) override {
return CompressedImage2D{CompressedPixelFormat::Bc1RGBAUnorm, {}, Containers::Array<char>{nullptr, 0, [](char*, std::size_t) {}}}; return ImageData2D{CompressedPixelFormat::Bc1RGBAUnorm, {}, Containers::Array<char>{nullptr, 0, [](char*, std::size_t) {}}};
} }
} converter; } converter;
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
converter.exportToCompressedImage(ImageView2D{PixelFormat::R8Unorm, {}}); converter.convert(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {}});
CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::exportToCompressedImage(): implementation is not allowed to use a custom Array deleter\n"); CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convert(): implementation is not allowed to use a custom Array deleter\n");
} }
void AbstractImageConverterTest::exportToData() { void AbstractImageConverterTest::convertImageData2D() {
struct: Trade::AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::Convert2D|ImageConverterFeature::ConvertCompressed2D; }
Containers::Optional<ImageData2D> doConvert(const ImageView2D&) override {
return ImageData2D{PixelFormat::R8Unorm, {}, Containers::array({'B'})};
};
Containers::Optional<ImageData2D> doConvert(const CompressedImageView2D&) override {
return ImageData2D{PixelFormat::R8Unorm, {}, Containers::array({'C'})};
};
} converter;
{
/* Should get "B" when converting uncompressed */
ImageData2D image{PixelFormat::RGBA8Unorm, {}, nullptr};
Containers::Optional<ImageData2D> out = converter.convert(image);
CORRADE_VERIFY(out);
CORRADE_COMPARE_AS(out->data(),
Containers::arrayView<char>({'B'}),
TestSuite::Compare::Container);
} {
/* Should get "C" when converting compressed */
ImageData2D image{CompressedPixelFormat::Bc1RGBUnorm, {}, nullptr};
Containers::Optional<ImageData2D> out = converter.convert(image);
CORRADE_VERIFY(out);
CORRADE_COMPARE_AS(out->data(),
Containers::arrayView<char>({'C'}),
TestSuite::Compare::Container);
}
}
void AbstractImageConverterTest::convert2DToData() {
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertData; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::Convert2DToData; }
Containers::Array<char> doExportToData(const ImageView2D& image) override { Containers::Array<char> doConvertToData(const ImageView2D& image) override {
return Containers::Array<char>{nullptr, std::size_t(image.size().product())}; return Containers::Array<char>{nullptr, std::size_t(image.size().product())};
} }
} converter; } converter;
Containers::Array<char> actual = converter.exportToData(ImageView2D{PixelFormat::RGBA8Unorm, {4, 6}, Containers::ArrayView<char>{nullptr, 96}}); Containers::Array<char> actual = converter.convertToData(ImageView2D{PixelFormat::RGBA8Unorm, {4, 6}, Containers::ArrayView<char>{nullptr, 96}});
CORRADE_COMPARE(actual.size(), 24); CORRADE_COMPARE(actual.size(), 24);
} }
void AbstractImageConverterTest::exportToDataNotImplemented() { void AbstractImageConverterTest::convert2DToDataNotImplemented() {
#ifdef CORRADE_NO_ASSERT #ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif #endif
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertData; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::Convert2DToData; }
} converter; } converter;
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
converter.exportToData(ImageView2D{PixelFormat::RGBA8Unorm, {4, 6}, Containers::ArrayView<char>{nullptr, 96}}); converter.convertToData(ImageView2D{PixelFormat::RGBA8Unorm, {4, 6}, Containers::ArrayView<char>{nullptr, 96}});
CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::exportToData(): feature advertised but not implemented\n"); CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToData(): 2D image conversion advertised but not implemented\n");
} }
void AbstractImageConverterTest::exportToDataCustomDeleter() { void AbstractImageConverterTest::convert2DToDataCustomDeleter() {
#ifdef CORRADE_NO_ASSERT #ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif #endif
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertData; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::Convert2DToData; }
Containers::Array<char> doExportToData(const ImageView2D&) override { Containers::Array<char> doConvertToData(const ImageView2D&) override {
return Containers::Array<char>{nullptr, 0, [](char*, std::size_t) {}}; return Containers::Array<char>{nullptr, 0, [](char*, std::size_t) {}};
} }
} converter; } converter;
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
converter.exportToData(ImageView2D{PixelFormat::RGBA8Unorm, {}}); converter.convertToData(ImageView2D{PixelFormat::RGBA8Unorm, {}});
CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::exportToData(): implementation is not allowed to use a custom Array deleter\n"); CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToData(): implementation is not allowed to use a custom Array deleter\n");
} }
void AbstractImageConverterTest::exportCompressedToData() { void AbstractImageConverterTest::convertCompressed2DToData() {
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedData; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressed2DToData; }
Containers::Array<char> doExportToData(const CompressedImageView2D& image) override { Containers::Array<char> doConvertToData(const CompressedImageView2D& image) override {
return Containers::Array<char>{nullptr, std::size_t(image.size().product())}; return Containers::Array<char>{nullptr, std::size_t(image.size().product())};
} }
} converter; } converter;
Containers::Array<char> actual = converter.exportToData(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {16, 8}, Containers::ArrayView<char>{nullptr, 64}}); Containers::Array<char> actual = converter.convertToData(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {16, 8}, Containers::ArrayView<char>{nullptr, 64}});
CORRADE_COMPARE(actual.size(), 128); CORRADE_COMPARE(actual.size(), 128);
} }
void AbstractImageConverterTest::exportCompressedToDataNotImplemented() { void AbstractImageConverterTest::convertCompressed2DToDataNotImplemented() {
#ifdef CORRADE_NO_ASSERT #ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif #endif
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertData; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressed2DToData; }
} converter; } converter;
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
converter.exportToData(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {16, 8}, Containers::ArrayView<char>{nullptr, 64}}); converter.convertToData(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {16, 8}, Containers::ArrayView<char>{nullptr, 64}});
CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::exportToData(): feature advertised but not implemented\n"); CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToData(): compressed 2D image conversion advertised but not implemented\n");
} }
void AbstractImageConverterTest::exportCompressedToDataCustomDeleter() { void AbstractImageConverterTest::convertCompressed2DToDataCustomDeleter() {
#ifdef CORRADE_NO_ASSERT #ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif #endif
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedData; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressed2DToData; }
Containers::Array<char> doExportToData(const CompressedImageView2D&) override { Containers::Array<char> doConvertToData(const CompressedImageView2D&) override {
return Containers::Array<char>{nullptr, 0, [](char*, std::size_t) {}}; return Containers::Array<char>{nullptr, 0, [](char*, std::size_t) {}};
} }
} converter; } converter;
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
converter.exportToData(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {}}); converter.convertToData(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {}});
CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::exportToData(): implementation is not allowed to use a custom Array deleter\n"); CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToData(): implementation is not allowed to use a custom Array deleter\n");
} }
/* Used by convertImageDataToData() and convertImageDataToFile() */ /* Used by convertImageDataToData() and convertImageDataToFile() */
class ImageDataConverter: public Trade::AbstractImageConverter { class ImageData2DConverter: public Trade::AbstractImageConverter {
private: private:
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertData|ImageConverterFeature::ConvertCompressedData; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::Convert2DToData|ImageConverterFeature::ConvertCompressed2DToData; }
Containers::Array<char> doExportToData(const ImageView2D&) override { Containers::Array<char> doConvertToData(const ImageView2D&) override {
return Containers::array({'B'}); return Containers::array({'B'});
}; };
Containers::Array<char> doExportToData(const CompressedImageView2D&) override { Containers::Array<char> doConvertToData(const CompressedImageView2D&) override {
return Containers::array({'C'}); return Containers::array({'C'});
}; };
}; };
void AbstractImageConverterTest::exportImageDataToData() { void AbstractImageConverterTest::convertImageData2DToData() {
ImageDataConverter converter; ImageData2DConverter converter;
{ /* Should get "B" when converting uncompressed */
/* Should get "B" when converting uncompressed */ CORRADE_COMPARE_AS(converter.convertToData(ImageData2D{PixelFormat::RGBA8Unorm, {}, nullptr}),
ImageData2D image{PixelFormat::RGBA8Unorm, {}, nullptr}; Containers::arrayView({'B'}),
CORRADE_COMPARE_AS(converter.exportToData(image), TestSuite::Compare::Container);
Containers::arrayView({'B'}),
TestSuite::Compare::Container); /* Should get "C" when converting compressed */
} { CORRADE_COMPARE_AS(converter.convertToData(ImageData2D{CompressedPixelFormat::Bc1RGBUnorm, {}, nullptr}),
/* Should get "C" when converting compressed */ Containers::arrayView({'C'}),
ImageData2D image{CompressedPixelFormat::Bc1RGBUnorm, {}, nullptr}; TestSuite::Compare::Container);
CORRADE_COMPARE_AS(converter.exportToData(image),
Containers::arrayView({'C'}),
TestSuite::Compare::Container);
}
} }
void AbstractImageConverterTest::exportToFile() { void AbstractImageConverterTest::convert2DToFile() {
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertData; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::Convert2DToFile; }
bool doExportToFile(const ImageView2D& image, const std::string& filename) override { bool doConvertToFile(const ImageView2D& image, Containers::StringView filename) override {
return Utility::Directory::write(filename, Containers::arrayView( return Utility::Directory::write(filename, Containers::arrayView(
{char(image.size().x()), char(image.size().y())})); {char(image.size().x()), char(image.size().y())}));
} }
@ -455,16 +491,16 @@ void AbstractImageConverterTest::exportToFile() {
Utility::Directory::rm(filename); Utility::Directory::rm(filename);
CORRADE_VERIFY(!Utility::Directory::exists(filename)); CORRADE_VERIFY(!Utility::Directory::exists(filename));
CORRADE_VERIFY(converter.exportToFile(ImageView2D{PixelFormat::RGBA8Unorm, {0xf0, 0x0d}, {nullptr, 0xf0*0x0d*4}}, filename)); CORRADE_VERIFY(converter.convertToFile(ImageView2D{PixelFormat::RGBA8Unorm, {0xf0, 0x0d}, {nullptr, 0xf0*0x0d*4}}, filename));
CORRADE_COMPARE_AS(filename, CORRADE_COMPARE_AS(filename,
"\xf0\x0d", TestSuite::Compare::FileToString); "\xf0\x0d", TestSuite::Compare::FileToString);
} }
void AbstractImageConverterTest::exportToFileThroughData() { void AbstractImageConverterTest::convert2DToFileThroughData() {
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertData; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::Convert2DToData; }
Containers::Array<char> doExportToData(const ImageView2D& image) override { Containers::Array<char> doConvertToData(const ImageView2D& image) override {
return Containers::array({char(image.size().x()), char(image.size().y())}); return Containers::array({char(image.size().x()), char(image.size().y())});
}; };
} converter; } converter;
@ -475,17 +511,17 @@ void AbstractImageConverterTest::exportToFileThroughData() {
Utility::Directory::rm(filename); Utility::Directory::rm(filename);
CORRADE_VERIFY(!Utility::Directory::exists(filename)); CORRADE_VERIFY(!Utility::Directory::exists(filename));
/* doExportToFile() should call doExportToData() */ /* doConvertToFile() should call doConvertToData() */
CORRADE_VERIFY(converter.exportToFile(ImageView2D(PixelFormat::RGBA8Unorm, {0xfe, 0xed}, {nullptr, 0xfe*0xed*4}), filename)); CORRADE_VERIFY(converter.convertToFile(ImageView2D(PixelFormat::RGBA8Unorm, {0xfe, 0xed}, {nullptr, 0xfe*0xed*4}), filename));
CORRADE_COMPARE_AS(filename, CORRADE_COMPARE_AS(filename,
"\xfe\xed", TestSuite::Compare::FileToString); "\xfe\xed", TestSuite::Compare::FileToString);
} }
void AbstractImageConverterTest::exportToFileThroughDataFailed() { void AbstractImageConverterTest::convert2DToFileThroughDataFailed() {
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertData; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::Convert2DToData; }
Containers::Array<char> doExportToData(const ImageView2D&) override { Containers::Array<char> doConvertToData(const ImageView2D&) override {
return {}; return {};
}; };
} converter; } converter;
@ -500,47 +536,47 @@ void AbstractImageConverterTest::exportToFileThroughDataFailed() {
should be printed (the base implementation assumes the plugin does it) */ should be printed (the base implementation assumes the plugin does it) */
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
CORRADE_VERIFY(!converter.exportToFile(ImageView2D(PixelFormat::RGBA8Unorm, {0xfe, 0xed}, {nullptr, 0xfe*0xed*4}), filename)); CORRADE_VERIFY(!converter.convertToFile(ImageView2D(PixelFormat::RGBA8Unorm, {0xfe, 0xed}, {nullptr, 0xfe*0xed*4}), filename));
CORRADE_VERIFY(!Utility::Directory::exists(filename)); CORRADE_VERIFY(!Utility::Directory::exists(filename));
CORRADE_COMPARE(out.str(), ""); CORRADE_COMPARE(out.str(), "");
} }
void AbstractImageConverterTest::exportToFileThroughDataNotWritable() { void AbstractImageConverterTest::convert2DToFileThroughDataNotWritable() {
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertData; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::Convert2DToData; }
Containers::Array<char> doExportToData(const ImageView2D& image) override { Containers::Array<char> doConvertToData(const ImageView2D& image) override {
return Containers::array({char(image.size().x()), char(image.size().y())}); return Containers::array({char(image.size().x()), char(image.size().y())});
}; };
} converter; } converter;
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
CORRADE_VERIFY(!converter.exportToFile(ImageView2D{PixelFormat::RGBA8Unorm, {0xfe, 0xed}, {nullptr, 0xfe*0xed*4}}, "/some/path/that/does/not/exist")); CORRADE_VERIFY(!converter.convertToFile(ImageView2D{PixelFormat::RGBA8Unorm, {0xfe, 0xed}, {nullptr, 0xfe*0xed*4}}, "/some/path/that/does/not/exist"));
CORRADE_COMPARE(out.str(), CORRADE_COMPARE(out.str(),
"Utility::Directory::write(): can't open /some/path/that/does/not/exist\n" "Utility::Directory::write(): can't open /some/path/that/does/not/exist\n"
"Trade::AbstractImageConverter::exportToFile(): cannot write to file /some/path/that/does/not/exist\n"); "Trade::AbstractImageConverter::convertToFile(): cannot write to file /some/path/that/does/not/exist\n");
} }
void AbstractImageConverterTest::exportToFileNotImplemented() { void AbstractImageConverterTest::convert2DToFileNotImplemented() {
#ifdef CORRADE_NO_ASSERT #ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif #endif
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertFile; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::Convert2DToFile; }
} converter; } converter;
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
converter.exportToFile(ImageView2D{PixelFormat::RGBA8Unorm, {4, 6}, {nullptr, 96}}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); converter.convertToFile(ImageView2D{PixelFormat::RGBA8Unorm, {4, 6}, {nullptr, 96}}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"));
CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::exportToFile(): feature advertised but not implemented\n"); CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToFile(): 2D image conversion advertised but not implemented\n");
} }
void AbstractImageConverterTest::exportCompressedToFile() { void AbstractImageConverterTest::convertCompressed2DToFile() {
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedFile; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressed2DToFile; }
bool doExportToFile(const CompressedImageView2D& image, const std::string& filename) override { bool doConvertToFile(const CompressedImageView2D& image, Containers::StringView filename) override {
return Utility::Directory::write(filename, Containers::arrayView( return Utility::Directory::write(filename, Containers::arrayView(
{char(image.size().x()), char(image.size().y())})); {char(image.size().x()), char(image.size().y())}));
} }
@ -552,16 +588,16 @@ void AbstractImageConverterTest::exportCompressedToFile() {
Utility::Directory::rm(filename); Utility::Directory::rm(filename);
CORRADE_VERIFY(!Utility::Directory::exists(filename)); CORRADE_VERIFY(!Utility::Directory::exists(filename));
CORRADE_VERIFY(converter.exportToFile(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {0xd0, 0x0d}, {nullptr, 64}}, filename)); CORRADE_VERIFY(converter.convertToFile(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {0xd0, 0x0d}, {nullptr, 64}}, filename));
CORRADE_COMPARE_AS(filename, CORRADE_COMPARE_AS(filename,
"\xd0\x0d", TestSuite::Compare::FileToString); "\xd0\x0d", TestSuite::Compare::FileToString);
} }
void AbstractImageConverterTest::exportCompressedToFileThroughData() { void AbstractImageConverterTest::convertCompressed2DToFileThroughData() {
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedData; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressed2DToData; }
Containers::Array<char> doExportToData(const CompressedImageView2D& image) override { Containers::Array<char> doConvertToData(const CompressedImageView2D& image) override {
return Containers::array({char(image.size().x()), char(image.size().y())}); return Containers::array({char(image.size().x()), char(image.size().y())});
}; };
} converter; } converter;
@ -572,17 +608,17 @@ void AbstractImageConverterTest::exportCompressedToFileThroughData() {
Utility::Directory::rm(filename); Utility::Directory::rm(filename);
CORRADE_VERIFY(!Utility::Directory::exists(filename)); CORRADE_VERIFY(!Utility::Directory::exists(filename));
/* doExportToFile() should call doExportToData() */ /* doConvertToFile() should call doConvertToData() */
CORRADE_VERIFY(converter.exportToFile(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {0xb0, 0xd9}, {nullptr, 64}}, filename)); CORRADE_VERIFY(converter.convertToFile(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {0xb0, 0xd9}, {nullptr, 64}}, filename));
CORRADE_COMPARE_AS(filename, CORRADE_COMPARE_AS(filename,
"\xb0\xd9", TestSuite::Compare::FileToString); "\xb0\xd9", TestSuite::Compare::FileToString);
} }
void AbstractImageConverterTest::exportCompressedToFileThroughDataFailed() { void AbstractImageConverterTest::convertCompressed2DToFileThroughDataFailed() {
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedData; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressed2DToData; }
Containers::Array<char> doExportToData(const CompressedImageView2D&) override { Containers::Array<char> doConvertToData(const CompressedImageView2D&) override {
return {}; return {};
}; };
} converter; } converter;
@ -597,73 +633,69 @@ void AbstractImageConverterTest::exportCompressedToFileThroughDataFailed() {
should be printed (the base implementation assumes the plugin does it) */ should be printed (the base implementation assumes the plugin does it) */
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
CORRADE_VERIFY(!converter.exportToFile(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {0xb0, 0xd9}, {nullptr, 64}}, filename)); CORRADE_VERIFY(!converter.convertToFile(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {0xb0, 0xd9}, {nullptr, 64}}, filename));
CORRADE_VERIFY(!Utility::Directory::exists(filename)); CORRADE_VERIFY(!Utility::Directory::exists(filename));
CORRADE_COMPARE(out.str(), ""); CORRADE_COMPARE(out.str(), "");
} }
void AbstractImageConverterTest::exportCompressedToFileThroughDataNotWritable() { void AbstractImageConverterTest::convertCompressed2DToFileThroughDataNotWritable() {
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedData; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressed2DToData; }
Containers::Array<char> doExportToData(const CompressedImageView2D& image) override { Containers::Array<char> doConvertToData(const CompressedImageView2D& image) override {
return Containers::array({char(image.size().x()), char(image.size().y())}); return Containers::array({char(image.size().x()), char(image.size().y())});
}; };
} converter; } converter;
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
converter.exportToFile(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {16, 8}, {nullptr, 64}}, "/some/path/that/does/not/exist"); converter.convertToFile(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {16, 8}, {nullptr, 64}}, "/some/path/that/does/not/exist");
CORRADE_COMPARE(out.str(), CORRADE_COMPARE(out.str(),
"Utility::Directory::write(): can't open /some/path/that/does/not/exist\n" "Utility::Directory::write(): can't open /some/path/that/does/not/exist\n"
"Trade::AbstractImageConverter::exportToFile(): cannot write to file /some/path/that/does/not/exist\n"); "Trade::AbstractImageConverter::convertToFile(): cannot write to file /some/path/that/does/not/exist\n");
} }
void AbstractImageConverterTest::exportCompressedToFileNotImplemented() { void AbstractImageConverterTest::convertCompressed2DToFileNotImplemented() {
#ifdef CORRADE_NO_ASSERT #ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif #endif
struct: AbstractImageConverter { struct: AbstractImageConverter {
ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressedFile; } ImageConverterFeatures doFeatures() const override { return ImageConverterFeature::ConvertCompressed2DToFile; }
} converter; } converter;
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
converter.exportToFile(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {16, 8}, {nullptr, 64}}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); converter.convertToFile(CompressedImageView2D{CompressedPixelFormat::Bc1RGBAUnorm, {16, 8}, {nullptr, 64}}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"));
CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::exportToFile(): feature advertised but not implemented\n"); CORRADE_COMPARE(out.str(), "Trade::AbstractImageConverter::convertToFile(): compressed 2D image conversion advertised but not implemented\n");
} }
void AbstractImageConverterTest::exportImageDataToFile() { void AbstractImageConverterTest::convertImageData2DToFile() {
ImageDataConverter converter; ImageData2DConverter converter;
{ /* Should get "B" when converting uncompressed */
/* Should get "B" when converting uncompressed */ CORRADE_VERIFY(converter.convertToFile(ImageData2D{PixelFormat::RGBA16F, {}, nullptr}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")));
ImageData2D image{PixelFormat::RGBA16F, {}, nullptr}; CORRADE_COMPARE_AS(Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"),
CORRADE_VERIFY(converter.exportToFile(image, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"))); "B", TestSuite::Compare::FileToString);
CORRADE_COMPARE_AS(Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"),
"B", TestSuite::Compare::FileToString); /* Should get "C" when converting compressed */
} { CORRADE_VERIFY(converter.convertToFile(ImageData2D{CompressedPixelFormat::Bc2RGBAUnorm, {}, nullptr}, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")));
/* Should get "C" when converting compressed */ CORRADE_COMPARE_AS(Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"),
ImageData2D image{CompressedPixelFormat::Bc2RGBAUnorm, {}, nullptr}; "C", TestSuite::Compare::FileToString);
CORRADE_VERIFY(converter.exportToFile(image, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")));
CORRADE_COMPARE_AS(Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"),
"C", TestSuite::Compare::FileToString);
}
} }
void AbstractImageConverterTest::debugFeature() { void AbstractImageConverterTest::debugFeature() {
std::ostringstream out; std::ostringstream out;
Debug{&out} << ImageConverterFeature::ConvertCompressedImage << ImageConverterFeature(0xf0); Debug{&out} << ImageConverterFeature::ConvertCompressed2D << ImageConverterFeature(0xdeadbeef);
CORRADE_COMPARE(out.str(), "Trade::ImageConverterFeature::ConvertCompressedImage Trade::ImageConverterFeature(0xf0)\n"); CORRADE_COMPARE(out.str(), "Trade::ImageConverterFeature::ConvertCompressed2D Trade::ImageConverterFeature(0xdeadbeef)\n");
} }
void AbstractImageConverterTest::debugFeatures() { void AbstractImageConverterTest::debugFeatures() {
std::ostringstream out; std::ostringstream out;
Debug{&out} << (ImageConverterFeature::ConvertData|ImageConverterFeature::ConvertCompressedFile) << ImageConverterFeatures{}; Debug{&out} << (ImageConverterFeature::Convert2DToData|ImageConverterFeature::ConvertCompressed2DToFile) << ImageConverterFeatures{};
CORRADE_COMPARE(out.str(), "Trade::ImageConverterFeature::ConvertData|Trade::ImageConverterFeature::ConvertCompressedFile Trade::ImageConverterFeatures{}\n"); CORRADE_COMPARE(out.str(), "Trade::ImageConverterFeature::Convert2DToData|Trade::ImageConverterFeature::ConvertCompressed2DToFile Trade::ImageConverterFeatures{}\n");
} }
void AbstractImageConverterTest::debugFlag() { void AbstractImageConverterTest::debugFlag() {

2
src/Magnum/Trade/imageconverter.cpp

@ -332,7 +332,7 @@ key=true; configuration subgroups are delimited with /.)")
Implementation::setOptions(*converter, args.value("converter-options")); Implementation::setOptions(*converter, args.value("converter-options"));
/* Save output file */ /* Save output file */
if(!converter->exportToFile(*image, output)) { if(!converter->convertToFile(*image, output)) {
Error() << "Cannot save file" << output; Error() << "Cannot save file" << output;
return 5; return 5;
} }

20
src/MagnumPlugins/AnyImageConverter/AnyImageConverter.cpp

@ -25,6 +25,8 @@
#include "AnyImageConverter.h" #include "AnyImageConverter.h"
#include <Corrade/Containers/StringView.h>
#include <Corrade/Containers/StringStl.h> /* for Directory */
#include <Corrade/PluginManager/Manager.h> #include <Corrade/PluginManager/Manager.h>
#include <Corrade/PluginManager/PluginMetadata.h> #include <Corrade/PluginManager/PluginMetadata.h>
#include <Corrade/Utility/Assert.h> #include <Corrade/Utility/Assert.h>
@ -42,10 +44,10 @@ AnyImageConverter::AnyImageConverter(PluginManager::AbstractManager& manager, co
AnyImageConverter::~AnyImageConverter() = default; AnyImageConverter::~AnyImageConverter() = default;
ImageConverterFeatures AnyImageConverter::doFeatures() const { ImageConverterFeatures AnyImageConverter::doFeatures() const {
return ImageConverterFeature::ConvertFile|ImageConverterFeature::ConvertCompressedFile; return ImageConverterFeature::Convert2DToFile|ImageConverterFeature::ConvertCompressed2DToFile;
} }
bool AnyImageConverter::doExportToFile(const ImageView2D& image, const std::string& filename) { bool AnyImageConverter::doConvertToFile(const ImageView2D& image, const Containers::StringView filename) {
CORRADE_INTERNAL_ASSERT(manager()); CORRADE_INTERNAL_ASSERT(manager());
/** @todo lowercase only the extension, once Directory::split() is done */ /** @todo lowercase only the extension, once Directory::split() is done */
@ -73,18 +75,18 @@ bool AnyImageConverter::doExportToFile(const ImageView2D& image, const std::stri
Utility::String::endsWith(normalized, ".vst")) Utility::String::endsWith(normalized, ".vst"))
plugin = "TgaImageConverter"; plugin = "TgaImageConverter";
else { else {
Error{} << "Trade::AnyImageConverter::exportToFile(): cannot determine the format of" << filename; Error{} << "Trade::AnyImageConverter::convertToFile(): cannot determine the format of" << filename;
return false; return false;
} }
/* Try to load the plugin */ /* Try to load the plugin */
if(!(manager()->load(plugin) & PluginManager::LoadState::Loaded)) { if(!(manager()->load(plugin) & PluginManager::LoadState::Loaded)) {
Error{} << "Trade::AnyImageConverter::exportToFile(): cannot load the" << plugin << "plugin"; Error{} << "Trade::AnyImageConverter::convertToFile(): cannot load the" << plugin << "plugin";
return false; return false;
} }
if(flags() & ImageConverterFlag::Verbose) { if(flags() & ImageConverterFlag::Verbose) {
Debug d; Debug d;
d << "Trade::AnyImageConverter::exportToFile(): using" << plugin; d << "Trade::AnyImageConverter::convertToFile(): using" << plugin;
PluginManager::PluginMetadata* metadata = manager()->metadata(plugin); PluginManager::PluginMetadata* metadata = manager()->metadata(plugin);
CORRADE_INTERNAL_ASSERT(metadata); CORRADE_INTERNAL_ASSERT(metadata);
if(plugin != metadata->name()) if(plugin != metadata->name())
@ -97,19 +99,19 @@ bool AnyImageConverter::doExportToFile(const ImageView2D& image, const std::stri
/* Try to convert the file (error output should be printed by the plugin /* Try to convert the file (error output should be printed by the plugin
itself) */ itself) */
return converter->exportToFile(image, filename); return converter->convertToFile(image, filename);
} }
bool AnyImageConverter::doExportToFile(const CompressedImageView2D&, const std::string& filename) { bool AnyImageConverter::doConvertToFile(const CompressedImageView2D&, const Containers::StringView filename) {
CORRADE_INTERNAL_ASSERT(manager()); CORRADE_INTERNAL_ASSERT(manager());
/* No file formats to store compressed data yet */ /* No file formats to store compressed data yet */
Error{} << "Trade::AnyImageConverter::exportToFile(): cannot determine the format of" << filename << "to store compressed data"; Error{} << "Trade::AnyImageConverter::convertToFile(): cannot determine the format of" << filename << "to store compressed data";
return false; return false;
} }
}} }}
CORRADE_PLUGIN_REGISTER(AnyImageConverter, Magnum::Trade::AnyImageConverter, CORRADE_PLUGIN_REGISTER(AnyImageConverter, Magnum::Trade::AnyImageConverter,
"cz.mosra.magnum.Trade.AbstractImageConverter/0.2.1") "cz.mosra.magnum.Trade.AbstractImageConverter/0.3")

4
src/MagnumPlugins/AnyImageConverter/AnyImageConverter.h

@ -117,8 +117,8 @@ class MAGNUM_ANYIMAGECONVERTER_EXPORT AnyImageConverter: public AbstractImageCon
private: private:
MAGNUM_ANYIMAGECONVERTER_LOCAL ImageConverterFeatures doFeatures() const override; MAGNUM_ANYIMAGECONVERTER_LOCAL ImageConverterFeatures doFeatures() const override;
MAGNUM_ANYIMAGECONVERTER_LOCAL bool doExportToFile(const ImageView2D& image, const std::string& filename) override; MAGNUM_ANYIMAGECONVERTER_LOCAL bool doConvertToFile(const ImageView2D& image, Containers::StringView filename) override;
MAGNUM_ANYIMAGECONVERTER_LOCAL bool doExportToFile(const CompressedImageView2D& image, const std::string& filename) override; MAGNUM_ANYIMAGECONVERTER_LOCAL bool doConvertToFile(const CompressedImageView2D& image, Containers::StringView filename) override;
}; };
}} }}

19
src/MagnumPlugins/AnyImageConverter/Test/AnyImageConverterTest.cpp

@ -24,6 +24,7 @@
*/ */
#include <sstream> #include <sstream>
#include <Corrade/Containers/StringStl.h>
#include <Corrade/PluginManager/Manager.h> #include <Corrade/PluginManager/Manager.h>
#include <Corrade/TestSuite/Tester.h> #include <Corrade/TestSuite/Tester.h>
#include <Corrade/Utility/Directory.h> #include <Corrade/Utility/Directory.h>
@ -121,7 +122,7 @@ void AnyImageConverterTest::convert() {
/* Just test that the exported file exists */ /* Just test that the exported file exists */
Containers::Pointer<AbstractImageConverter> converter = _manager.instantiate("AnyImageConverter"); Containers::Pointer<AbstractImageConverter> converter = _manager.instantiate("AnyImageConverter");
CORRADE_VERIFY(converter->exportToFile(Image, filename)); CORRADE_VERIFY(converter->convertToFile(Image, filename));
CORRADE_VERIFY(Utility::Directory::exists(filename)); CORRADE_VERIFY(Utility::Directory::exists(filename));
} }
@ -133,14 +134,14 @@ void AnyImageConverterTest::detect() {
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
CORRADE_VERIFY(!converter->exportToFile(Image, data.filename)); CORRADE_VERIFY(!converter->convertToFile(Image, data.filename));
/* Can't use raw string literals in macros on GCC 4.8 */ /* Can't use raw string literals in macros on GCC 4.8 */
#ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT #ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
CORRADE_COMPARE(out.str(), Utility::formatString( CORRADE_COMPARE(out.str(), Utility::formatString(
"PluginManager::Manager::load(): plugin {0} is not static and was not found in nonexistent\nTrade::AnyImageConverter::exportToFile(): cannot load the {0} plugin\n", data.plugin)); "PluginManager::Manager::load(): plugin {0} is not static and was not found in nonexistent\nTrade::AnyImageConverter::convertToFile(): cannot load the {0} plugin\n", data.plugin));
#else #else
CORRADE_COMPARE(out.str(), Utility::formatString( CORRADE_COMPARE(out.str(), Utility::formatString(
"PluginManager::Manager::load(): plugin {0} was not found\nTrade::AnyImageConverter::exportToFile(): cannot load the {0} plugin\n", data.plugin)); "PluginManager::Manager::load(): plugin {0} was not found\nTrade::AnyImageConverter::convertToFile(): cannot load the {0} plugin\n", data.plugin));
#endif #endif
} }
@ -149,9 +150,9 @@ void AnyImageConverterTest::unknown() {
Error redirectError{&output}; Error redirectError{&output};
Containers::Pointer<AbstractImageConverter> converter = _manager.instantiate("AnyImageConverter"); Containers::Pointer<AbstractImageConverter> converter = _manager.instantiate("AnyImageConverter");
CORRADE_VERIFY(!converter->exportToFile(Image, "image.xcf")); CORRADE_VERIFY(!converter->convertToFile(Image, "image.xcf"));
CORRADE_COMPARE(output.str(), "Trade::AnyImageConverter::exportToFile(): cannot determine the format of image.xcf\n"); CORRADE_COMPARE(output.str(), "Trade::AnyImageConverter::convertToFile(): cannot determine the format of image.xcf\n");
} }
void AnyImageConverterTest::verbose() { void AnyImageConverterTest::verbose() {
@ -169,12 +170,12 @@ void AnyImageConverterTest::verbose() {
std::ostringstream out; std::ostringstream out;
{ {
Debug redirectOutput{&out}; Debug redirectOutput{&out};
CORRADE_VERIFY(converter->exportToFile(Image, filename)); CORRADE_VERIFY(converter->convertToFile(Image, filename));
} }
CORRADE_VERIFY(Utility::Directory::exists(filename)); CORRADE_VERIFY(Utility::Directory::exists(filename));
CORRADE_COMPARE(out.str(), CORRADE_COMPARE(out.str(),
"Trade::AnyImageConverter::exportToFile(): using TgaImageConverter\n" "Trade::AnyImageConverter::convertToFile(): using TgaImageConverter\n"
"Trade::TgaImageConverter::exportToData(): converting from RGB to BGR\n"); "Trade::TgaImageConverter::convertToData(): converting from RGB to BGR\n");
} }
}}}} }}}}

2
src/MagnumPlugins/MagnumFontConverter/MagnumFontConverter.cpp

@ -120,7 +120,7 @@ std::vector<std::pair<std::string, Containers::Array<char>>> MagnumFontConverter
std::copy(confStr.begin(), confStr.end(), confData.begin()); std::copy(confStr.begin(), confStr.end(), confData.begin());
/* Save cache image */ /* Save cache image */
auto tgaData = Trade::TgaImageConverter().exportToData(cache.image()); auto tgaData = Trade::TgaImageConverter().convertToData(cache.image());
std::vector<std::pair<std::string, Containers::Array<char>>> out; std::vector<std::pair<std::string, Containers::Array<char>>> out;
out.emplace_back(filename + ".conf", std::move(confData)); out.emplace_back(filename + ".conf", std::move(confData));

12
src/MagnumPlugins/TgaImageConverter/Test/TgaImageConverterTest.cpp

@ -63,8 +63,8 @@ constexpr struct {
} VerboseData[] { } VerboseData[] {
{"", {}, "", ""}, {"", {}, "", ""},
{"verbose", ImageConverterFlag::Verbose, {"verbose", ImageConverterFlag::Verbose,
"Trade::TgaImageConverter::exportToData(): converting from RGB to BGR\n", "Trade::TgaImageConverter::convertToData(): converting from RGB to BGR\n",
"Trade::TgaImageConverter::exportToData(): converting from RGBA to BGRA\n"} "Trade::TgaImageConverter::convertToData(): converting from RGBA to BGRA\n"}
}; };
/* Padded to four byte alignment (the resulting file is *not* padded) */ /* Padded to four byte alignment (the resulting file is *not* padded) */
@ -118,9 +118,9 @@ void TgaImageConverterTest::wrongFormat() {
Error redirectError{&out}; Error redirectError{&out};
Containers::Pointer<AbstractImageConverter> converter = _converterManager.instantiate("TgaImageConverter"); Containers::Pointer<AbstractImageConverter> converter = _converterManager.instantiate("TgaImageConverter");
const auto data = converter->exportToData(image); const auto data = converter->convertToData(image);
CORRADE_VERIFY(!data); CORRADE_VERIFY(!data);
CORRADE_COMPARE(out.str(), "Trade::TgaImageConverter::exportToData(): unsupported pixel format PixelFormat::RG8Unorm\n"); CORRADE_COMPARE(out.str(), "Trade::TgaImageConverter::convertToData(): unsupported pixel format PixelFormat::RG8Unorm\n");
} }
void TgaImageConverterTest::rgb() { void TgaImageConverterTest::rgb() {
@ -134,7 +134,7 @@ void TgaImageConverterTest::rgb() {
Containers::Array<char> array; Containers::Array<char> array;
{ {
Debug redirectOutput{&out}; Debug redirectOutput{&out};
array = converter->exportToData(OriginalRGB); array = converter->convertToData(OriginalRGB);
} }
CORRADE_VERIFY(out); CORRADE_VERIFY(out);
@ -165,7 +165,7 @@ void TgaImageConverterTest::rgba() {
Containers::Array<char> array; Containers::Array<char> array;
{ {
Debug redirectOutput{&out}; Debug redirectOutput{&out};
array = converter->exportToData(OriginalRGBA); array = converter->convertToData(OriginalRGBA);
} }
CORRADE_VERIFY(out); CORRADE_VERIFY(out);

12
src/MagnumPlugins/TgaImageConverter/TgaImageConverter.cpp

@ -43,9 +43,9 @@ TgaImageConverter::TgaImageConverter() = default;
TgaImageConverter::TgaImageConverter(PluginManager::AbstractManager& manager, const std::string& plugin): AbstractImageConverter{manager, plugin} {} TgaImageConverter::TgaImageConverter(PluginManager::AbstractManager& manager, const std::string& plugin): AbstractImageConverter{manager, plugin} {}
ImageConverterFeatures TgaImageConverter::doFeatures() const { return ImageConverterFeature::ConvertData; } ImageConverterFeatures TgaImageConverter::doFeatures() const { return ImageConverterFeature::Convert2DToData; }
Containers::Array<char> TgaImageConverter::doExportToData(const ImageView2D& image) { Containers::Array<char> TgaImageConverter::doConvertToData(const ImageView2D& image) {
/* Initialize data buffer */ /* Initialize data buffer */
const auto pixelSize = UnsignedByte(image.pixelSize()); const auto pixelSize = UnsignedByte(image.pixelSize());
Containers::Array<char> data{Containers::ValueInit, sizeof(Implementation::TgaHeader) + pixelSize*image.size().product()}; Containers::Array<char> data{Containers::ValueInit, sizeof(Implementation::TgaHeader) + pixelSize*image.size().product()};
@ -61,7 +61,7 @@ Containers::Array<char> TgaImageConverter::doExportToData(const ImageView2D& ima
header->imageType = 3; header->imageType = 3;
break; break;
default: default:
Error() << "Trade::TgaImageConverter::exportToData(): unsupported pixel format" << image.format(); Error() << "Trade::TgaImageConverter::convertToData(): unsupported pixel format" << image.format();
return nullptr; return nullptr;
} }
header->bpp = pixelSize*8; header->bpp = pixelSize*8;
@ -75,12 +75,12 @@ Containers::Array<char> TgaImageConverter::doExportToData(const ImageView2D& ima
if(image.format() == PixelFormat::RGB8Unorm) { if(image.format() == PixelFormat::RGB8Unorm) {
if(flags() & ImageConverterFlag::Verbose) if(flags() & ImageConverterFlag::Verbose)
Debug{} << "Trade::TgaImageConverter::exportToData(): converting from RGB to BGR"; Debug{} << "Trade::TgaImageConverter::convertToData(): converting from RGB to BGR";
for(Vector3ub& pixel: Containers::arrayCast<Vector3ub>(pixels)) for(Vector3ub& pixel: Containers::arrayCast<Vector3ub>(pixels))
pixel = Math::gather<'b', 'g', 'r'>(pixel); pixel = Math::gather<'b', 'g', 'r'>(pixel);
} else if(image.format() == PixelFormat::RGBA8Unorm) { } else if(image.format() == PixelFormat::RGBA8Unorm) {
if(flags() & ImageConverterFlag::Verbose) if(flags() & ImageConverterFlag::Verbose)
Debug{} << "Trade::TgaImageConverter::exportToData(): converting from RGBA to BGRA"; Debug{} << "Trade::TgaImageConverter::convertToData(): converting from RGBA to BGRA";
for(Vector4ub& pixel: Containers::arrayCast<Vector4ub>(pixels)) for(Vector4ub& pixel: Containers::arrayCast<Vector4ub>(pixels))
pixel = Math::gather<'b', 'g', 'r', 'a'>(pixel); pixel = Math::gather<'b', 'g', 'r', 'a'>(pixel);
} }
@ -91,4 +91,4 @@ Containers::Array<char> TgaImageConverter::doExportToData(const ImageView2D& ima
}} }}
CORRADE_PLUGIN_REGISTER(TgaImageConverter, Magnum::Trade::TgaImageConverter, CORRADE_PLUGIN_REGISTER(TgaImageConverter, Magnum::Trade::TgaImageConverter,
"cz.mosra.magnum.Trade.AbstractImageConverter/0.2.1") "cz.mosra.magnum.Trade.AbstractImageConverter/0.3")

2
src/MagnumPlugins/TgaImageConverter/TgaImageConverter.h

@ -104,7 +104,7 @@ class MAGNUM_TGAIMAGECONVERTER_EXPORT TgaImageConverter: public AbstractImageCon
private: private:
ImageConverterFeatures MAGNUM_TGAIMAGECONVERTER_LOCAL doFeatures() const override; ImageConverterFeatures MAGNUM_TGAIMAGECONVERTER_LOCAL doFeatures() const override;
Containers::Array<char> MAGNUM_TGAIMAGECONVERTER_LOCAL doExportToData(const ImageView2D& image) override; Containers::Array<char> MAGNUM_TGAIMAGECONVERTER_LOCAL doConvertToData(const ImageView2D& image) override;
}; };
}} }}

Loading…
Cancel
Save