Fix image IO to handle any format based on file extension

This commit is contained in:
nsubiron 2018-10-05 00:22:15 +02:00
parent 2326345f9e
commit eeb72e7020
4 changed files with 232 additions and 53 deletions

View File

@ -0,0 +1,26 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#include "carla/FileSystem.h"
#include <boost/filesystem/operations.hpp>
namespace carla {
void FileSystem::ValidateFilePath(std::string &filepath, const std::string &ext) {
namespace fs = boost::filesystem;
fs::path path(filepath);
if (path.extension().empty() && !ext.empty()) {
if (ext[0] != '.') {
path += '.';
}
path += ext;
}
fs::create_directories(path.parent_path());
filepath = path.string();
}
} // namespace carla

View File

@ -0,0 +1,29 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include <string>
namespace carla {
/// Static functions for accessing the file system.
///
/// @warning Using this file requires linking against boost_filesystem.
class FileSystem {
public:
/// Convenient function to validate a path before creating a file.
///
/// 1) Ensures all the parent directories are created if missing.
/// 2) If @a filepath is missing the extension, @a default_extension is
/// appended to the path.
static void ValidateFilePath(
std::string &filepath,
const std::string &default_extension = "");
};
} // namespace carla

View File

@ -14,16 +14,12 @@ namespace image {
class ImageIO {
public:
using io_default = io::png;
static_assert(io_default::is_supported, "Default format not supported!");
template <typename Str, typename ImageT, typename IO = io_default>
template <typename Str, typename ImageT, typename IO = io::any>
static void ReadImage(Str &&in_filename, ImageT &image, IO = IO()) {
IO::read_image(std::forward<Str>(in_filename), image);
}
template <typename Str, typename ViewT, typename IO = io_default>
template <typename Str, typename ViewT, typename IO = io::any>
static void WriteView(Str &&out_filename, const ViewT &image_view, IO = IO()) {
IO::write_view(std::forward<Str>(out_filename), image_view);
}

View File

@ -6,6 +6,9 @@
#pragma once
#include "carla/FileSystem.h"
#include "carla/Logging.h"
#include "carla/StringUtil.h"
#include "carla/image/BoostGil.h"
#ifndef LIBCARLA_IMAGE_WITH_PNG_SUPPORT
@ -82,88 +85,213 @@ namespace io {
namespace detail {
struct jpeg_reader {
#if LIBCARLA_IMAGE_WITH_JPEG_SUPPORT
template <typename Str, typename IMAGE>
static void read_image(Str &&in_filename, IMAGE &image) {
static_assert(has_jpeg_support(), "JPEG not supported");
boost::gil::jpeg_read_image(std::forward<Str>(in_filename), image);
}
#endif // LIBCARLA_IMAGE_WITH_JPEG_SUPPORT
};
struct io_png {
struct jpeg_writer {
#if LIBCARLA_IMAGE_WITH_JPEG_SUPPORT
template <typename Str, typename VIEW>
static void write_view(Str &&out_filename, const VIEW &view) {
static_assert(has_jpeg_support(), "JPEG not supported");
boost::gil::jpeg_write_view(std::forward<Str>(out_filename), view);
}
#endif // LIBCARLA_IMAGE_WITH_JPEG_SUPPORT
};
static constexpr bool is_supported = has_png_support();
struct png_reader {
#if LIBCARLA_IMAGE_WITH_PNG_SUPPORT
static constexpr const char *get_default_extension() {
return "png";
}
template <typename Str>
static bool match_extension(const Str &str) {
return StringUtil::EndsWith(str, get_default_extension());
}
template <typename Str, typename IMAGE>
static void read_image(Str &&in_filename, IMAGE &image) {
static_assert(has_png_support(), "PNG not supported");
boost::gil::png_read_and_convert_image(std::forward<Str>(in_filename), image);
}
#endif // LIBCARLA_IMAGE_WITH_PNG_SUPPORT
};
struct png_writer {
#if LIBCARLA_IMAGE_WITH_PNG_SUPPORT
template <typename Str, typename VIEW>
static void write_view(Str &&out_filename, const VIEW &view) {
static_assert(has_png_support(), "PNG not supported");
boost::gil::png_write_view(std::forward<Str>(out_filename), view);
}
#endif // LIBCARLA_IMAGE_WITH_PNG_SUPPORT
};
struct tiff_reader {
#if LIBCARLA_IMAGE_WITH_TIFF_SUPPORT
struct io_jpeg {
static constexpr bool is_supported = has_jpeg_support();
#if LIBCARLA_IMAGE_WITH_JPEG_SUPPORT
static constexpr const char *get_default_extension() {
return "jpeg";
}
template <typename Str>
static bool match_extension(const Str &str) {
return StringUtil::EndsWith(str, get_default_extension()) ||
StringUtil::EndsWith(str, "jpg");
}
template <typename Str, typename IMAGE>
static void read_image(Str &&in_filename, IMAGE &image) {
static_assert(has_tiff_support(), "TIFF not supported");
boost::gil::tiff_read_and_convert_image(std::forward<Str>(in_filename), image);
boost::gil::jpeg_read_image(std::forward<Str>(in_filename), image);
}
template <typename Str, typename VIEW>
static void write_view(Str &&out_filename, const VIEW &view) {
boost::gil::jpeg_write_view(std::forward<Str>(out_filename), view);
}
#endif // LIBCARLA_IMAGE_WITH_JPEG_SUPPORT
};
struct io_tiff {
static constexpr bool is_supported = has_tiff_support();
#if LIBCARLA_IMAGE_WITH_TIFF_SUPPORT
static constexpr const char *get_default_extension() {
return "tiff";
}
template <typename Str>
static bool match_extension(const Str &str) {
return StringUtil::EndsWith(str, get_default_extension());
}
template <typename Str, typename IMAGE>
static void read_image(Str &&in_filename, IMAGE &image) {
boost::gil::tiff_read_and_convert_image(std::forward<Str>(in_filename), image);
}
#endif // LIBCARLA_IMAGE_WITH_TIFF_SUPPORT
};
struct tiff_writer {
#if LIBCARLA_IMAGE_WITH_TIFF_SUPPORT
template <typename Str, typename VIEW>
static void write_view(Str &&out_filename, const VIEW &view) {
static_assert(has_tiff_support(), "TIFF not supported");
boost::gil::tiff_write_view(std::forward<Str>(out_filename), view);
}
#endif // LIBCARLA_IMAGE_WITH_TIFF_SUPPORT
};
template <bool IS_SUPPORTED, typename READER, typename WRITER>
struct image_io;
struct io_resolver {
template <typename IO, typename Str>
static typename std::enable_if<IO::is_supported, bool>::type match_extension(const Str &str) {
return IO::match_extension(str);
}
template <typename IO, typename Str>
static typename std::enable_if<!IO::is_supported, bool>::type match_extension(const Str &) {
return false;
}
template <typename IO, typename Str, typename... Args>
static typename std::enable_if<IO::is_supported>::type read_image(const Str &path, Args &&... args) {
log_debug("reading", path, "as", IO::get_default_extension());
IO::read_image(path, std::forward<Args>(args)...);
}
template <typename IO, typename... Args>
static typename std::enable_if<!IO::is_supported>::type read_image(Args &&...) {
DEBUG_ASSERT(false);
}
template <typename IO, typename... Args>
static typename std::enable_if<IO::is_supported>::type write_view(std::string path, Args &&... args) {
FileSystem::ValidateFilePath(path, IO::get_default_extension());
log_debug("writing", path, "as", IO::get_default_extension());
IO::write_view(path, std::forward<Args>(args)...);
}
template <typename IO, typename... Args>
static typename std::enable_if<!IO::is_supported>::type write_view(Args &&...) {
DEBUG_ASSERT(false);
}
template <typename READER, typename WRITER>
struct image_io<false, READER, WRITER> {
constexpr static bool is_supported = false;
};
template <typename READER, typename WRITER>
struct image_io<true, READER, WRITER> {
constexpr static bool is_supported = true;
using reader_type = READER;
using writer_type = WRITER;
template <typename... IOs>
struct io_impl;
template <typename IO>
struct io_impl<IO> {
constexpr static bool is_supported = IO::is_supported;
template <typename... Args>
static void read_image(Args &&... args) {
io_resolver::read_image<IO>(std::forward<Args>(args)...);
}
template <typename... Args>
static void write_view(Args &&... args) {
io_resolver::write_view<IO>(std::forward<Args>(args)...);
}
template <typename Str, typename... Args>
static bool try_read_image(const Str &filename, Args &&... args) {
if (io_resolver::match_extension<IO>(filename)) {
io_resolver::read_image<IO>(filename, std::forward<Args>(args)...);
return true;
}
return false;
}
template <typename Str, typename... Args>
static bool try_write_view(const Str &filename, Args &&... args) {
if (io_resolver::match_extension<IO>(filename)) {
io_resolver::write_view<IO>(filename, std::forward<Args>(args)...);
return true;
}
return false;
}
};
template <typename IO, typename... IOs>
struct io_impl<IO, IOs...> {
private:
using self = io_impl<IO>;
using recursive = io_impl<IOs...>;
public:
constexpr static bool is_supported = self::is_supported || recursive::is_supported;
template <typename... Args>
static void read_image(Args &... args) {
if (!recursive::try_read_image(args...)) {
self::read_image(args...);
}
}
template <typename... Args>
static bool try_read_image(Args &... args) {
return recursive::try_read_image(args...) || self::try_read_image(args...);
}
template <typename... Args>
static void write_view(Args &... args) {
if (!recursive::try_write_view(args...)) {
self::write_view(args...);
}
}
template <typename... Args>
static bool try_write_view(Args &... args) {
return recursive::try_write_view(args...) || self::try_write_view(args...);
}
};
template <typename DefaultIO, typename... IOs>
struct io_any : detail::io_impl<DefaultIO, IOs...> {
static_assert(DefaultIO::is_supported, "Default IO needs to be supported.");
};
} // namespace detail
struct jpeg : public detail::image_io<has_jpeg_support(), detail::jpeg_reader, detail::jpeg_writer> {};
struct png : detail::io_impl<detail::io_png> {};
struct png : public detail::image_io<has_png_support(), detail::png_reader, detail::png_writer> {};
struct jpeg : detail::io_impl<detail::io_jpeg> {};
struct tiff : public detail::image_io<has_tiff_support(), detail::tiff_reader, detail::tiff_writer> {};
struct tiff : detail::io_impl<detail::io_tiff> {};
struct any : detail::io_any<detail::io_png, detail::io_jpeg, detail::io_tiff> {};
} // namespace io
} // namespace image