From 62c3b57fa0f647461965a0551d385fd672c8f8fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 11 Dec 2021 19:47:15 +0100 Subject: [PATCH] imageconverter: add a --map option. Because sometimes we might want to extract images out of huge scene files, or using importers that only allow memory-mapped input. --- doc/changelog.dox | 3 ++- src/Magnum/Trade/imageconverter.cpp | 42 +++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index 3a1bb8489..4b0d67a97 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -237,7 +237,8 @@ See also: non-temporary memory to the importer, allowing the implementations to avoid allocating an internal copy; for benchmarking and testing purposes it's also exposed via a `--map` option in the - @ref magnum-sceneconverter "magnum-sceneconverter" utility + @ref magnum-sceneconverter "magnum-sceneconverter" and + @ref magnum-imageconverter "magnum-imageconverter" utilities - Ability to convert also 1D and 3D images with the @ref magnum-imageconverter "magnum-imageconverter" utility, as well as combining layers into images of one dimension more (or vice versa) and diff --git a/src/Magnum/Trade/imageconverter.cpp b/src/Magnum/Trade/imageconverter.cpp index d0fc07726..e920806d1 100644 --- a/src/Magnum/Trade/imageconverter.cpp +++ b/src/Magnum/Trade/imageconverter.cpp @@ -69,7 +69,7 @@ information. @code{.sh} magnum-imageconverter [-h|--help] [-I|--importer PLUGIN] - [-C|--converter PLUGIN] [--plugin-dir DIR] + [-C|--converter PLUGIN] [--plugin-dir DIR] [--map] [-i|--importer-options key=val,key2=val2,…] [-c|--converter-options key=val,key2=val2,…] [-D|--dimensions N] [--image N] [--level N] [--layer N] [--layers] [--levels] [--in-place] @@ -87,6 +87,8 @@ Arguments: - `-C`, `--converter PLUGIN` --- image converter plugin (default: @ref Trade::AnyImageConverter "AnyImageConverter") - `--plugin-dir DIR` --- override base plugin dir +- `--map` --- memory-map the input for zero-copy import (works only for + standalone files) - `-i`, `--importer-options key=val,key2=val2,…` --- configuration options to pass to the importer - `-c`, `--converter-options key=val,key2=val2,…` --- configuration options @@ -272,6 +274,9 @@ int main(int argc, char** argv) { .addOption('I', "importer", "AnyImageImporter").setHelp("importer", "image importer plugin", "PLUGIN") .addOption('C', "converter", "AnyImageConverter").setHelp("converter", "image converter plugin", "PLUGIN") .addOption("plugin-dir").setHelp("plugin-dir", "override base plugin dir", "DIR") + #if defined(CORRADE_TARGET_UNIX) || (defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT)) + .addBooleanOption("map").setHelp("map", "memory-map the input for zero-copy import (works only for standalone files)") + #endif .addOption('i', "importer-options").setHelp("importer-options", "configuration options to pass to the importer", "key=val,key2=val2,…") .addOption('c', "converter-options").setHelp("converter-options", "configuration options to pass to the converter", "key=val,key2=val2,…") .addOption('D', "dimensions", "2").setHelp("dimensions", "import and convert image of given dimensions", "N") @@ -365,6 +370,9 @@ key=true; configuration subgroups are delimited with /.)") const UnsignedInt image = args.value("image"); Containers::Optional level; if(!args.value("level").empty()) level = args.value("level"); + #if defined(CORRADE_TARGET_UNIX) || (defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT)) + Containers::Array> mapped; + #endif Containers::Array images1D; Containers::Array images2D; Containers::Array images3D; @@ -398,11 +406,30 @@ key=true; configuration subgroups are delimited with /.)") Error{} << "Cannot open file" << input; return 3; } + + /* Read the file or map it if requested */ Containers::Array data; + #if defined(CORRADE_TARGET_UNIX) || (defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT)) + if(args.isSet("map")) { + arrayAppend(mapped, InPlaceInit); + + Trade::Implementation::Duration d{importTime}; + if(!(mapped.back() = Utility::Directory::mapRead(input))) { + Error() << "Cannot memory-map file" << input; + return 3; + } + + /* Fake a mutable array with a non-owning deleter to have the + same type as from Directory::read(). The actual memory is + owned by the `mapped` array. */ + data = Containers::Array{const_cast(mapped.back().data()), mapped.back().size(), [](char*, std::size_t){}}; + } else + #endif { Trade::Implementation::Duration d{importTime}; data = Utility::Directory::read(input); } + auto side = Int(std::sqrt(data.size()/pixelSize)); if(data.size() % pixelSize || side*side*pixelSize != data.size()) { Error{} << "File of size" << data.size() << "is not a tightly-packed square of" << format; @@ -434,7 +461,18 @@ key=true; configuration subgroups are delimited with /.)") if(args.isSet("verbose")) importer->addFlags(Trade::ImporterFlag::Verbose); Implementation::setOptions(*importer, "AnyImageImporter", args.value("importer-options")); - /* Open input file */ + /* Open the file or map it if requested */ + #if defined(CORRADE_TARGET_UNIX) || (defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT)) + if(args.isSet("map")) { + arrayAppend(mapped, InPlaceInit); + + Trade::Implementation::Duration d{importTime}; + if(!(mapped.back() = Utility::Directory::mapRead(input)) || !importer->openMemory(mapped.back())) { + Error() << "Cannot memory-map file" << input; + return 3; + } + } else + #endif { Trade::Implementation::Duration d{importTime}; if(!importer->openFile(input)) {