X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=core%2Fproducer%2Fcolor%2Fcolor_producer.cpp;h=12f6ef21896d039e93a4c489f04f5793fad5704f;hb=b9f8a94b40e88ee27363dd04bd009e1e1869f20e;hp=a63cc8af102330cd282d85733a06de9c53407c15;hpb=474909e14ae3ae6da171a5871c6192a982962a6f;p=casparcg diff --git a/core/producer/color/color_producer.cpp b/core/producer/color/color_producer.cpp index a63cc8af1..12f6ef218 100644 --- a/core/producer/color/color_producer.cpp +++ b/core/producer/color/color_producer.cpp @@ -19,7 +19,7 @@ * Author: Robert Nagy, ronag89@gmail.com */ -#include "../../stdafx.h" +#include "../../StdAfx.h" #include "color_producer.h" @@ -28,7 +28,10 @@ #include #include #include +#include #include +#include +#include #include #include @@ -38,29 +41,69 @@ #include namespace caspar { namespace core { - + +draw_frame create_color_frame(void* tag, const spl::shared_ptr& frame_factory, const std::vector& values) +{ + core::pixel_format_desc desc(pixel_format::bgra); + desc.planes.push_back(core::pixel_format_desc::plane(static_cast(values.size()), 1, 4)); + auto frame = frame_factory->create_frame(tag, desc, core::audio_channel_layout::invalid()); + + for (int i = 0; i < values.size(); ++i) + *reinterpret_cast(frame.image_data(0).begin() + (i * 4)) = values.at(i); + + return core::draw_frame(std::move(frame)); +} + +draw_frame create_color_frame(void* tag, const spl::shared_ptr& frame_factory, uint32_t value) +{ + std::vector values = { value }; + + return create_color_frame(tag, frame_factory, values); +} + +draw_frame create_color_frame(void* tag, const spl::shared_ptr& frame_factory, const std::vector& strs) +{ + std::vector values(strs.size()); + + for (int i = 0; i < values.size(); ++i) + { + if (!try_get_color(strs.at(i), values.at(i))) + CASPAR_THROW_EXCEPTION(user_error() << msg_info(L"Invalid color: " + strs.at(i))); + } + + return create_color_frame(tag, frame_factory, values); +} + class color_producer : public frame_producer_base { - monitor::basic_subject event_subject_; + monitor::subject monitor_subject_; const std::wstring color_str_; constraints constraints_; draw_frame frame_; public: - explicit color_producer(const spl::shared_ptr& frame_factory, const std::wstring& color) - : color_str_(color) + color_producer(const spl::shared_ptr& frame_factory, uint32_t value) + : color_str_(L"") , constraints_(1, 1) - , frame_(create_color_frame(this, frame_factory, color)) + , frame_(create_color_frame(this, frame_factory, value)) + { + CASPAR_LOG(info) << print() << L" Initialized"; + } + + color_producer(const spl::shared_ptr& frame_factory, const std::vector& colors) + : color_str_(boost::join(colors, L", ")) + , constraints_(static_cast(colors.size()), 1) + , frame_(create_color_frame(this, frame_factory, colors)) { CASPAR_LOG(info) << print() << L" Initialized"; } // frame_producer - + draw_frame receive_impl() override { - event_subject_ << monitor::event("color") % color_str_; + monitor_subject_ << monitor::message("color") % color_str_; return frame_; } @@ -69,7 +112,7 @@ public: { return constraints_; } - + std::wstring print() const override { return L"color[" + color_str_ + L"]"; @@ -79,7 +122,7 @@ public: { return L"color"; } - + boost::property_tree::wptree info() const override { boost::property_tree::wptree info; @@ -88,88 +131,136 @@ public: return info; } - void subscribe(const monitor::observable::observer_ptr& o) override - { - return event_subject_.subscribe(o); - } - - void unsubscribe(const monitor::observable::observer_ptr& o) override - { - return event_subject_.unsubscribe(o); - } + monitor::subject& monitor_output() override {return monitor_subject_;} }; std::wstring get_hex_color(const std::wstring& str) { if(str.at(0) == '#') return str.length() == 7 ? L"#FF" + str.substr(1) : str; - - if(boost::iequals(str, L"EMPTY")) + + std::wstring col_str = boost::to_upper_copy(str); + + if(col_str == L"EMPTY") return L"#00000000"; - if(boost::iequals(str, L"BLACK")) + if(col_str == L"BLACK") return L"#FF000000"; - - if(boost::iequals(str, L"WHITE")) + + if(col_str == L"WHITE") return L"#FFFFFFFF"; - - if(boost::iequals(str, L"RED")) + + if(col_str == L"RED") return L"#FFFF0000"; - - if(boost::iequals(str, L"GREEN")) + + if(col_str == L"GREEN") return L"#FF00FF00"; - - if(boost::iequals(str, L"BLUE")) - return L"#FF0000FF"; - - if(boost::iequals(str, L"ORANGE")) - return L"#FFFFA500"; - - if(boost::iequals(str, L"YELLOW")) + + if(col_str == L"BLUE") + return L"#FF0000FF"; + + if(col_str == L"ORANGE") + return L"#FFFFA500"; + + if(col_str == L"YELLOW") return L"#FFFFFF00"; - - if(boost::iequals(str, L"BROWN")) + + if(col_str == L"BROWN") return L"#FFA52A2A"; - - if(boost::iequals(str, L"GRAY")) + + if(col_str == L"GRAY") return L"#FF808080"; - - if(boost::iequals(str, L"TEAL")) + + if(col_str == L"TEAL") return L"#FF008080"; - + return str; } +bool try_get_color(const std::wstring& str, uint32_t& value) +{ + auto color_str = get_hex_color(str); + if(color_str.length() != 9 || color_str[0] != '#') + return false; + + std::wstringstream ss(color_str.substr(1)); + if(!(ss >> std::hex >> value) || !ss.eof()) + return false; + + return true; +} + +void describe_color_producer(core::help_sink& sink, const core::help_repository& repo) +{ + sink.short_description(L"Fills a layer with a solid color or a horizontal gradient."); + sink.syntax( + L"{#[argb_hex_value:string]}" + L",{#[rgb_hex_value:string]}" + L",{[named_color:EMPTY,BLACK,WHITE,RED,GREEN,BLUE,ORANGE,YELLOW,BROWN,GRAY,TEAL]} " + L"{...more colors}"); + sink.para()->text(L"A producer that fills a layer with a solid color. If more than one color is specified it becomes a gradient between those colors."); + sink.para() + ->text(L"If a ")->code(L"#") + ->text(L" sign followed by an 8 character hexadecimal number is given it is interpreted as an 8-bit per channel ARGB color. ") + ->text(L"If it is instead followed by a 6 character hexadecimal number it is interpreted as an 8-bit per channel RGB value with an opaque alpha channel."); + sink.para()->text(L"There are also a number of predefined named colors, that are specified without a ")->code(L"#")->text(L" sign:"); + sink.definitions() + ->item(L"EMPTY", L"Predefined ARGB value #00000000") + ->item(L"BLACK", L"Predefined ARGB value #FF000000") + ->item(L"WHITE", L"Predefined ARGB value #FFFFFFFF") + ->item(L"RED", L"Predefined ARGB value #FFFF0000") + ->item(L"GREEN", L"Predefined ARGB value #FF00FF00") + ->item(L"BLUE", L"Predefined ARGB value #FF0000FF") + ->item(L"ORANGE", L"Predefined ARGB value #FFFFA500") + ->item(L"YELLOW", L"Predefined ARGB value #FFFFFF00") + ->item(L"BROWN", L"Predefined ARGB value #FFA52A2A") + ->item(L"GRAY", L"Predefined ARGB value #FF808080") + ->item(L"TEAL", L"Predefined ARGB value #FF008080"); + sink.para() + ->strong(L"Note")->text(L" that it is important that all RGB values are multiplied with the alpha ") + ->text(L"at all times, otherwise the compositing in the mixer will be incorrect."); + sink.para()->text(L"Solid color examples:"); + sink.example(L"PLAY 1-10 EMPTY", L"For a completely transparent frame."); + sink.example(L"PLAY 1-10 #00000000", L"For an explicitly defined completely transparent frame."); + sink.example(L"PLAY 1-10 #000000", L"For an explicitly defined completely opaque black frame."); + sink.example(L"PLAY 1-10 RED", L"For a completely red frame."); + sink.example(L"PLAY 1-10 #7F007F00", + L"For a completely green half transparent frame. " + L"Since the RGB part has been premultiplied with the A part this is 100% green."); + sink.para()->text(L"Horizontal gradient examples:"); + sink.example(L"PLAY 1-10 WHITE BLACK", L"For a gradient between white and black."); + sink.example(L"PLAY 1-10 WHITE WHITE WHITE BLACK", L"For a gradient between white and black with the white part beings 3 times as long as the black part."); + sink.example( + L"PLAY 1-10 RED EMPTY\n" + L"MIXER 1-10 ANCHOR 0.5 0.5\n" + L"MIXER 1-10 FILL 0.5 0.5 2 2\n" + L"MIXER 1-10 ROTATION 45", + L"For a 45 degree gradient covering the screen."); +} + +spl::shared_ptr create_color_producer(const spl::shared_ptr& frame_factory, uint32_t value) +{ + return spl::make_shared(frame_factory, value); +} + spl::shared_ptr create_color_producer(const spl::shared_ptr& frame_factory, const std::vector& params) { if(params.size() < 0) return core::frame_producer::empty(); - auto color2 = get_hex_color(params[0]); - if(color2.length() != 9 || color2[0] != '#') + uint32_t value = 0; + if(!try_get_color(params.at(0), value)) return core::frame_producer::empty(); - return spl::make_shared(frame_factory, color2); -} + std::vector colors; -draw_frame create_color_frame(void* tag, const spl::shared_ptr& frame_factory, const std::wstring& color) -{ - auto color2 = get_hex_color(color); - if(color2.length() != 9 || color2[0] != '#') - CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("color") << arg_value_info(color2) << msg_info("Invalid color.")); - - core::pixel_format_desc desc(pixel_format::bgra); - desc.planes.push_back(core::pixel_format_desc::plane(1, 1, 4)); - auto frame = frame_factory->create_frame(tag, desc); - - // Read color from hex-string and write to frame pixel. - - auto& value = *reinterpret_cast(frame.image_data(0).begin()); - std::wstringstream str(color2.substr(1)); - if(!(str >> std::hex >> value) || !str.eof()) - CASPAR_THROW_EXCEPTION(invalid_argument() << arg_name_info("color") << arg_value_info(color2) << msg_info("Invalid color.")); - - return core::draw_frame(std::move(frame)); + for (auto& param : params) + { + if (try_get_color(param, value)) + colors.push_back(param); + } + + return spl::make_shared(frame_factory, colors); } -}} \ No newline at end of file +}}