#include "producer/image_producer.h"
#include "producer/image_scroll_producer.h"
#include "consumer/image_consumer.h"
+#include "util/image_loader.h"
#include <core/producer/frame_producer.h>
#include <core/consumer/frame_consumer.h>
#include <common/utf.h>
#include <boost/property_tree/ptree.hpp>
+#include <boost/algorithm/string/case_conv.hpp>
#include <FreeImage.h>
dependencies.consumer_registry->register_consumer_factory(L"Image Consumer", create_consumer, describe_consumer);
dependencies.media_info_repo->register_extractor([](const std::wstring& file, const std::wstring& extension, core::media_info& info)
{
- if (extension == L".TGA"
- || extension == L".COL"
- || extension == L".PNG"
- || extension == L".JPEG"
- || extension == L".JPG"
- || extension == L".GIF"
- || extension == L".BMP")
+ if (supported_extensions().find(boost::to_lower_copy(extension)) != supported_extensions().end())
{
info.clip_type = L"STILL";
{
auto bitmap = load_image(filename);
FreeImage_FlipVertical(bitmap.get());
-
+
core::pixel_format_desc desc = core::pixel_format::bgra;
auto width = FreeImage_GetWidth(bitmap.get());
auto height = FreeImage_GetHeight(bitmap.get());
FreeImage_GetBits(bitmap.get()),
frame.image_data(0).size(),
frame.image_data(0).begin());
-
+
return std::make_pair(
core::draw_frame(std::move(frame)),
core::constraints(width, height));
}
struct image_producer : public core::frame_producer_base
-{
+{
core::monitor::subject monitor_subject_;
const std::wstring description_;
const spl::shared_ptr<core::frame_factory> frame_factory_;
const uint32_t length_;
core::draw_frame frame_ = core::draw_frame::empty();
core::constraints constraints_;
-
+
image_producer(const spl::shared_ptr<core::frame_factory>& frame_factory, const std::wstring& description, bool thumbnail_mode, uint32_t length)
: description_(description)
, frame_factory_(frame_factory)
desc.format = core::pixel_format::bgra;
desc.planes.push_back(core::pixel_format_desc::plane(FreeImage_GetWidth(bitmap.get()), FreeImage_GetHeight(bitmap.get()), 4));
auto frame = frame_factory_->create_frame(this, desc, core::audio_channel_layout::invalid());
-
+
std::copy_n(FreeImage_GetBits(bitmap.get()), frame.image_data().size(), frame.image_data().begin());
frame_ = core::draw_frame(std::move(frame));
constraints_.width.set(FreeImage_GetWidth(bitmap.get()));
constraints_.height.set(FreeImage_GetHeight(bitmap.get()));
}
-
+
// frame_producer
core::draw_frame receive_impl() override
{
return constraints_;
}
-
+
std::wstring print() const override
{
return L"image_producer[" + description_ + L"]";
return info;
}
- core::monitor::subject& monitor_output()
+ core::monitor::subject& monitor_output()
{
return monitor_subject_;
}
L">> LOADBG 1-10 EMPTY MIX 20 AUTO\n", L"Plays a slide show of 3 images for 100 frames each and fades to black.");
}
-static const auto g_extensions = {
- L".png",
- L".tga",
- L".bmp",
- L".jpg",
- L".jpeg",
- L".gif",
- L".tiff",
- L".tif",
- L".jp2",
- L".jpx",
- L".j2k",
- L".j2c"
-};
-
spl::shared_ptr<core::frame_producer> create_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
{
auto length = get_param(L"LENGTH", params, std::numeric_limits<uint32_t>::max());
auto extension = it->path().extension().wstring();
- if (std::find_if(g_extensions.begin(), g_extensions.end(), ieq(extension)) == g_extensions.end())
+ if (std::find_if(supported_extensions().begin(), supported_extensions().end(), ieq(extension)) == supported_extensions().end())
continue;
files.insert(it->path().wstring());
std::wstring filename = env::media_folder() + params.at(0);
- auto ext = std::find_if(g_extensions.begin(), g_extensions.end(), [&](const std::wstring& ex) -> bool
+ auto ext = std::find_if(supported_extensions().begin(), supported_extensions().end(), [&](const std::wstring& ex) -> bool
{
auto file = caspar::find_case_insensitive(boost::filesystem::path(filename).wstring() + ex);
return static_cast<bool>(file);
});
- if(ext == g_extensions.end())
+ if(ext == supported_extensions().end())
return core::frame_producer::empty();
return spl::make_shared<image_producer>(dependencies.frame_factory, *caspar::find_case_insensitive(filename + *ext), false, length);
{
std::wstring filename = env::media_folder() + media_file;
- auto ext = std::find_if(g_extensions.begin(), g_extensions.end(), [&](const std::wstring& ex) -> bool
+ auto ext = std::find_if(supported_extensions().begin(), supported_extensions().end(), [&](const std::wstring& ex) -> bool
{
auto file = caspar::find_case_insensitive(boost::filesystem::path(filename).wstring() + ex);
return static_cast<bool>(file);
});
- if (ext == g_extensions.end())
+ if (ext == supported_extensions().end())
return core::draw_frame::empty();
spl::shared_ptr<core::frame_producer> producer = spl::make_shared<image_producer>(
*caspar::find_case_insensitive(filename + *ext),
true,
1);
-
+
return producer->receive();
}
#include <cstdint>
namespace caspar { namespace image {
-
+
// Like tweened_transform but for speed
class speed_tweener
{
return fetch();
}
};
-
+
struct image_scroll_producer : public core::frame_producer_base
-{
+{
core::monitor::subject monitor_subject_;
const std::wstring filename_;
int start_offset_x_ = 0;
int start_offset_y_ = 0;
bool progressive_;
-
+
explicit image_scroll_producer(
const spl::shared_ptr<core::frame_factory>& frame_factory,
const core::video_format_desc& format_desc,
auto frame = frame_factory->create_frame(this, desc, core::audio_channel_layout::invalid());
if(count >= frame.image_data(0).size())
- {
+ {
std::copy_n(bytes + count - frame.image_data(0).size(), frame.image_data(0).size(), frame.image_data(0).begin());
count -= static_cast<int>(frame.image_data(0).size());
}
else
{
- memset(frame.image_data(0).begin(), 0, frame.image_data(0).size());
+ memset(frame.image_data(0).begin(), 0, frame.image_data(0).size());
std::copy_n(bytes, count, frame.image_data(0).begin() + format_desc_.size - count);
count = 0;
}
desc.planes.push_back(core::pixel_format_desc::plane(format_desc_.width, height_, 4));
auto frame = frame_factory->create_frame(this, desc, core::audio_channel_layout::invalid());
if(count >= frame.image_data(0).size())
- {
+ {
for(int y = 0; y < height_; ++y)
std::copy_n(bytes + i * format_desc_.width*4 + y * width_*4, format_desc_.width*4, frame.image_data(0).begin() + y * format_desc_.width*4);
-
+
++i;
count -= static_cast<int>(frame.image_data(0).size());
}
else
{
- memset(frame.image_data(0).begin(), 0, frame.image_data(0).size());
+ memset(frame.image_data(0).begin(), 0, frame.image_data(0).size());
auto width2 = width_ % format_desc_.width;
for(int y = 0; y < height_; ++y)
std::copy_n(bytes + i * format_desc_.width*4 + y * width_*4, width2*4, frame.image_data(0).begin() + y * format_desc_.width*4);
count = 0;
}
-
+
frames_.push_back(core::draw_frame(std::move(frame)));
}
return std::move(result);
}
-
+
// frame_producer
core::draw_frame render_frame(bool allow_eof)
{
if(frames_.empty())
return core::draw_frame::empty();
-
+
core::draw_frame result(get_visible());
auto& fill_translation = result.transform().image_transform.fill_translation;
if (static_cast<size_t>(std::abs(delta_)) >= height_ + format_desc_.height && allow_eof)
return core::draw_frame::empty();
- fill_translation[1] =
+ fill_translation[1] =
static_cast<double>(start_offset_y_) / static_cast<double>(format_desc_.height)
+ delta_ / static_cast<double>(format_desc_.height);
}
if (static_cast<size_t>(std::abs(delta_)) >= width_ + format_desc_.width && allow_eof)
return core::draw_frame::empty();
- fill_translation[0] =
+ fill_translation[0] =
static_cast<double>(start_offset_x_) / static_cast<double>(format_desc_.width)
+ (delta_) / static_cast<double>(format_desc_.width);
}
result = core::draw_frame::interlace(field1, field2, format_desc_.field_mode);
}
-
+
monitor_subject_ << core::monitor::message("/file/path") % filename_
- << core::monitor::message("/delta") % delta_
+ << core::monitor::message("/delta") % delta_
<< core::monitor::message("/speed") % speed_.fetch();
return result;
{
return constraints_;
}
-
+
std::wstring print() const override
{
return L"image_scroll_producer[" + filename_ + L"]";
spl::shared_ptr<core::frame_producer> create_scroll_producer(const core::frame_producer_dependencies& dependencies, const std::vector<std::wstring>& params)
{
- static const auto extensions = {
- L".png",
- L".tga",
- L".bmp",
- L".jpg",
- L".jpeg",
- L".gif",
- L".tiff",
- L".tif",
- L".jp2",
- L".jpx",
- L".j2k",
- L".j2c"
- };
std::wstring filename = env::media_folder() + params.at(0);
-
- auto ext = std::find_if(extensions.begin(), extensions.end(), [&](const std::wstring& ex) -> bool
+
+ auto ext = std::find_if(supported_extensions().begin(), supported_extensions().end(), [&](const std::wstring& ex) -> bool
{
auto file = caspar::find_case_insensitive(boost::filesystem::path(filename).replace_extension(ex).wstring());
return static_cast<bool>(file);
});
- if(ext == extensions.end())
+ if(ext == supported_extensions().end())
return core::frame_producer::empty();
-
+
double duration = 0.0;
double speed = get_param(L"SPEED", params, 0.0);
boost::optional<boost::posix_time::ptime> end_time;
fif = FreeImage_GetFIFFromFilename(u8(filename).c_str());
#endif
- if(fif == FIF_UNKNOWN || !FreeImage_FIFSupportsReading(fif))
+ if(fif == FIF_UNKNOWN || !FreeImage_FIFSupportsReading(fif))
CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("Unsupported image format."));
-
+
#ifdef WIN32
auto bitmap = std::shared_ptr<FIBITMAP>(FreeImage_LoadU(fif, filename.c_str(), 0), FreeImage_Unload);
#else
auto bitmap = std::shared_ptr<FIBITMAP>(FreeImage_Load(fif, u8(filename).c_str(), 0), FreeImage_Unload);
#endif
-
+
if(FreeImage_GetBPP(bitmap.get()) != 32)
{
bitmap = std::shared_ptr<FIBITMAP>(FreeImage_ConvertTo32Bits(bitmap.get()), FreeImage_Unload);
if(!bitmap)
- CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("Unsupported image format."));
+ CASPAR_THROW_EXCEPTION(invalid_argument() << msg_info("Unsupported image format."));
}
//PNG-images need to be premultiplied with their alpha
image_view<bgra_pixel> original_view(FreeImage_GetBits(bitmap.get()), FreeImage_GetWidth(bitmap.get()), FreeImage_GetHeight(bitmap.get()));
premultiply(original_view);
}
-
+
return bitmap;
}
return bitmap;
}
+const std::set<std::wstring>& supported_extensions()
+{
+ static const std::set<std::wstring> extensions =
+ {
+ L".png",
+ L".tga",
+ L".bmp",
+ L".jpg",
+ L".jpeg",
+ L".gif",
+ L".tiff",
+ L".tif",
+ L".jp2",
+ L".jpx",
+ L".j2k",
+ L".j2c"
+ };
+
+ return extensions;
+}
+
}}
#include <memory>
#include <string>
+#include <set>
namespace caspar { namespace image {
std::shared_ptr<FIBITMAP> load_image(const std::wstring& filename);
std::shared_ptr<FIBITMAP> load_png_from_memory(const void* memory_location, size_t size);
+const std::set<std::wstring>& supported_extensions();
}}