diff --git a/src/Trade/AbstractImageConverter.cpp b/src/Trade/AbstractImageConverter.cpp index 2a06d5b63..d0a465f68 100644 --- a/src/Trade/AbstractImageConverter.cpp +++ b/src/Trade/AbstractImageConverter.cpp @@ -24,6 +24,7 @@ #include "AbstractImageConverter.h" +#include #include #include @@ -33,25 +34,48 @@ AbstractImageConverter::AbstractImageConverter() = default; AbstractImageConverter::AbstractImageConverter(PluginManager::AbstractManager* manager, std::string plugin): AbstractPlugin(manager, std::move(plugin)) {} -Image2D* AbstractImageConverter::convertToImage(const Image2D* const) const { - CORRADE_ASSERT(features() & Feature::ConvertToImage, - "Trade::AbstractImageConverter::convertToImage(): feature advertised but not implemented", nullptr); +Image2D* AbstractImageConverter::exportToImage(const Image2D* const image) const { + CORRADE_ASSERT(features() & Feature::ConvertImage, + "Trade::AbstractImageConverter::exportToImage(): feature not supported", nullptr); - CORRADE_ASSERT(false, "Trade::AbstractImageConverter::convertToImage(): feature not implemented", nullptr); + return doExportToImage(image); } -Containers::Array AbstractImageConverter::convertToData(const Image2D* const) const { - CORRADE_ASSERT(features() & Feature::ConvertToData, - "Trade::AbstractImageConverter::convertToData(): feature advertised but not implemented", {}); +Image2D* AbstractImageConverter::doExportToImage(const Image2D*) const { + CORRADE_ASSERT(false, "Trade::AbstractImageConverter::exportToImage(): feature advertised but not implemented", nullptr); +} + +Containers::Array AbstractImageConverter::exportToData(const Image2D* const image) const { + CORRADE_ASSERT(features() & Feature::ConvertData, + "Trade::AbstractImageConverter::exportToData(): feature not supported", nullptr); + + return doExportToData(image); +} - CORRADE_ASSERT(false, "Trade::AbstractImageConverter::convertToData(): feature not implemented", {}); +Containers::Array AbstractImageConverter::doExportToData(const Image2D*) const { + CORRADE_ASSERT(false, "Trade::AbstractImageConverter::exportToData(): feature advertised but not implemented", nullptr); } -bool AbstractImageConverter::convertToFile(const Image2D* const, const std::string&) const { - CORRADE_ASSERT(features() & Feature::ConvertToFile, - "Trade::AbstractImageConverter::convertToFile(): feature advertised but not implemented", false); +bool AbstractImageConverter::exportToFile(const Image2D* const image, const std::string& filename) const { + return doExportToFile(image, filename); +} + +bool AbstractImageConverter::doExportToFile(const Image2D* const image, const std::string& filename) const { + CORRADE_ASSERT(features() & Feature::ConvertData, "Trade::AbstractImageConverter::exportToFile(): not implemented", nullptr); + + auto data = doExportToData(image); + if(!data) return false; + + /* Open file */ + std::ofstream out(filename.data(), std::ios::binary); + if(!out.good()) { + Error() << "Trade::AbstractImageConverter::exportToFile(): cannot write to file" << filename; + return false; + } - CORRADE_ASSERT(false, "Trade::AbstractImageConverter::convertToFile(): feature not implemented", false); + /* Write data, close */ + out.write(reinterpret_cast(data.begin()), data.size()); + return true; } }} diff --git a/src/Trade/AbstractImageConverter.h b/src/Trade/AbstractImageConverter.h index 8cc609eff..126964286 100644 --- a/src/Trade/AbstractImageConverter.h +++ b/src/Trade/AbstractImageConverter.h @@ -44,12 +44,19 @@ or compressing them. @section AbstractImageConverter-subclassing Subclassing -Plugin implements function features() and one or more of convertToImage(), -convertToData() or convertToFile() functions based on what features are +Plugin implements function doFeatures() and one or more of doExportToImage(), +doExportToData() or doExportToFile() 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: + +- Functions doExportToImage() or doExportToData() are called only if + @ref Feature "Feature::ConvertImage" or @ref Feature "Feature::ConvertData" + is supported. */ class MAGNUM_EXPORT AbstractImageConverter: public PluginManager::AbstractPlugin { - CORRADE_PLUGIN_INTERFACE("cz.mosra.magnum.Trade.AbstractImageConverter/0.1") + CORRADE_PLUGIN_INTERFACE("cz.mosra.magnum.Trade.AbstractImageConverter/0.2") public: /** @@ -58,14 +65,11 @@ class MAGNUM_EXPORT AbstractImageConverter: public PluginManager::AbstractPlugin * @see Features, features() */ enum class Feature: UnsignedByte { - /** Converting to image with different format with convertToImage() */ - ConvertToImage = 1 << 0, - - /** Converting to data with convertToData() */ - ConvertToData = 1 << 1, + /** Conversion to image with different format with exportToImage() */ + ConvertImage = 1 << 0, - /** Converting to file with convertToFile() */ - ConvertToFile = 1 << 2 + /** Exporting to raw data with exportToData() */ + ConvertData = 1 << 1 }; /** @@ -82,34 +86,56 @@ class MAGNUM_EXPORT AbstractImageConverter: public PluginManager::AbstractPlugin explicit AbstractImageConverter(PluginManager::AbstractManager* manager, std::string plugin); /** @brief Features supported by this converter */ - virtual Features features() const = 0; + Features features() const { return doFeatures(); } /** * @brief Convert image to different format * - * Available only if @ref Feature "Feature::ConvertToImage" is supported. + * Available only if @ref Feature "Feature::ConvertImage" is supported. * Returns converted image on success, `nullptr` otherwise. - * @see features(), convertToData(), convertToFile() + * @see features(), exportToData(), exportToFile() */ - virtual Image2D* convertToImage(const Image2D* image) const; + Image2D* exportToImage(const Image2D* image) const; /** - * @brief Convert image to raw data + * @brief Export image to raw data * - * Available only if @ref Feature "Feature::ConvertToData" is supported. - * Returns data pointer and size on success, `nullptr` otherwise. - * @see features(), convertToImage(), convertToFile() + * Available only if @ref Feature "Feature::ConvertData" is supported. + * Returns data on success, zero-sized array otherwise. + * @see features(), exportToImage(), exportToFile() */ - virtual Containers::Array convertToData(const Image2D* image) const; + Containers::Array exportToData(const Image2D* image) const; /** - * @brief Convert image and save it to file + * @brief Export image to file * - * Available only if @ref Feature "Feature::ConvertToFile" is supported. * Returns `true` on success, `false` otherwise. - * @see features(), convertToImage(), convertToData() + * @see features(), exportToImage(), exportToData() + */ + bool exportToFile(const Image2D* image, const std::string& filename) const; + + #ifndef DOXYGEN_GENERATING_OUTPUT + private: + #else + protected: + #endif + /** @brief Implementation of features() */ + virtual Features doFeatures() const = 0; + + /** @brief Implementation of exportToImage() */ + virtual Image2D* doExportToImage(const Image2D* image) const; + + /** @brief Implementation of exportToData() */ + virtual Containers::Array doExportToData(const Image2D* image) const; + + /** + * @brief Implementation of exportToFile() + * + * If @ref Feature "Feature::ConvertData" is supported, default + * implementation calls doExportToData() and saves the result to given + * file. */ - virtual bool convertToFile(const Image2D* image, const std::string& filename) const; + virtual bool doExportToFile(const Image2D* image, const std::string& filename) const; }; CORRADE_ENUMSET_OPERATORS(AbstractImageConverter::Features) diff --git a/src/Trade/Test/AbstractImageConverterTest.cpp b/src/Trade/Test/AbstractImageConverterTest.cpp new file mode 100644 index 000000000..3d209ea79 --- /dev/null +++ b/src/Trade/Test/AbstractImageConverterTest.cpp @@ -0,0 +1,75 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include + +#include "Image.h" +#include "ImageFormat.h" +#include "Trade/AbstractImageConverter.h" + +#include "testConfigure.h" + +namespace Magnum { namespace Trade { namespace Test { + +class AbstractImageConverterTest: public TestSuite::Tester { + public: + explicit AbstractImageConverterTest(); + + void exportToFile(); +}; + +AbstractImageConverterTest::AbstractImageConverterTest() { + addTests({&AbstractImageConverterTest::exportToFile}); +} + +void AbstractImageConverterTest::exportToFile() { + class DataExporter: public Trade::AbstractImageConverter { + private: + Features doFeatures() const override { return Feature::ConvertData; } + + Containers::Array doExportToData(const Image2D* image) const override { + Containers::Array out(2); + out[0] = image->size().x(); + out[1] = image->size().y(); + return out; + }; + }; + + /* Remove previous file */ + Utility::Directory::rm(Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out")); + + /* doExportToFile() should call doExportToData() */ + DataExporter exporter; + Image2D image({0xfe, 0xed}, ImageFormat::RGBA, ImageType::UnsignedByte, nullptr); + CORRADE_VERIFY(exporter.exportToFile(&image, Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"))); + CORRADE_COMPARE_AS(Utility::Directory::join(TRADE_TEST_OUTPUT_DIR, "image.out"), + "\xFE\xED", TestSuite::Compare::FileToString); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Trade::Test::AbstractImageConverterTest) diff --git a/src/Trade/Test/CMakeLists.txt b/src/Trade/Test/CMakeLists.txt index 7d9c878e0..a3c163349 100644 --- a/src/Trade/Test/CMakeLists.txt +++ b/src/Trade/Test/CMakeLists.txt @@ -27,6 +27,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/testConfigure.h.cmake include_directories(${CMAKE_CURRENT_BINARY_DIR}) +corrade_add_test(TradeAbstractImageConverterTest AbstractImageConverterTest.cpp LIBRARIES Magnum) corrade_add_test(TradeAbstractImporterTest AbstractImporterTest.cpp LIBRARIES Magnum) corrade_add_test(TradeObjectData2DTest ObjectData2DTest.cpp LIBRARIES Magnum) corrade_add_test(TradeObjectData3DTest ObjectData3DTest.cpp LIBRARIES Magnum) diff --git a/src/Trade/Test/testConfigure.h.cmake b/src/Trade/Test/testConfigure.h.cmake index 921a711c0..e2882497a 100644 --- a/src/Trade/Test/testConfigure.h.cmake +++ b/src/Trade/Test/testConfigure.h.cmake @@ -23,3 +23,4 @@ */ #define TRADE_TEST_DIR "${CMAKE_CURRENT_SOURCE_DIR}" +#define TRADE_TEST_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}"