Browse Source

imageconverter: ability to combine multiple image layers together.

Hey, this was fun, after all!
pull/537/head
Vladimír Vondruš 5 years ago
parent
commit
b83099a8c6
  1. 3
      doc/changelog.dox
  2. 513
      src/Magnum/Trade/imageconverter.cpp

3
doc/changelog.dox

@ -208,7 +208,8 @@ See also:
are encouraged over @relativeref{Trade::AbstractImporter,setFlags()} as it are encouraged over @relativeref{Trade::AbstractImporter,setFlags()} as it
avoid accidentally clearing default flags potentially added in the future. avoid accidentally clearing default flags potentially added in the future.
- Ability to convert also 1D and 3D images with the - Ability to convert also 1D and 3D images with the
@ref magnum-imageconverter "magnum-imageconverter" utility. @ref magnum-imageconverter "magnum-imageconverter" utility, as well as
combining layers into images of one dimension more
@subsubsection changelog-latest-new-vk Vk library @subsubsection changelog-latest-new-vk Vk library

513
src/Magnum/Trade/imageconverter.cpp

@ -26,8 +26,10 @@
#include <Corrade/Containers/Optional.h> #include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/GrowableArray.h> #include <Corrade/Containers/GrowableArray.h>
#include <Corrade/Containers/StaticArray.h> #include <Corrade/Containers/StaticArray.h>
#include <Corrade/Containers/StridedArrayView.h>
#include <Corrade/PluginManager/Manager.h> #include <Corrade/PluginManager/Manager.h>
#include <Corrade/Utility/Arguments.h> #include <Corrade/Utility/Arguments.h>
#include <Corrade/Utility/Algorithms.h>
#include <Corrade/Utility/ConfigurationGroup.h> #include <Corrade/Utility/ConfigurationGroup.h>
#include <Corrade/Utility/DebugStl.h> #include <Corrade/Utility/DebugStl.h>
#include <Corrade/Utility/Directory.h> #include <Corrade/Utility/Directory.h>
@ -69,7 +71,7 @@ magnum-imageconverter [-h|--help] [-I|--importer PLUGIN]
[-C|--converter PLUGIN] [--plugin-dir DIR] [-C|--converter PLUGIN] [--plugin-dir DIR]
[-i|--importer-options key=val,key2=val2,] [-i|--importer-options key=val,key2=val2,]
[-c|--converter-options key=val,key2=val2,] [-D|--dimensions N] [-c|--converter-options key=val,key2=val2,] [-D|--dimensions N]
[--image N] [--level N] [--in-place] [--info] [-v|--verbose] [--image N] [--level N] [--layers] [--in-place] [--info] [-v|--verbose]
[--] input output [--] input output
@endcode @endcode
@ -92,6 +94,8 @@ Arguments:
(default: `2`) (default: `2`)
- `--image N` --- image to import (default: `0`) - `--image N` --- image to import (default: `0`)
- `--level N` --- image level to import (default: `0`) - `--level N` --- image level to import (default: `0`)
- `--layers` --- combine multiple layers into an image with one dimension
more
- `--in-place` --- overwrite the input image with the output - `--in-place` --- overwrite the input image with the output
- `--info` --- print info about the input file and exit - `--info` --- print info about the input file and exit
- `-v`, `--verbose` --- verbose output from importer and converter plugins - `-v`, `--verbose` --- verbose output from importer and converter plugins
@ -146,9 +150,58 @@ magnum-imageconverter image.dds --converter raw data.dat
using namespace Magnum; using namespace Magnum;
namespace {
template<UnsignedInt dimensions> bool checkCommonFormat(const Utility::Arguments& args, const Containers::Array<Trade::ImageData<dimensions>>& images) {
CORRADE_INTERNAL_ASSERT(!images.empty());
const bool compressed = images.front().isCompressed();
PixelFormat format{};
CompressedPixelFormat compressedFormat{};
if(!compressed) format = images.front().format();
else compressedFormat = images.front().compressedFormat();
for(std::size_t i = 1; i != images.size(); ++i) {
if(images[i].isCompressed() != compressed ||
(!compressed && images[i].format() != format) ||
(compressed && images[i].compressedFormat() != compressedFormat))
{
Error e;
e << "Images have different formats," << args.arrayValue("input", i) << "has";
if(images[i].isCompressed())
e << images[i].compressedFormat();
else
e << images[i].format();
e << Debug::nospace << ", expected";
if(compressed)
e << compressedFormat;
else
e << format;
return false;
}
}
return true;
}
template<UnsignedInt dimensions> bool checkCommonFormatAndSize(const Utility::Arguments& args, const Containers::Array<Trade::ImageData<dimensions>>& images) {
if(!checkCommonFormat(args, images)) return false;
CORRADE_INTERNAL_ASSERT(!images.empty());
Math::Vector<dimensions, Int> size = images.front().size();
for(std::size_t i = 1; i != images.size(); ++i) {
if(images[i].size() != size) {
Error{} << "Images have different sizes," << args.arrayValue("input", i) << "has a size of" << images[i].size() << Debug::nospace << ", expected" << size;
return false;
}
}
return true;
}
}
int main(int argc, char** argv) { int main(int argc, char** argv) {
Utility::Arguments args; Utility::Arguments args;
args.addArgument("input").setHelp("input", "input image") args.addArrayArgument("input").setHelp("input", "input image(s)")
.addArgument("output").setHelp("output", "output image; ignored if --info is present, disallowed for --in-place") .addArgument("output").setHelp("output", "output image; ignored if --info is present, disallowed for --in-place")
.addOption('I', "importer", "AnyImageImporter").setHelp("importer", "image importer plugin", "PLUGIN") .addOption('I', "importer", "AnyImageImporter").setHelp("importer", "image importer plugin", "PLUGIN")
.addOption('C', "converter", "AnyImageConverter").setHelp("converter", "image converter plugin", "PLUGIN") .addOption('C', "converter", "AnyImageConverter").setHelp("converter", "image converter plugin", "PLUGIN")
@ -158,6 +211,7 @@ int main(int argc, char** argv) {
.addOption('D', "dimensions", "2").setHelp("dimensions", "import and convert image of given dimensions", "N") .addOption('D', "dimensions", "2").setHelp("dimensions", "import and convert image of given dimensions", "N")
.addOption("image", "0").setHelp("image", "image to import", "N") .addOption("image", "0").setHelp("image", "image to import", "N")
.addOption("level", "0").setHelp("level", "image level to import", "N") .addOption("level", "0").setHelp("level", "image level to import", "N")
.addBooleanOption("layers").setHelp("layers", "combine multiple layers into an image with one dimension more")
.addBooleanOption("in-place").setHelp("in-place", "overwrite the input image with the output") .addBooleanOption("in-place").setHelp("in-place", "overwrite the input image with the output")
.addBooleanOption("info").setHelp("info", "print info about the input file and exit") .addBooleanOption("info").setHelp("info", "print info about the input file and exit")
.addBooleanOption('v', "verbose").setHelp("verbose", "verbose output from importer and converter plugins") .addBooleanOption('v', "verbose").setHelp("verbose", "verbose output from importer and converter plugins")
@ -201,182 +255,306 @@ key=true; configuration subgroups are delimited with /.)")
Warning{} << "Ignoring output file for --info:" << args.value<Containers::StringView>("output"); Warning{} << "Ignoring output file for --info:" << args.value<Containers::StringView>("output");
} }
/* Mutually incompatible options */
if(args.isSet("layers") && args.isSet("in-place")) {
Error{} << "The --layers option can't be combined with --in-place";
return 1;
}
if(args.isSet("layers") && args.isSet("info")) {
Error{} << "The --layers option can't be combined with --info";
return 1;
}
if(!args.isSet("layers") && args.arrayValueCount("input") > 1) {
Error{} << "Multiple input files require the --layers option to be set";
return 1;
}
PluginManager::Manager<Trade::AbstractImporter> importerManager{ PluginManager::Manager<Trade::AbstractImporter> importerManager{
args.value("plugin-dir").empty() ? std::string{} : args.value("plugin-dir").empty() ? std::string{} :
Utility::Directory::join(args.value("plugin-dir"), Trade::AbstractImporter::pluginSearchPaths()[0])}; Utility::Directory::join(args.value("plugin-dir"), Trade::AbstractImporter::pluginSearchPaths()[0])};
/* Load raw data, if requested; assume it's a tightly-packed square of
given format */
/** @todo implement image slicing and then use `--slice "0 0 w h"` to
specify non-rectangular size (and +x +y to specify padding?) */
const std::string input = args.value("input");
const Int dimensions = args.value<Int>("dimensions"); const Int dimensions = args.value<Int>("dimensions");
/** @todo make them array options as well? */
const UnsignedInt image = args.value<UnsignedInt>("image"); const UnsignedInt image = args.value<UnsignedInt>("image");
const UnsignedInt level = args.value<UnsignedInt>("level"); const UnsignedInt level = args.value<UnsignedInt>("level");
Containers::Optional<Trade::ImageData1D> image1D; Containers::Array<Trade::ImageData1D> images1D;
Containers::Optional<Trade::ImageData2D> image2D; Containers::Array<Trade::ImageData2D> images2D;
Containers::Optional<Trade::ImageData3D> image3D; Containers::Array<Trade::ImageData3D> images3D;
if(Utility::String::beginsWith(args.value("importer"), "raw:")) {
if(dimensions != 2) { for(std::size_t i = 0, max = args.arrayValueCount("input"); i != max; ++i) {
Error{} << "Raw data inputs can be only used for 2D images"; const std::string input = args.arrayValue("input", i);
return 1;
} /* Load raw data, if requested; assume it's a tightly-packed square of
given format */
/** @todo implement image slicing and then use `--slice "0 0 w h"` to
specify non-rectangular size (and +x +y to specify padding?) */
if(Utility::String::beginsWith(args.value("importer"), "raw:")) {
if(dimensions != 2) {
Error{} << "Raw data inputs can be only used for 2D images";
return 1;
}
/** @todo Any chance to do this without using internal APIs? */ /** @todo Any chance to do this without using internal APIs? */
const PixelFormat format = Utility::ConfigurationValue<PixelFormat>::fromString(args.value("importer").substr(4), {}); const PixelFormat format = Utility::ConfigurationValue<PixelFormat>::fromString(args.value("importer").substr(4), {});
const UnsignedInt pixelSize = Magnum::pixelSize(format); const UnsignedInt pixelSize = Magnum::pixelSize(format);
if(format == PixelFormat{}) { if(format == PixelFormat{}) {
Error{} << "Invalid raw pixel format" << args.value("importer"); Error{} << "Invalid raw pixel format" << args.value("importer");
return 4; return 4;
} }
/** @todo simplify once read() reliably returns an Optional */ /** @todo simplify once read() reliably returns an Optional */
if(!Utility::Directory::exists(input)) { if(!Utility::Directory::exists(input)) {
Error{} << "Cannot open file" << input; Error{} << "Cannot open file" << input;
return 3; return 3;
} }
Containers::Array<char> data = Utility::Directory::read(input); Containers::Array<char> data = Utility::Directory::read(input);
auto side = Int(std::sqrt(data.size()/pixelSize)); auto side = Int(std::sqrt(data.size()/pixelSize));
if(data.size() % pixelSize || side*side*pixelSize != data.size()) { if(data.size() % pixelSize || side*side*pixelSize != data.size()) {
Error{} << "File of size" << data.size() << "is not a tightly-packed square of" << format; Error{} << "File of size" << data.size() << "is not a tightly-packed square of" << format;
return 5; return 5;
} }
/* Print image info, if requested */ /* Print image info, if requested */
if(args.isSet("info")) { if(args.isSet("info")) {
Debug{} << "Image 0:\n Mip 0:" << format << Vector2i{side}; Debug{} << "Image 0:\n Mip 0:" << format << Vector2i{side};
return 0; return 0;
} }
image2D = Trade::ImageData2D(format, Vector2i{side}, std::move(data)); arrayAppend(images2D, InPlaceInit, format, Vector2i{side}, std::move(data));
/* Otherwise load it using an importer plugin */ /* Otherwise load it using an importer plugin */
} else { } else {
Containers::Pointer<Trade::AbstractImporter> importer = importerManager.loadAndInstantiate(args.value("importer")); Containers::Pointer<Trade::AbstractImporter> importer = importerManager.loadAndInstantiate(args.value("importer"));
if(!importer) { if(!importer) {
Debug{} << "Available importer plugins:" << Utility::String::join(importerManager.aliasList(), ", "); Debug{} << "Available importer plugins:" << Utility::String::join(importerManager.aliasList(), ", ");
return 1; return 1;
} }
/* Set options, if passed */ /* Set options, if passed */
if(args.isSet("verbose")) importer->addFlags(Trade::ImporterFlag::Verbose); if(args.isSet("verbose")) importer->addFlags(Trade::ImporterFlag::Verbose);
Implementation::setOptions(*importer, "AnyImageImporter", args.value("importer-options")); Implementation::setOptions(*importer, "AnyImageImporter", args.value("importer-options"));
/* Print image info, if requested. This is always done for just one
file, checked above. */
if(args.isSet("info")) {
/* Open the file, but don't fail when an image can't be
opened */
if(!importer->openFile(input)) {
Error() << "Cannot open file" << input;
return 3;
}
if(!importer->image1DCount() && !importer->image2DCount() && !importer->image3DCount()) {
Debug{} << "No images found in" << input;
return 0;
}
/* Parse everything first to avoid errors interleaved with
output. In case the images have all just a single level and
no names, write them in a compact way without listing
levels. */
bool error = false, compact = true;
Containers::Array<Trade::Implementation::ImageInfo> infos =
Trade::Implementation::imageInfo(*importer, error, compact);
for(const Trade::Implementation::ImageInfo& info: infos) {
Debug d;
if(info.level == 0) {
if(info.size.z()) d << "3D image";
else if(info.size.y()) d << "2D image";
else d << "1D image";
d << info.image << Debug::nospace << ":";
if(!info.name.empty()) d << info.name;
if(!compact) d << Debug::newline;
}
if(!compact) d << " Level" << info.level << Debug::nospace << ":";
if(info.compressed) d << info.compressedFormat;
else d << info.format;
if(info.size.z()) d << info.size;
else if(info.size.y()) d << info.size.xy();
else d << Math::Vector<1, Int>(info.size.x());
}
return error ? 1 : 0;
}
/* Print image info, if requested */ /* Open input file */
if(args.isSet("info")) {
/* Open the file, but don't fail when an image can't be opened */
if(!importer->openFile(input)) { if(!importer->openFile(input)) {
Error() << "Cannot open file" << input; Error{} << "Cannot open file" << input;
return 3; return 3;
} }
/* Bail early if there's no image whatsoever. More detailed errors
with hints are provided for each dimension below. */
if(!importer->image1DCount() && !importer->image2DCount() && !importer->image3DCount()) { if(!importer->image1DCount() && !importer->image2DCount() && !importer->image3DCount()) {
Debug{} << "No images found in" << input; Error{} << "No images found in" << input;
return 0; return 1;
} }
/* Parse everything first to avoid errors interleaved with output. bool imported = false;
In case the images have all just a single level and no names, if(dimensions == 1) {
write them in a compact way without listing levels. */ if(!importer->image1DCount()) {
bool error = false, compact = true; Error{} << "No 1D images found in" << input << Debug::nospace << ". Specify -D2 or -D3 for 2D or 3D image conversion.";
Containers::Array<Trade::Implementation::ImageInfo> infos = return 1;
Trade::Implementation::imageInfo(*importer, error, compact); }
if(image >= importer->image1DCount()) {
for(const Trade::Implementation::ImageInfo& info: infos) { Error{} << "1D image number" << image << "not found in" << input << Debug::nospace << ", the file has only" << importer->image1DCount() << "1D images";
Debug d; return 1;
if(info.level == 0) { }
if(info.size.z()) d << "3D image"; if(level >= importer->image1DLevelCount(image)) {
else if(info.size.y()) d << "2D image"; Error{} << "1D image" << image << "in" << input << "doesn't have a level number" << level << Debug::nospace << ", only" << importer->image1DLevelCount(image) << "levels";
else d << "1D image"; return 1;
d << info.image << Debug::nospace << ":";
if(!info.name.empty()) d << info.name;
if(!compact) d << Debug::newline;
} }
if(!compact) d << " Level" << info.level << Debug::nospace << ":";
if(info.compressed) d << info.compressedFormat;
else d << info.format;
if(info.size.z()) d << info.size;
else if(info.size.y()) d << info.size.xy();
else d << Math::Vector<1, Int>(info.size.x());
}
return error ? 1 : 0; if(Containers::Optional<Trade::ImageData1D> image1D = importer->image1D(image, level)) {
} arrayAppend(images1D, std::move(*image1D));
imported = true;
}
/* Open input file */ } else if(dimensions == 2) {
if(!importer->openFile(input)) { if(!importer->image2DCount()) {
Error{} << "Cannot open file" << input; Error{} << "No 2D images found in" << input << Debug::nospace << ". Specify -D1 or -D3 for 1D or 3D image conversion.";
return 3; return 1;
} }
if(image >= importer->image2DCount()) {
Error{} << "2D image number" << image << "not found in" << input << Debug::nospace << ", the file has only" << importer->image2DCount() << "2D images";
return 1;
}
if(level >= importer->image2DLevelCount(image)) {
Error{} << "2D image" << image << "in" << input << "doesn't have a level number" << level << Debug::nospace << ", only" << importer->image2DLevelCount(image) << "levels";
return 1;
}
/* Bail early if there's no image whatsoever. More detailed errors with if(Containers::Optional<Trade::ImageData2D> image2D = importer->image2D(image, level)) {
hints are provided for each dimension below. */ arrayAppend(images2D, std::move(*image2D));
if(!importer->image1DCount() && !importer->image2DCount() && !importer->image3DCount()) { imported = true;
Error{} << "No images found in" << input; }
return 1;
}
bool imported; } else if(dimensions == 3) {
if(dimensions == 1) { if(!importer->image3DCount()) {
if(!importer->image1DCount()) { Error{} << "No 3D images found in" << input << Debug::nospace << ". Specify -D1 or -D2 for 1D or 2D image conversion.";
Error{} << "No 1D images found in" << input << Debug::nospace << ". Specify -D2 or -D3 for 2D or 3D image conversion."; return 1;
return 1; }
} if(image >= importer->image3DCount()) {
if(image >= importer->image1DCount()) { Error{} << "3D image number" << image << "not found in" << input << Debug::nospace << ", the file has only" << importer->image3DCount() << "3D images";
Error{} << "1D image number" << image << "not found in" << input << Debug::nospace << ", the file has only" << importer->image1DCount() << "1D images"; return 1;
return 1; }
} if(level >= importer->image3DLevelCount(image)) {
if(level >= importer->image1DLevelCount(image)) { Error{} << "3D image" << image << "in" << input << "doesn't have a level number" << level << Debug::nospace << ", only" << importer->image3DLevelCount(image) << "levels";
Error{} << "1D image" << image << "in" << input << "doesn't have a level number" << level << Debug::nospace << ", only" << importer->image1DLevelCount(image) << "levels"; return 1;
return 1; }
}
imported = !!(image1D = importer->image1D(image, level)); if(Containers::Optional<Trade::ImageData3D> image3D = importer->image3D(image, level)) {
arrayAppend(images3D, std::move(*image3D));
imported = true;
}
} else if(dimensions == 2) { } else {
if(!importer->image2DCount()) { Error{} << "Invalid --dimensions option:" << args.value("dimensions");
Error{} << "No 2D images found in" << input << Debug::nospace << ". Specify -D1 or -D3 for 1D or 3D image conversion.";
return 1;
}
if(image >= importer->image2DCount()) {
Error{} << "2D image number" << image << "not found in" << input << Debug::nospace << ", the file has only" << importer->image2DCount() << "2D images";
return 1;
}
if(level >= importer->image2DLevelCount(image)) {
Error{} << "2D image" << image << "in" << input << "doesn't have a level number" << level << Debug::nospace << ", only" << importer->image2DLevelCount(image) << "levels";
return 1; return 1;
} }
imported = !!(image2D = importer->image2D(image, level)); if(!imported) {
Error{} << "Cannot import image" << image << Debug::nospace << ":" << Debug::nospace << level << "from" << input;
} else if(dimensions == 3) { return 4;
if(!importer->image3DCount()) {
Error{} << "No 3D images found in" << input << Debug::nospace << ". Specify -D1 or -D2 for 1D or 2D image conversion.";
return 1;
} }
if(image >= importer->image3DCount()) { }
Error{} << "3D image number" << image << "not found in" << input << Debug::nospace << ", the file has only" << importer->image3DCount() << "3D images"; }
std::string output;
if(args.isSet("in-place")) {
/* Should have been checked in a graceful way above */
CORRADE_INTERNAL_ASSERT(args.arrayValueCount("input") == 1);
output = args.arrayValue("input", 0);
} else output = args.value("output");
Int outputDimensions;
/* Not strictly needed to be an Optional, acts as a sanity check that we
don't use something that wasn't populated proparly. */
Containers::Optional<Trade::ImageData1D> outputImage1D;
Containers::Optional<Trade::ImageData2D> outputImage2D;
Containers::Optional<Trade::ImageData3D> outputImage3D;
/* Combine multiple layers into an image of one dimension more */
if(args.isSet("layers")) {
if(dimensions == 1) {
if(!checkCommonFormatAndSize(args, images1D)) return 1;
outputDimensions = 2;
if(!images1D.front().isCompressed()) {
/* Allocate a new image */
/** @todo simplify once ImageData is able to allocate on its
own, including correct padding etc */
const Vector2i size{images1D.front().size()[0], Int(images1D.size())};
outputImage2D = Trade::ImageData2D{
/* Don't want to bother with row padding, it's temporary
anyway */
PixelStorage{}.setAlignment(1),
images1D.front().format(),
size,
Containers::Array<char>{NoInit, size.product()*images1D.front().pixelSize()}
};
/* Copy the pixel data over */
const Containers::StridedArrayView3D<char> outputPixels = outputImage2D->mutablePixels();
for(std::size_t i = 0; i != images1D.size(); ++i)
Utility::copy(images1D[i].pixels(), outputPixels[i]);
} else {
Error{} << "The --layers option isn't implemented for compressed images yet.";
return 1; return 1;
} }
if(level >= importer->image3DLevelCount(image)) {
Error{} << "3D image" << image << "in" << input << "doesn't have a level number" << level << Debug::nospace << ", only" << importer->image3DLevelCount(image) << "levels"; } else if(dimensions == 2) {
if(!checkCommonFormatAndSize(args, images2D)) return 1;
outputDimensions = 3;
if(!images2D.front().isCompressed()) {
/* Allocate a new image */
/** @todo simplify once ImageData is able to allocate on its
own, including correct padding etc */
const Vector3i size{images2D.front().size(), Int(images2D.size())};
outputImage3D = Trade::ImageData3D{
/* Don't want to bother with row padding, it's temporary
anyway */
PixelStorage{}.setAlignment(1),
images2D.front().format(),
size,
Containers::Array<char>{NoInit, size.product()*images2D.front().pixelSize()}
};
/* Copy the pixel data over */
const Containers::StridedArrayView4D<char> outputPixels = outputImage3D->mutablePixels();
for(std::size_t i = 0; i != images2D.size(); ++i)
Utility::copy(images2D[i].pixels(), outputPixels[i]);
} else {
Error{} << "The --layers option isn't implemented for compressed images yet.";
return 1; return 1;
} }
imported = !!(image3D = importer->image3D(image, level)); } else if(dimensions == 3) {
Error{} << "The --layers option can be only used with 1D and 2D inputs, not 3D";
} else {
Error{} << "Invalid --dimensions option:" << args.value("dimensions");
return 1; return 1;
}
if(!imported) { } else CORRADE_INTERNAL_ASSERT_UNREACHABLE();
Error{} << "Cannot import image" << image << Debug::nospace << ":" << Debug::nospace << level << "from" << input;
return 4;
}
}
const std::string output = args.value(args.isSet("in-place") ? "input" : "output"); /* Single image conversion, just pass the input through */
} else {
if(dimensions == 1) {
CORRADE_INTERNAL_ASSERT(images1D.size() == 1);
outputDimensions = 1;
outputImage1D = std::move(images1D.front());
} else if(dimensions == 2) {
CORRADE_INTERNAL_ASSERT(images2D.size() == 1);
outputDimensions = 2;
outputImage2D = std::move(images2D.front());
} else if(dimensions == 3) {
CORRADE_INTERNAL_ASSERT(images3D.size() == 1);
outputDimensions = 3;
outputImage3D = std::move(images3D.front());
} else CORRADE_INTERNAL_ASSERT_UNREACHABLE();
}
{ {
Debug d; Debug d;
@ -384,23 +562,26 @@ key=true; configuration subgroups are delimited with /.)")
d << "Writing raw image data of size"; d << "Writing raw image data of size";
else else
d << "Converting image of size"; d << "Converting image of size";
if(dimensions == 1) if(outputDimensions == 1)
d << image1D->size(); d << outputImage1D->size();
else if(dimensions == 2) else if(outputDimensions == 2)
d << image2D->size(); d << outputImage2D->size();
else if(dimensions == 3) else if(outputDimensions == 3)
d << image3D->size(); d << outputImage3D->size();
else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); else CORRADE_INTERNAL_ASSERT_UNREACHABLE();
d << "and format"; d << "and format";
if(dimensions == 1) { if(outputDimensions == 1) {
if(image1D->isCompressed()) d << image1D->compressedFormat(); if(outputImage1D->isCompressed())
else d << image1D->format(); d << outputImage1D->compressedFormat();
} else if(dimensions == 2) { else d << outputImage1D->format();
if(image2D->isCompressed()) d << image2D->compressedFormat(); } else if(outputDimensions == 2) {
else d << image2D->format(); if(outputImage2D->isCompressed())
} else if(dimensions == 3) { d << outputImage2D->compressedFormat();
if(image3D->isCompressed()) d << image3D->compressedFormat(); else d << outputImage2D->format();
else d << image3D->format(); } else if(outputDimensions == 3) {
if(outputImage3D->isCompressed())
d << outputImage3D->compressedFormat();
else d << outputImage3D->format();
} else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); } else CORRADE_INTERNAL_ASSERT_UNREACHABLE();
d << "to" << output; d << "to" << output;
} }
@ -408,12 +589,12 @@ key=true; configuration subgroups are delimited with /.)")
/* Save raw data, if requested */ /* Save raw data, if requested */
if(args.value("converter") == "raw") { if(args.value("converter") == "raw") {
Containers::ArrayView<const char> data; Containers::ArrayView<const char> data;
if(dimensions == 1) if(outputDimensions == 1)
data = image1D->data(); data = outputImage1D->data();
else if(dimensions == 2) else if(outputDimensions == 2)
data = image2D->data(); data = outputImage3D->data();
else if(dimensions == 3) else if(outputDimensions == 3)
data = image3D->data(); data = outputImage3D->data();
else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); else CORRADE_INTERNAL_ASSERT_UNREACHABLE();
return Utility::Directory::write(output, data) ? 0 : 1; return Utility::Directory::write(output, data) ? 0 : 1;
} }
@ -434,15 +615,15 @@ key=true; configuration subgroups are delimited with /.)")
/* Save output file */ /* Save output file */
bool converted; bool converted;
if(dimensions == 1) if(outputDimensions == 1)
converted = converter->convertToFile(*image1D, output); converted = converter->convertToFile(*outputImage1D, output);
else if(dimensions == 2) else if(outputDimensions == 2)
converted = converter->convertToFile(*image2D, output); converted = converter->convertToFile(*outputImage2D, output);
else if(dimensions == 3) else if(outputDimensions == 3)
converted = converter->convertToFile(*image3D, output); converted = converter->convertToFile(*outputImage3D, output);
else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); else CORRADE_INTERNAL_ASSERT_UNREACHABLE();
if(!converted) { if(!converted) {
Error() << "Cannot save file" << output; Error{} << "Cannot save file" << output;
return 5; return 5;
} }
} }

Loading…
Cancel
Save