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 Corrade::Containers::Optional but has (deprecated) implicit conversion
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
changed to have input first and output second, for consistency with other
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/StridedArrayView.h>
#include <Corrade/Containers/StringView.h>
#include <Corrade/Utility/Algorithms.h>
#include "Magnum/PixelFormat.h"
@ -62,7 +63,7 @@ int main() {
{std::size_t(OutputSize.y()), std::size_t(OutputSize.x())}};
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;
}
}

1
doc/generated/easings.cpp

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

17
doc/generated/primitives.cpp

@ -26,6 +26,7 @@
#include <tuple>
#include <Corrade/Containers/ArrayViewStl.h>
#include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/StringStl.h>
#include <Corrade/PluginManager/Manager.h>
#include <Corrade/Utility/Directory.h>
@ -198,7 +199,7 @@ int PrimitiveVisualizer::exec() {
GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color);
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);
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);
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);
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);
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);
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);
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);
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/Optional.h>
#include <Corrade/Containers/StringStl.h>
#include <Corrade/PluginManager/Manager.h>
#include <Corrade/Utility/Directory.h>
@ -145,7 +146,7 @@ int ShaderVisualizer::exec() {
GL::AbstractFramebuffer::blit(multisampleFramebuffer, framebuffer, framebuffer.viewport(), GL::FramebufferBlit::Color);
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();

3
src/Magnum/DebugTools/CompareImage.cpp

@ -29,6 +29,7 @@
#include <sstream>
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/StridedArrayView.h>
#include <Corrade/Containers/StringStl.h> /* for Directory */
#include <Corrade/Containers/Optional.h>
#include <Corrade/PluginManager/Manager.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
to the output nevertheless). */
Containers::Pointer<Trade::AbstractImageConverter> converter = _state->converterManager().loadAndInstantiate("AnyImageConverter");
if(converter && converter->exportToFile(image, filename))
if(converter && converter->convertToFile(image, filename))
out << "->" << filename;
}

3
src/Magnum/DebugTools/Screenshot.cpp

@ -26,6 +26,7 @@
#include "Screenshot.h"
#include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/StringStl.h>
#include <Corrade/PluginManager/Manager.h>
#include <Corrade/Utility/DebugStl.h>
@ -78,7 +79,7 @@ bool screenshot(PluginManager::Manager<Trade::AbstractImageConverter>& manager,
return false;
Image2D image = framebuffer.read(framebuffer.viewport(), {format});
if(!converter->exportToFile(image, filename))
if(!converter->convertToFile(image, filename))
return false;
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();
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 {
#ifndef DOXYGEN_GENERATING_OUTPUT
/** @todo remove once AbstractImageConverter returns ImageData instead */
namespace Trade { class AbstractImageConverter; }
#endif
/**
@brief Image
@ -471,14 +466,6 @@ template<UnsignedInt dimensions> class Image {
Containers::Array<char> release();
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;
PixelFormat _format;
UnsignedInt _formatExtra;
@ -702,14 +689,6 @@ template<UnsignedInt dimensions> class CompressedImage {
Containers::Array<char> release();
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
together with the image */
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 */
Image2D result{PixelFormat::R8Unorm};
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");
return 5;
}

194
src/Magnum/Trade/AbstractImageConverter.cpp

@ -28,6 +28,8 @@
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/EnumSet.hpp>
#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/Directory.h>
#include <Corrade/Utility/DebugStl.h>
@ -45,7 +47,7 @@ namespace Magnum { namespace Trade {
std::string AbstractImageConverter::pluginInterface() {
return
/* [interface] */
"cz.mosra.magnum.Trade.AbstractImageConverter/0.2.1"
"cz.mosra.magnum.Trade.AbstractImageConverter/0.3"
/* [interface] */
;
}
@ -93,109 +95,181 @@ void AbstractImageConverter::clearFlags(ImageConverterFlags flags) {
setFlags(_flags & ~flags);
}
Containers::Optional<Image2D> AbstractImageConverter::exportToImage(const ImageView2D& image) {
CORRADE_ASSERT(features() & ImageConverterFeature::ConvertImage,
"Trade::AbstractImageConverter::exportToImage(): feature not supported", {});
Containers::Optional<ImageData2D> AbstractImageConverter::convert(const ImageView2D& image) {
CORRADE_ASSERT(features() & ImageConverterFeature::Convert2D,
"Trade::AbstractImageConverter::convert(): 2D image conversion not supported", {});
Containers::Optional<Image2D> out = doExportToImage(image);
CORRADE_ASSERT(!out || !out->_data.deleter(), "Trade::AbstractImageConverter::exportToImage(): implementation is not allowed to use a custom Array deleter", {});
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;
}
Containers::Optional<Image2D> AbstractImageConverter::doExportToImage(const ImageView2D&) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::exportToImage(): feature advertised but not implemented", {});
Containers::Optional<ImageData2D> AbstractImageConverter::doConvert(const ImageView2D&) {
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) {
CORRADE_ASSERT(features() & ImageConverterFeature::ConvertCompressedImage,
"Trade::AbstractImageConverter::exportToCompressedImage(): feature not supported", {});
Containers::Optional<ImageData2D> out = convert(image);
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);
CORRADE_ASSERT(!out || !out->_data.deleter(), "Trade::AbstractImageConverter::exportToCompressedImage(): implementation is not allowed to use a custom Array deleter", {});
Containers::Optional<ImageData2D> AbstractImageConverter::convert(const CompressedImageView2D& image) {
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;
}
Containers::Optional<CompressedImage2D> AbstractImageConverter::doExportToCompressedImage(const ImageView2D&) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::exportToCompressedImage(): feature advertised but not implemented", {});
Containers::Optional<ImageData2D> AbstractImageConverter::doConvert(const CompressedImageView2D&) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::convert(): compressed 2D image conversion advertised but not implemented", {});
}
Containers::Array<char> AbstractImageConverter::exportToData(const ImageView2D& image) {
CORRADE_ASSERT(features() & ImageConverterFeature::ConvertData,
"Trade::AbstractImageConverter::exportToData(): feature not supported", nullptr);
Containers::Optional<ImageData2D> AbstractImageConverter::convert(const ImageData2D& image) {
return image.isCompressed() ? convert(CompressedImageView2D(image)) : convert(ImageView2D(image));
}
Containers::Array<char> out = doExportToData(image);
CORRADE_ASSERT(!out.deleter(), "Trade::AbstractImageConverter::exportToData(): implementation is not allowed to use a custom Array deleter", {});
Containers::Array<char> AbstractImageConverter::convertToData(const ImageView2D& image) {
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;
}
Containers::Array<char> AbstractImageConverter::doExportToData(const ImageView2D&) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::exportToData(): feature advertised but not implemented", nullptr);
Containers::Array<char> AbstractImageConverter::doConvertToData(const ImageView2D&) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::convertToData(): 2D image conversion advertised but not implemented", nullptr);
}
Containers::Array<char> AbstractImageConverter::exportToData(const CompressedImageView2D& image) {
CORRADE_ASSERT(features() & ImageConverterFeature::ConvertCompressedData,
"Trade::AbstractImageConverter::exportToData(): feature not supported", nullptr);
#ifdef MAGNUM_BUILD_DEPRECATED
Containers::Array<char> AbstractImageConverter::exportToData(const ImageView2D& image) {
return convertToData(image);
}
#endif
Containers::Array<char> out = doExportToData(image);
CORRADE_ASSERT(!out.deleter(), "Trade::AbstractImageConverter::exportToData(): implementation is not allowed to use a custom Array deleter", {});
Containers::Array<char> AbstractImageConverter::convertToData(const CompressedImageView2D& image) {
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;
}
Containers::Array<char> AbstractImageConverter::doExportToData(const CompressedImageView2D&) {
CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImageConverter::exportToData(): feature advertised but not implemented", nullptr);
Containers::Array<char> AbstractImageConverter::doConvertToData(const CompressedImageView2D&) {
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) {
return image.isCompressed() ? exportToData(CompressedImageView2D(image)) : exportToData(ImageView2D(image));
return convertToData(image);
}
#endif
bool AbstractImageConverter::exportToFile(const ImageView2D& image, const std::string& filename) {
CORRADE_ASSERT(features() & ImageConverterFeature::ConvertFile,
"Trade::AbstractImageConverter::exportToFile(): feature not supported", {});
bool AbstractImageConverter::convertToFile(const ImageView2D& image, const Containers::StringView filename) {
CORRADE_ASSERT(features() & ImageConverterFeature::Convert2DToFile,
"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) {
CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertData, "Trade::AbstractImageConverter::exportToFile(): feature advertised but not implemented", false);
bool AbstractImageConverter::doConvertToFile(const ImageView2D& image, const Containers::StringView filename) {
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 */
if(!data) return false;
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 true;
}
bool AbstractImageConverter::exportToFile(const CompressedImageView2D& image, const std::string& filename) {
CORRADE_ASSERT(features() & ImageConverterFeature::ConvertCompressedFile,
"Trade::AbstractImageConverter::exportToFile(): feature not supported", {});
#ifdef MAGNUM_BUILD_DEPRECATED
bool AbstractImageConverter::exportToFile(const ImageView2D& image, const std::string& filename) {
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) {
CORRADE_ASSERT(features() >= ImageConverterFeature::ConvertCompressedData, "Trade::AbstractImageConverter::exportToFile(): feature advertised but not implemented", false);
bool AbstractImageConverter::doConvertToFile(const CompressedImageView2D& image, Containers::StringView filename) {
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 */
if(!data) return false;
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 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) {
return image.isCompressed() ? exportToFile(CompressedImageView2D(image), filename) : exportToFile(ImageView2D(image), filename);
return convertToFile(image, filename);
}
#endif
Debug& operator<<(Debug& debug, const ImageConverterFeature value) {
debug << "Trade::ImageConverterFeature" << Debug::nospace;
@ -203,28 +277,28 @@ Debug& operator<<(Debug& debug, const ImageConverterFeature value) {
switch(value) {
/* LCOV_EXCL_START */
#define _c(v) case ImageConverterFeature::v: return debug << "::" #v;
_c(ConvertImage)
_c(ConvertCompressedImage)
_c(ConvertFile)
_c(ConvertCompressedFile)
_c(ConvertData)
_c(ConvertCompressedData)
_c(Convert2D)
_c(ConvertCompressed2D)
_c(Convert2DToFile)
_c(ConvertCompressed2DToFile)
_c(Convert2DToData)
_c(ConvertCompressed2DToData)
#undef _c
/* 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) {
return Containers::enumSetDebugOutput(debug, value, "Trade::ImageConverterFeatures{}", {
ImageConverterFeature::ConvertImage,
ImageConverterFeature::ConvertCompressedImage,
ImageConverterFeature::ConvertData,
ImageConverterFeature::ConvertCompressedData,
/* These are implied by Convert[Compressed]Data, so have to be last */
ImageConverterFeature::ConvertFile,
ImageConverterFeature::ConvertCompressedFile});
ImageConverterFeature::Convert2D,
ImageConverterFeature::ConvertCompressed2D,
ImageConverterFeature::Convert2DToData,
ImageConverterFeature::ConvertCompressed2DToData,
/* These are implied by Convert[Compressed]ToData, so have to be last */
ImageConverterFeature::Convert2DToFile,
ImageConverterFeature::ConvertCompressed2DToFile});
}
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()
*/
enum class ImageConverterFeature: UnsignedByte {
enum class ImageConverterFeature: UnsignedInt {
/**
* Conversion to image with different format with
* @ref AbstractImageConverter::exportToImage()
* Convert a 2D image with
* @ref AbstractImageConverter::convert(const ImageView2D&)
* @m_since_latest
*/
ConvertImage = 1 << 0,
Convert2D = 1 << 0,
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* Conversion to compressed image with
* @ref AbstractImageConverter::exportToCompressedImage()
* @copydoc ImageConverterFeature::Convert2D
* @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
* @ref AbstractImageConverter::exportToFile(const ImageView2D&, const std::string&)
* @copydoc ImageConverterFeature::Convert2D
* @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
* @ref AbstractImageConverter::exportToFile(const CompressedImageView2D&, const std::string&)
* Convert a compressed 2D image with
* @ref AbstractImageConverter::convert(const CompressedImageView2D&)
* @m_since_latest
*/
ConvertCompressedFile = 1 << 3,
ConvertCompressed2D = 1 << 1,
/**
* Exporting to raw data with
* @ref AbstractImageConverter::exportToData(const ImageView2D&).
* Implies @ref ImageConverterFeature::ConvertFile.
* Convert a 2D image to a file with
* @ref AbstractImageConverter::convertToFile(const ImageView2D&, Containers::StringView)
* @m_since_latest
*/
ConvertData = ConvertFile|(1 << 4),
Convert2DToFile = 1 << 2,
#ifdef MAGNUM_BUILD_DEPRECATED
/**
* Exporting compressed image to raw data with
* @ref AbstractImageConverter::exportToData(const CompressedImageView2D&).
* Implies @ref ImageConverterFeature::ConvertCompressedFile.
* @copydoc ImageConverterFeature::Convert2DToFile
* @m_deprecated_since_latest Use
* @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
The plugin needs to implement the @ref doFeatures() function and one or more of
@ref doExportToImage(), @ref doExportToCompressedImage(), @ref doExportToData()
or @ref doExportToFile() functions based on what features are supported.
@ref doConvert(), @ref doConvertToData() or @ref doConvertToFile() functions
based on what features are supported.
You don't need to do most of the redundant sanity checks, these things are
checked by the implementation:
- The function @ref doExportToImage() is called only if
@ref ImageConverterFeature::ConvertImage is supported.
- The function @ref doExportToCompressedImage() is called only if
@ref ImageConverterFeature::ConvertCompressedImage is supported.
- The function @ref doExportToData(const ImageView2D&) is called only if
@ref ImageConverterFeature::ConvertData is supported.
- The function @ref doExportToData(const CompressedImageView2D&) is called
only if @ref ImageConverterFeature::ConvertCompressedData is supported.
- The function @ref doExportToFile(const ImageView2D&, const std::string&) is
called only if @ref ImageConverterFeature::ConvertFile is supported.
- The function @ref doExportToFile(const CompressedImageView2D&, const std::string&)
is called only if @ref ImageConverterFeature::ConvertCompressedFile is
- The function @ref doConvert(const ImageView2D&) is called only if
@ref ImageConverterFeature::Convert2D is supported.
- The function @ref doConvert(const CompressedImageView2D&) is called only if
@ref ImageConverterFeature::ConvertCompressed2D is supported.
- The function @ref doConvertToData(const ImageView2D&) is called only if
@ref ImageConverterFeature::Convert2DToData is supported.
- The function @ref doConvertToData(const CompressedImageView2D&) is called
only if @ref ImageConverterFeature::ConvertCompressed2DToData is supported.
- The function @ref doConvertToFile(const ImageView2D&, Containers::StringView)
is called only if @ref ImageConverterFeature::Convert2DToFile is supported.
- The function @ref doConvertToFile(const CompressedImageView2D&, Containers::StringView)
is called only if @ref ImageConverterFeature::ConvertCompressed2DToFile is
supported.
@m_class{m-block m-warning}
@ -292,86 +354,194 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract
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,
* @ref Containers::NullOpt otherwise.
* @see @ref features(), @ref exportToData(), @ref exportToFile()
* @ref Containers::NullOpt otherwise. The implementation is allowed to
* 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
* is supported. Returns converted image on success,
* @ref Containers::NullOpt otherwise.
* @see @ref features(), @ref exportToData(), @ref exportToFile()
* Available only if @ref ImageConverterFeature::ConvertCompressed2D is
* supported. Returns converted image on success,
* @ref Containers::NullOpt otherwise. The implementation is allowed to
* 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
* supported. Returns data on success, zero-sized array otherwise.
* @see @ref features(), @ref exportToImage(),
* @ref exportToFile(const ImageView2D&, const std::string&)
* Based on whether the image is compressed or not, calls either
* @ref convert(const ImageView2D&) or
* @ref convert(const CompressedImageView2D&). See documentation of
* 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
* is supported. Returns data on success, zero-sized array otherwise.
* @see @ref features(), @ref exportToCompressedImage(),
* @ref exportToFile(const CompressedImageView2D&, const std::string&)
* Available only if @ref ImageConverterFeature::Convert2DToData is
* supported. Returns data on success, @cpp nullptr @ce otherwise.
* @see @ref features(), @ref convertToData(const CompressedImageView2D&),
* @ref convertToData(const ImageData2D&), @ref convert(),
* @ref convertToFile()
*/
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
* @ref exportToData(const ImageView2D&) or
* @ref exportToData(const CompressedImageView2D&). See documentation
* of those two functions for details.
* @ref convertToData(const ImageView2D&) or
* @ref convertToData(const CompressedImageView2D&). See documentation
* 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
* @ref ImageConverterFeature::ConvertData is supported. Returns
* Available only if @ref ImageConverterFeature::Convert2DToFile or
* @ref ImageConverterFeature::Convert2DToData is supported. Returns
* @cpp true @ce on success, @cpp false @ce otherwise.
* @see @ref features(), @ref exportToImage(),
* @ref exportToData(const ImageView2D&)
* @see @ref features(), @ref convertToFile(const CompressedImageView2D&, Containers::StringView),
* @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
* or @ref ImageConverterFeature::ConvertCompressedData is supported.
* Returns @cpp true @ce on success, @cpp false @ce otherwise.
* @see @ref features(), @ref exportToCompressedImage(),
* @ref exportToData(const CompressedImageView2D&)
* Available only if @ref ImageConverterFeature::ConvertCompressed2DToFile
* or @ref ImageConverterFeature::ConvertCompressed2DToData is
* supported. Returns @cpp true @ce on success, @cpp false @ce
* otherwise.
* @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
* @ref exportToFile(const ImageView2D&, const std::string&) or
* @ref exportToFile(const CompressedImageView2D&, const std::string&).
* See documentation of those two functions for details.
* @ref convertToFile(const ImageView2D&, Containers::StringView) or
* @ref convertToFile(const CompressedImageView2D&, Containers::StringView).
* 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:
/** @brief Implementation for @ref features() */
@ -392,35 +562,49 @@ class MAGNUM_TRADE_EXPORT AbstractImageConverter: public PluginManager::Abstract
*/
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
* implementation calls @ref doExportToData(const ImageView2D&) and
* If @ref ImageConverterFeature::Convert2DToData is supported, default
* implementation calls @ref doConvertToData(const ImageView2D&) and
* 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,
* default implementation calls @ref doExportToData(const CompressedImageView2D&)
* If @ref ImageConverterFeature::ConvertCompressed2DToData is
* supported, default implementation calls @ref doConvertToData(const CompressedImageView2D&)
* 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;
};

1
src/Magnum/Trade/ImageData.h

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

20
src/MagnumPlugins/AnyImageConverter/AnyImageConverter.cpp

@ -25,6 +25,8 @@
#include "AnyImageConverter.h"
#include <Corrade/Containers/StringView.h>
#include <Corrade/Containers/StringStl.h> /* for Directory */
#include <Corrade/PluginManager/Manager.h>
#include <Corrade/PluginManager/PluginMetadata.h>
#include <Corrade/Utility/Assert.h>
@ -42,10 +44,10 @@ AnyImageConverter::AnyImageConverter(PluginManager::AbstractManager& manager, co
AnyImageConverter::~AnyImageConverter() = default;
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());
/** @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"))
plugin = "TgaImageConverter";
else {
Error{} << "Trade::AnyImageConverter::exportToFile(): cannot determine the format of" << filename;
Error{} << "Trade::AnyImageConverter::convertToFile(): cannot determine the format of" << filename;
return false;
}
/* Try to load the plugin */
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;
}
if(flags() & ImageConverterFlag::Verbose) {
Debug d;
d << "Trade::AnyImageConverter::exportToFile(): using" << plugin;
d << "Trade::AnyImageConverter::convertToFile(): using" << plugin;
PluginManager::PluginMetadata* metadata = manager()->metadata(plugin);
CORRADE_INTERNAL_ASSERT(metadata);
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
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());
/* 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;
}
}}
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:
MAGNUM_ANYIMAGECONVERTER_LOCAL ImageConverterFeatures doFeatures() const override;
MAGNUM_ANYIMAGECONVERTER_LOCAL bool doExportToFile(const ImageView2D& image, const std::string& filename) override;
MAGNUM_ANYIMAGECONVERTER_LOCAL bool doExportToFile(const CompressedImageView2D& image, const std::string& filename) override;
MAGNUM_ANYIMAGECONVERTER_LOCAL bool doConvertToFile(const ImageView2D& image, Containers::StringView 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 <Corrade/Containers/StringStl.h>
#include <Corrade/PluginManager/Manager.h>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/Utility/Directory.h>
@ -121,7 +122,7 @@ void AnyImageConverterTest::convert() {
/* Just test that the exported file exists */
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));
}
@ -133,14 +134,14 @@ void AnyImageConverterTest::detect() {
std::ostringstream 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 */
#ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
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
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
}
@ -149,9 +150,9 @@ void AnyImageConverterTest::unknown() {
Error redirectError{&output};
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() {
@ -169,12 +170,12 @@ void AnyImageConverterTest::verbose() {
std::ostringstream out;
{
Debug redirectOutput{&out};
CORRADE_VERIFY(converter->exportToFile(Image, filename));
CORRADE_VERIFY(converter->convertToFile(Image, filename));
}
CORRADE_VERIFY(Utility::Directory::exists(filename));
CORRADE_COMPARE(out.str(),
"Trade::AnyImageConverter::exportToFile(): using TgaImageConverter\n"
"Trade::TgaImageConverter::exportToData(): converting from RGB to BGR\n");
"Trade::AnyImageConverter::convertToFile(): using TgaImageConverter\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());
/* 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;
out.emplace_back(filename + ".conf", std::move(confData));

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

@ -63,8 +63,8 @@ constexpr struct {
} VerboseData[] {
{"", {}, "", ""},
{"verbose", ImageConverterFlag::Verbose,
"Trade::TgaImageConverter::exportToData(): converting from RGB to BGR\n",
"Trade::TgaImageConverter::exportToData(): converting from RGBA to BGRA\n"}
"Trade::TgaImageConverter::convertToData(): converting from RGB to BGR\n",
"Trade::TgaImageConverter::convertToData(): converting from RGBA to BGRA\n"}
};
/* Padded to four byte alignment (the resulting file is *not* padded) */
@ -118,9 +118,9 @@ void TgaImageConverterTest::wrongFormat() {
Error redirectError{&out};
Containers::Pointer<AbstractImageConverter> converter = _converterManager.instantiate("TgaImageConverter");
const auto data = converter->exportToData(image);
const auto data = converter->convertToData(image);
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() {
@ -134,7 +134,7 @@ void TgaImageConverterTest::rgb() {
Containers::Array<char> array;
{
Debug redirectOutput{&out};
array = converter->exportToData(OriginalRGB);
array = converter->convertToData(OriginalRGB);
}
CORRADE_VERIFY(out);
@ -165,7 +165,7 @@ void TgaImageConverterTest::rgba() {
Containers::Array<char> array;
{
Debug redirectOutput{&out};
array = converter->exportToData(OriginalRGBA);
array = converter->convertToData(OriginalRGBA);
}
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} {}
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 */
const auto pixelSize = UnsignedByte(image.pixelSize());
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;
break;
default:
Error() << "Trade::TgaImageConverter::exportToData(): unsupported pixel format" << image.format();
Error() << "Trade::TgaImageConverter::convertToData(): unsupported pixel format" << image.format();
return nullptr;
}
header->bpp = pixelSize*8;
@ -75,12 +75,12 @@ Containers::Array<char> TgaImageConverter::doExportToData(const ImageView2D& ima
if(image.format() == PixelFormat::RGB8Unorm) {
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))
pixel = Math::gather<'b', 'g', 'r'>(pixel);
} else if(image.format() == PixelFormat::RGBA8Unorm) {
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))
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,
"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:
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