4242#include < filesystem>
4343#include < fstream>
4444#include < functional>
45+ #include < optional>
46+ #include < string>
4547#include < unordered_map>
48+ #include < vector>
4649
4750namespace LV {
4851
4952 namespace fs = std::filesystem;
5053
5154 namespace {
5255
53- using BitmapLoad = std::function<VideoPtr (std::istream&)>;
54- using BitmapSave = std::function<bool (Video const &, std::ostream&)>;
56+ using BitmapReader = std::function<VideoPtr (std::istream&)>;
57+ using BitmapWriter = std::function<bool (Video const &, std::ostream&)>;
5558
56- std::unordered_map<std::string, BitmapLoad> const bitmap_load_map =
59+ struct ImageFormatInfo
5760 {
58- { " bmp" , bitmap_load_bmp },
59- { " png" , bitmap_load_png }
61+ std::string name;
62+ BitmapReader reader;
63+ BitmapWriter writer;
64+ std::vector<std::string> extensions;
6065 };
6166
62- std::unordered_map<std::string, BitmapSave > const bitmap_save_map =
67+ std::unordered_map<ImageFormat, ImageFormatInfo > const supported_image_formats
6368 {
64- { " png" , bitmap_save_png }
69+ {ImageFormat::BMP, {" BMP" , bitmap_load_bmp, nullptr , {" .bmp" }}},
70+ {ImageFormat::PNG, {" PNG" , bitmap_load_png, bitmap_save_png, {" .png" }}}
6571 };
6672
67- std::unordered_map<std::string, std::string > const bitmap_format_extension_map =
73+ std::unordered_map<std::string, ImageFormat > const image_format_by_extension
6874 {
69- { " .png " , " png " },
70- { " .bmp " , " bmp " }
75+ {" .bmp " , ImageFormat::BMP },
76+ {" .png " , ImageFormat::PNG }
7177 };
7278
79+ std::unordered_map<std::string, ImageFormat> build_image_format_extension_lookup ()
80+ {
81+ std::unordered_map<std::string, ImageFormat> map;
82+
83+ for (auto const & entry : supported_image_formats)
84+ for (auto const & extension : entry.second .extensions )
85+ map.emplace (extension, entry.first );
86+
87+ return map;
88+ }
89+
90+ // TODO: Use heterogeneous/transparent lookups to avoid having to accept only std::string.
91+ std::optional<ImageFormat> find_image_format_by_extension (std::string const & extension)
92+ {
93+ static auto const lookup {build_image_format_extension_lookup ()};
94+
95+ auto match {lookup.find (extension)};
96+ if (match == lookup.end ())
97+ return std::nullopt ;
98+ return match->second ;
99+ }
100+
73101 bool is_valid_scale_method (VisVideoScaleMethod scale_method)
74102 {
75103 return scale_method == VISUAL_VIDEO_SCALE_NEAREST
@@ -227,10 +255,12 @@ namespace LV {
227255
228256 VideoPtr Video::create_from_stream (std::istream& input)
229257 {
230- for (auto entry : bitmap_load_map) {
231- auto image {entry.second (input)};
232- if (image) {
233- return image;
258+ for (auto entry : supported_image_formats) {
259+ if (entry.second .reader ) {
260+ auto image {entry.second .reader (input)};
261+ if (image) {
262+ return image;
263+ }
234264 }
235265 }
236266
@@ -298,8 +328,8 @@ namespace LV {
298328 auto extension {fs::path {path}.extension ()};
299329 auto extension_lower (to_lower_ascii (extension.string ()));
300330
301- auto entry {bitmap_format_extension_map. find (extension_lower)};
302- if (entry == bitmap_format_extension_map. end ()) {
331+ auto format { find_image_format_by_extension (extension_lower)};
332+ if (!format. has_value ()) {
303333 visual_log (VISUAL_LOG_ERROR, " Could not deduce format from filename (%s)" , path.c_str ());
304334 return false ;
305335 }
@@ -310,19 +340,24 @@ namespace LV {
310340 return false ;
311341 }
312342
313- return save_to_stream (output, entry-> second );
343+ return save_to_stream (output, format. value () );
314344 }
315345
316- bool Video::save_to_stream (std::ostream& output, std::string const & format) const
346+ bool Video::save_to_stream (std::ostream& output, ImageFormat format) const
317347 {
318- auto entry {bitmap_save_map.find (format)};
319- if (entry == bitmap_save_map.end ()) {
320- std::string format_str {format};
321- visual_log (VISUAL_LOG_ERROR, " Saving to %s format is not supported" , format_str.c_str ());
348+ auto entry {supported_image_formats.find (format)};
349+
350+ if (entry == supported_image_formats.end ()) {
351+ visual_log (VISUAL_LOG_ERROR, " Saving to unknown format (%d)." , static_cast <int > (format));
352+ return false ;
353+ }
354+
355+ if (!entry->second .writer ) {
356+ visual_log (VISUAL_LOG_ERROR, " Saving to %s is unsupported." , entry->second .name .c_str ());
322357 return false ;
323358 }
324359
325- return entry->second (*this , output);
360+ return entry->second . writer (*this , output);
326361 }
327362
328363 void Video::copy_attrs (VideoConstPtr const & src)
0 commit comments