Browse Source

AnyImageImporter: fall back to BasisImporter if KtxImporter isn't found.

Final piece of the KTX2/Basis delegation chain that I somehow forgot to
implement.
pull/565/merge
Vladimír Vondruš 4 years ago
parent
commit
569ae5a195
  1. 39
      src/MagnumPlugins/AnyImageImporter/AnyImageImporter.cpp
  2. 3
      src/MagnumPlugins/AnyImageImporter/AnyImageImporter.h
  3. 112
      src/MagnumPlugins/AnyImageImporter/Test/AnyImageImporterTest.cpp
  4. 2
      src/MagnumPlugins/AnyImageImporter/Test/CMakeLists.txt
  5. BIN
      src/MagnumPlugins/AnyImageImporter/Test/basis.ktx2

39
src/MagnumPlugins/AnyImageImporter/AnyImageImporter.cpp

@ -94,9 +94,31 @@ void AnyImageImporter::doOpenFile(const Containers::StringView filename) {
plugin = "JpegImporter"_s;
else if(normalizedExtension == ".jp2"_s)
plugin = "Jpeg2000Importer"_s;
else if(normalizedExtension == ".ktx2"_s)
else if(normalizedExtension == ".ktx2"_s) {
plugin = "KtxImporter"_s;
else if(normalizedExtension == ".mng"_s)
/* KtxImporter delegates to BasisImporter in case the file is
Basis-compressed, so that's a good default choice. However, if it
isn't available, we should try delegating to BasisImporter instead,
so people that have just Basis-compressed KTX files don't need to
have KtxImporter as well.
BasisImporter unfortunately can't handle non-Basis-compressed KTX
files, so in case people have just BasisImporter and not
KtxImporter, it'll fail, but with a clear message suggesting to use
KtxImporter. If neither BasisImporter would be available, it'd fail
too (complaining that KtxImporter isn't available), so the behavior
is roughly the same.
Further discussion and reasoning here:
https://github.com/mosra/magnum-plugins/pull/112#discussion_r734976174 */
if(manager()->loadState("KtxImporter"_s) == PluginManager::LoadState::NotFound &&
manager()->loadState("BasisImporter"_s) != PluginManager::LoadState::NotFound) {
if(flags() & ImporterFlag::Verbose)
Debug{} << "Trade::AnyImageImporter::openFile(): KtxImporter not found, trying a fallback";
plugin = "BasisImporter"_s;
}
} else if(normalizedExtension == ".mng"_s)
plugin = "MngImporter"_s;
else if(normalizedExtension == ".pbm"_s)
plugin = "PbmImporter"_s;
@ -200,10 +222,19 @@ void AnyImageImporter::doOpenData(Containers::Array<char>&& data, DataFlags) {
else if(dataString.hasPrefix("\xff\xd8\xff"_s))
plugin = "JpegImporter"_s;
/* https://github.khronos.org/KTX-Specification/#_identifier */
else if(dataString.hasPrefix("\xabKTX 20\xbb\r\n\x1a\n"_s))
else if(dataString.hasPrefix("\xabKTX 20\xbb\r\n\x1a\n"_s)) {
plugin = "KtxImporter"_s;
/* Same logic as in doOpenFile() for *.ktx2 files, see above for more
information */
if(manager()->loadState("KtxImporter"_s) == PluginManager::LoadState::NotFound &&
manager()->loadState("BasisImporter"_s) != PluginManager::LoadState::NotFound) {
if(flags() & ImporterFlag::Verbose)
Debug{} << "Trade::AnyImageImporter::openData(): KtxImporter not found, trying a fallback";
plugin = "BasisImporter"_s;
}
/* https://en.wikipedia.org/wiki/Portable_Network_Graphics#File_header */
else if(dataString.hasPrefix("\x89PNG\x0d\x0a\x1a\x0a"_s))
} else if(dataString.hasPrefix("\x89PNG\x0d\x0a\x1a\x0a"_s))
plugin = "PngImporter"_s;
/* http://paulbourke.net/dataformats/tiff/,
http://paulbourke.net/dataformats/tiff/tiff_summary.pdf */

3
src/MagnumPlugins/AnyImageImporter/AnyImageImporter.h

@ -79,7 +79,8 @@ Supported formats:
- JPEG 2000 (`*.jp2`), loaded with any plugin that provides
`Jpeg2000Importer`
- KTX2 (`*.ktx2` or data with corresponding signature), loaded with
@ref KtxImporter or any other plugin that provides it
@ref KtxImporter or any other plugin that provides it. If not found,
@ref BasisImporter is tried as a fallback.
- Multiple-image Network Graphics (`*.mng`), loaded with any plugin that
provides `MngImporter`
- Portable Bitmap (`*.pbm`), loaded with any plugin that provides `PbmImporter`

112
src/MagnumPlugins/AnyImageImporter/Test/AnyImageImporterTest.cpp

@ -29,6 +29,7 @@
#include <Corrade/Containers/StringView.h>
#include <Corrade/PluginManager/Manager.h>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/TestSuite/Compare/String.h>
#include <Corrade/Utility/ConfigurationGroup.h>
#include <Corrade/Utility/DebugStl.h>
#include <Corrade/Utility/FormatStl.h>
@ -51,6 +52,9 @@ struct AnyImageImporterTest: TestSuite::Tester {
void load3D();
void detect();
void ktxBasisFallbackFile();
void ktxBasisFallbackData();
void unknownExtension();
void unknownSignature();
void emptyData();
@ -129,6 +133,31 @@ constexpr struct {
/* Not testing everything, just the most important ones */
};
const struct {
const char* name;
bool ktxImporterPresent;
bool basisImporterPresent;
bool verbose;
const char* expectedMessage;
} KtxBasisFallbackData[]{
{"both KtxImporter and BasisImporter present", true, true, true,
"Trade::AnyImageImporter::{}(): using KtxImporter\n"},
{"only KtxImporter present", true, false, true,
"Trade::AnyImageImporter::{}(): using KtxImporter\n"},
{"only BasisImporter present", false, true, true,
"Trade::AnyImageImporter::{0}(): KtxImporter not found, trying a fallback\n"
"Trade::AnyImageImporter::{0}(): using BasisImporter\n"},
{"only BasisImporter present, verbose output disabled", false, true, false,
nullptr},
{"neither present", false, false, true,
#ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
"PluginManager::Manager::load(): plugin KtxImporter is not static and was not found in nonexistent\n"
#else
"PluginManager::Manager::load(): plugin KtxImporter was not found\n"
#endif
"Trade::AnyImageImporter::{}(): cannot load the KtxImporter plugin"}
};
using namespace Containers::Literals;
const struct {
@ -173,6 +202,10 @@ AnyImageImporterTest::AnyImageImporterTest() {
addInstancedTests({&AnyImageImporterTest::detect},
Containers::arraySize(DetectData));
addInstancedTests({&AnyImageImporterTest::ktxBasisFallbackFile,
&AnyImageImporterTest::ktxBasisFallbackData},
Containers::arraySize(KtxBasisFallbackData));
addTests({&AnyImageImporterTest::unknownExtension});
addInstancedTests({&AnyImageImporterTest::unknownSignature},
@ -310,6 +343,85 @@ void AnyImageImporterTest::detect() {
#endif
}
void AnyImageImporterTest::ktxBasisFallbackFile() {
auto&& data = KtxBasisFallbackData[testCaseInstanceId()];
setTestCaseDescription(data.name);
PluginManager::Manager<AbstractImporter> manager{MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR};
#ifdef ANYIMAGEIMPORTER_PLUGIN_FILENAME
CORRADE_VERIFY(manager.load(ANYIMAGEIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded);
#endif
/* Catch also ABI and interface mismatch errors */
if(data.ktxImporterPresent && !(manager.load("KtxImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("KtxImporter plugin can't be loaded.");
if(data.basisImporterPresent && !(manager.load("BasisImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("BasisImporter plugin can't be loaded.");
/* Set invalid plugin directory to ensure the remaining plugins don't get
loaded after this point */
#ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
manager.setPluginDirectory("nonexistent");
#endif
Containers::Pointer<AbstractImporter> importer = manager.instantiate("AnyImageImporter");
if(data.verbose)
importer->setFlags(ImporterFlag::Verbose);
std::ostringstream out;
Debug redirectOutput{&out};
Error redirectError{&out};
/* We don't care if the file opens (it won't if BasisImporter isn't
present), just verifying if correct plugin got picked by checking the
message. */
importer->openFile(Utility::Path::join(ANYIMAGEIMPORTER_TEST_DIR, "basis.ktx2"));
if(data.expectedMessage) CORRADE_COMPARE_AS(out.str(),
Utility::formatString(data.expectedMessage, "openFile"),
TestSuite::Compare::StringHasPrefix);
else CORRADE_COMPARE(out.str(), "");
}
void AnyImageImporterTest::ktxBasisFallbackData() {
auto&& data = KtxBasisFallbackData[testCaseInstanceId()];
setTestCaseDescription(data.name);
PluginManager::Manager<AbstractImporter> manager{MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR};
#ifdef ANYIMAGEIMPORTER_PLUGIN_FILENAME
CORRADE_VERIFY(manager.load(ANYIMAGEIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded);
#endif
/* Catch also ABI and interface mismatch errors */
if(data.ktxImporterPresent && !(manager.load("KtxImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("KtxImporter plugin can't be loaded.");
if(data.basisImporterPresent && !(manager.load("BasisImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("BasisImporter plugin can't be loaded.");
/* Set invalid plugin directory to ensure the remaining plugins don't get
loaded after this point */
#ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
manager.setPluginDirectory("nonexistent");
#endif
Containers::Pointer<AbstractImporter> importer = manager.instantiate("AnyImageImporter");
if(data.verbose)
importer->setFlags(ImporterFlag::Verbose);
Containers::Optional<Containers::Array<char>> read = Utility::Path::read(Utility::Path::join(ANYIMAGEIMPORTER_TEST_DIR, "basis.ktx2"));
CORRADE_VERIFY(read);
std::ostringstream out;
Debug redirectOutput{&out};
Error redirectError{&out};
/* We don't care if the file opens (it won't if BasisImporter isn't
present), just verifying if correct plugin got picked by checking the
message. */
importer->openData(*read);
if(data.expectedMessage) CORRADE_COMPARE_AS(out.str(),
Utility::formatString(data.expectedMessage, "openData"),
TestSuite::Compare::StringHasPrefix);
else CORRADE_COMPARE(out.str(), "");
}
void AnyImageImporterTest::unknownExtension() {
Containers::Pointer<AbstractImporter> importer = _manager.instantiate("AnyImageImporter");

2
src/MagnumPlugins/AnyImageImporter/Test/CMakeLists.txt

@ -56,6 +56,8 @@ corrade_add_test(AnyImageImporterTest AnyImageImporterTest.cpp
# Generated by AnyImageConverterTest::convert{1D,3D}()
1d.ktx2
3d.ktx2
# rgb.ktx2 from BasisImporter test data (in magnum-plugins), renamed
basis.ktx2
gray.jpg
image.exr
image.tiff

BIN
src/MagnumPlugins/AnyImageImporter/Test/basis.ktx2

Binary file not shown.
Loading…
Cancel
Save