Skip to content

Commit

Permalink
Core (LV::Video): Introduce LV::ImageFormat enum for identifying imag…
Browse files Browse the repository at this point in the history
…e formats.
  • Loading branch information
kaixiong committed Jan 29, 2025
1 parent dfbbc07 commit 06b0434
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 29 deletions.
79 changes: 55 additions & 24 deletions libvisual/libvisual/lv_video.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "lv_color.h"
#include "lv_common.h"
#include "lv_cpu.h"
#include "private/lv_string_hash.hpp"
#include "private/lv_video_private.hpp"
#include "private/lv_video_blit.hpp"
#include "private/lv_video_convert.hpp"
Expand All @@ -42,33 +43,56 @@
#include <filesystem>
#include <fstream>
#include <functional>
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>

namespace LV {

namespace fs = std::filesystem;

namespace {

using BitmapLoad = std::function<VideoPtr (std::istream&)>;
using BitmapSave = std::function<bool (Video const&, std::ostream&)>;
using BitmapReader = std::function<VideoPtr (std::istream&)>;
using BitmapWriter = std::function<bool (Video const&, std::ostream&)>;

std::unordered_map<std::string, BitmapLoad> const bitmap_load_map =
struct ImageFormatInfo
{
{ "bmp", bitmap_load_bmp },
{ "png", bitmap_load_png }
std::string name;
BitmapReader reader;
BitmapWriter writer;
std::vector<std::string> extensions;
};

std::unordered_map<std::string, BitmapSave> const bitmap_save_map =
using FormatExtensionLookup = std::unordered_map<std::string, ImageFormat, StringHash, std::equal_to<>>;

std::unordered_map<ImageFormat, ImageFormatInfo> const supported_image_formats
{
{ "png", bitmap_save_png }
{ImageFormat::BMP, {"BMP", bitmap_load_bmp, nullptr, {".bmp"}}},
{ImageFormat::PNG, {"PNG", bitmap_load_png, bitmap_save_png, {".png"}}}
};

std::unordered_map<std::string, std::string> const bitmap_format_extension_map =
FormatExtensionLookup build_image_format_extension_lookup ()
{
{ ".png", "png" },
{ ".bmp", "bmp" }
};
FormatExtensionLookup map;

for (auto const& entry : supported_image_formats)
for (auto const& extension : entry.second.extensions)
map.emplace (extension, entry.first);

return map;
}

std::optional<ImageFormat> find_image_format_by_extension (std::string_view extension)
{
static auto const lookup {build_image_format_extension_lookup ()};

auto match {lookup.find (extension)};
if (match == lookup.end ())
return std::nullopt;
return match->second;
}

bool is_valid_scale_method (VisVideoScaleMethod scale_method)
{
Expand Down Expand Up @@ -227,10 +251,12 @@ namespace LV {

VideoPtr Video::create_from_stream (std::istream& input)
{
for (auto entry : bitmap_load_map) {
auto image {entry.second (input)};
if (image) {
return image;
for (auto entry : supported_image_formats) {
if (entry.second.reader) {
auto image {entry.second.reader (input)};
if (image) {
return image;
}
}
}

Expand Down Expand Up @@ -298,8 +324,8 @@ namespace LV {
auto extension {fs::path {path}.extension ()};
auto extension_lower (to_lower_ascii (extension.string ()));

auto entry {bitmap_format_extension_map.find (extension_lower)};
if (entry == bitmap_format_extension_map.end ()) {
auto format {find_image_format_by_extension (extension_lower)};
if (!format.has_value ()) {
visual_log (VISUAL_LOG_ERROR, "Could not deduce format from filename (%s)", path.c_str ());
return false;
}
Expand All @@ -310,19 +336,24 @@ namespace LV {
return false;
}

return save_to_stream (output, entry->second);
return save_to_stream (output, format.value ());
}

bool Video::save_to_stream (std::ostream& output, std::string const& format) const
bool Video::save_to_stream (std::ostream& output, ImageFormat format) const
{
auto entry {bitmap_save_map.find (format)};
if (entry == bitmap_save_map.end ()) {
std::string format_str {format};
visual_log (VISUAL_LOG_ERROR, "Saving to %s format is not supported", format_str.c_str ());
auto entry {supported_image_formats.find (format)};

if (entry == supported_image_formats.end ()) {
visual_log (VISUAL_LOG_ERROR, "Saving to unknown format (%d).", static_cast<int> (format));
return false;
}

if (!entry->second.writer) {
visual_log (VISUAL_LOG_ERROR, "Saving to %s is unsupported.", entry->second.name.c_str ());
return false;
}

return entry->second (*this, output);
return entry->second.writer (*this, output);
}

void Video::copy_attrs (VideoConstPtr const& src)
Expand Down
22 changes: 20 additions & 2 deletions libvisual/libvisual/lv_video.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ typedef enum {
VISUAL_VIDEO_COMPOSE_TYPE_CUSTOM /**< Custom compose function (looks up on the source VisVideo. */
} VisVideoComposeType;

/**
* The set of known and supported image formats.
*/
typedef enum {
VISUAL_IMAGE_FORMAT_BMP = 0,
VISUAL_IMAGE_FORMAT_PNG
} VisImageFormat;

typedef struct _VisVideoAttrOptions VisVideoAttrOptions;

#ifdef __cplusplus
Expand Down Expand Up @@ -125,6 +133,15 @@ struct _VisVideoAttrOptions {

namespace LV {

/**
* The set of known and supported image formats.
*/
enum class ImageFormat
{
BMP = VISUAL_IMAGE_FORMAT_BMP,
PNG = VISUAL_IMAGE_FORMAT_PNG
};

class Video;

typedef IntrusivePtr<Video> VideoPtr;
Expand Down Expand Up @@ -271,11 +288,12 @@ namespace LV {
/**
* Saves contents to a stream.
*
* @param output stream
* @param output stream to write contents to.
* @param format image file format to encode contents in.
*
* @return true if file was successfully saved, false otherwise.
*/
bool save_to_stream (std::ostream& output, std::string const& format) const;
bool save_to_stream (std::ostream& output, ImageFormat format) const;

/**
* Sets all attributes.
Expand Down
6 changes: 3 additions & 3 deletions libvisual/tests/video_test/video_save_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ void test_save_indexed8 ()
LV_TEST_ASSERT (png_image);

std::stringstream buffer;
LV_TEST_ASSERT (png_image->save_to_stream (buffer, "png"));
LV_TEST_ASSERT (png_image->save_to_stream (buffer, LV::ImageFormat::PNG));

auto png_saved_image {LV::Video::create_from_stream (buffer)};
LV_TEST_ASSERT (png_saved_image);
Expand All @@ -21,7 +21,7 @@ void test_save_rgb24 ()
LV_TEST_ASSERT (png_image);

std::stringstream buffer;
LV_TEST_ASSERT (png_image->save_to_stream (buffer, "png"));
LV_TEST_ASSERT (png_image->save_to_stream (buffer, LV::ImageFormat::PNG));

auto png_saved_image {LV::Video::create_from_stream (buffer)};
LV_TEST_ASSERT (png_saved_image);
Expand All @@ -34,7 +34,7 @@ void test_save_argb32 ()
LV_TEST_ASSERT (png_image);

std::stringstream buffer;
LV_TEST_ASSERT (png_image->save_to_stream (buffer, "png"));
LV_TEST_ASSERT (png_image->save_to_stream (buffer, LV::ImageFormat::PNG));

auto png_saved_image {LV::Video::create_from_stream (buffer)};
LV_TEST_ASSERT (png_saved_image);
Expand Down

0 comments on commit 06b0434

Please sign in to comment.