diff options
| author | Carl Hetherington <cth@carlh.net> | 2025-03-20 21:02:55 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2025-03-24 00:29:31 +0100 |
| commit | 8edb46702b372b6e672d0ac8f810e151e1aa5707 (patch) | |
| tree | e2a458fc456b3bd98982e6e31c0ec7589ab25274 /src | |
| parent | 0322c4604bf79c11a99dcd929a6f74685a0a4e31 (diff) | |
Read/write subtitle variable Z.v1.10.16
Diffstat (limited to 'src')
| -rw-r--r-- | src/text.cc | 17 | ||||
| -rw-r--r-- | src/text.h | 13 | ||||
| -rw-r--r-- | src/text_asset.cc | 52 | ||||
| -rw-r--r-- | src/text_asset.h | 5 | ||||
| -rw-r--r-- | src/text_asset_internal.cc | 46 | ||||
| -rw-r--r-- | src/text_asset_internal.h | 36 | ||||
| -rw-r--r-- | src/text_image.cc | 8 | ||||
| -rw-r--r-- | src/text_image.h | 2 | ||||
| -rw-r--r-- | src/text_string.cc | 8 | ||||
| -rw-r--r-- | src/text_string.h | 2 |
10 files changed, 178 insertions, 11 deletions
diff --git a/src/text.cc b/src/text.cc index 158af38c..8f72b953 100644 --- a/src/text.cc +++ b/src/text.cc @@ -44,6 +44,9 @@ using std::shared_ptr; +using std::string; +using std::vector; +using boost::optional; using namespace dcp; @@ -56,6 +59,7 @@ Text::Text( float v_position, VAlign v_align, float z_position, + vector<VariableZPosition> variable_z_positions, Time fade_up_time, Time fade_down_time ) @@ -66,6 +70,7 @@ Text::Text( , _v_position (v_position) , _v_align (v_align) , _z_position(z_position) + , _variable_z_positions(variable_z_positions) , _fade_up_time (fade_up_time) , _fade_down_time (fade_down_time) { @@ -117,6 +122,11 @@ Text::equals(shared_ptr<const Text> other, EqualityOptions const& options, NoteH same = false; } + if (variable_z_positions() != other->variable_z_positions()) { + note(NoteType::ERROR, "text variable Z positions differ"); + same = false; + } + if (fade_up_time() != other->fade_up_time()) { note(NoteType::ERROR, "text fade-up times differ"); same = false; @@ -129,3 +139,10 @@ Text::equals(shared_ptr<const Text> other, EqualityOptions const& options, NoteH return same; } + + +bool dcp::operator==(Text::VariableZPosition a, Text::VariableZPosition b) +{ + return a.position == b.position && a.duration == b.duration; +} + @@ -97,6 +97,10 @@ public: int64_t duration; }; + std::vector<VariableZPosition> variable_z_positions() const { + return _variable_z_positions; + } + Time fade_up_time () const { return _fade_up_time; } @@ -128,6 +132,10 @@ public: _z_position = z; } + void set_variable_z_positions(std::vector<VariableZPosition> z) { + _variable_z_positions = std::move(z); + } + void set_fade_up_time (Time t) { _fade_up_time = t; } @@ -148,6 +156,7 @@ protected: float v_position, VAlign v_align, float z_position, + std::vector<VariableZPosition> variable_z, Time fade_up_time, Time fade_down_time ); @@ -165,11 +174,15 @@ protected: float _v_position = 0; VAlign _v_align = VAlign::CENTER; float _z_position = 0; + std::vector<VariableZPosition> _variable_z_positions; Time _fade_up_time; Time _fade_down_time; }; +bool operator==(Text::VariableZPosition a, Text::VariableZPosition b); + + } diff --git a/src/text_asset.cc b/src/text_asset.cc index c3341452..41690d93 100644 --- a/src/text_asset.cc +++ b/src/text_asset.cc @@ -206,6 +206,10 @@ TextAsset::position_align(TextAsset::ParseState& ps, xmlpp::Element const * node if (auto zp = optional_number_attribute<float>(node, "Zposition")) { ps.z_position = zp.get() / 100; } + + if (auto variable_z = optional_string_attribute(node, "VariableZ")) { + ps.variable_z = *variable_z; + } } @@ -248,6 +252,14 @@ TextAsset::subtitle_node_state(xmlpp::Element const * node, optional<int> tcr) c ps.out = Time (string_attribute(node, "TimeOut"), tcr); ps.fade_up_time = fade_time (node, "FadeUpTime", tcr); ps.fade_down_time = fade_time (node, "FadeDownTime", tcr); + + for (auto child: node->get_children()) { + auto element = dynamic_cast<xmlpp::Element const*>(child); + if (element && element->get_name() == "LoadVariableZ") { + ps.load_variable_z.push_back(LoadVariableZ(element)); + } + } + return ps; } @@ -287,6 +299,8 @@ TextAsset::parse_texts(xmlpp::Element const * node, vector<ParseState>& state, o state.push_back (ParseState ()); } else if (node->get_name() == "Image") { state.push_back (image_node_state (node)); + } else if (node->get_name() == "LoadVariableZ") { + return; } else { throw XMLError ("unexpected node " + node->get_name()); } @@ -453,6 +467,9 @@ TextAsset::maybe_add_text( if (i.z_position) { ps.z_position = i.z_position.get(); } + if (i.variable_z) { + ps.variable_z = i.variable_z.get(); + } if (i.direction) { ps.direction = i.direction.get(); } @@ -471,6 +488,13 @@ TextAsset::maybe_add_text( if (i.type) { ps.type = i.type.get(); } + for (auto j: i.load_variable_z) { + /* j is a LoadVariableZ from this "sub" ParseState. See if we should add it to the end result */ + auto const k = std::find_if(ps.load_variable_z.begin(), ps.load_variable_z.end(), [j](LoadVariableZ const& z) { return j.id() == z.id(); }); + if (k == ps.load_variable_z.end()) { + ps.load_variable_z.push_back(j); + } + } } if (!ps.in || !ps.out) { @@ -482,6 +506,12 @@ TextAsset::maybe_add_text( switch (ps.type.get()) { case ParseState::Type::TEXT: + { + vector<Text::VariableZPosition> variable_z; + auto iter = std::find_if(ps.load_variable_z.begin(), ps.load_variable_z.end(), [&ps](LoadVariableZ const& z) { return z.id() == ps.variable_z; }); + if (iter != ps.load_variable_z.end()) { + variable_z = iter->positions(); + } _texts.push_back ( make_shared<TextString>( ps.font_id, @@ -498,6 +528,7 @@ TextAsset::maybe_add_text( ps.v_position.get_value_or(0), ps.v_align.get_value_or(VAlign::CENTER), ps.z_position.get_value_or(0), + variable_z, ps.direction.get_value_or (Direction::LTR), text, ps.effect.get_value_or (Effect::NONE), @@ -509,6 +540,7 @@ TextAsset::maybe_add_text( ) ); break; + } case ParseState::Type::IMAGE: { switch (standard) { @@ -530,6 +562,12 @@ TextAsset::maybe_add_text( break; } + vector<Text::VariableZPosition> variable_z; + auto iter = std::find_if(ps.load_variable_z.begin(), ps.load_variable_z.end(), [&ps](LoadVariableZ const& z) { return ps.variable_z && z.id() == *ps.variable_z; }); + if (iter != ps.load_variable_z.end()) { + variable_z = iter->positions(); + } + /* Add a text with no image data and we'll fill that in later */ _texts.push_back( make_shared<TextImage>( @@ -542,6 +580,7 @@ TextAsset::maybe_add_text( ps.v_position.get_value_or(0), ps.v_align.get_value_or(VAlign::CENTER), ps.z_position.get_value_or(0), + variable_z, ps.fade_up_time.get_value_or(Time()), ps.fade_down_time.get_value_or(Time()) ) @@ -747,6 +786,7 @@ TextAsset::texts_as_xml(xmlpp::Element* xml_root, int time_code_rate, Standard s float last_v_position; float last_z_position; Direction last_direction; + int load_variable_z_index = 1; for (auto i: sorted) { if (!subtitle || @@ -783,6 +823,7 @@ TextAsset::texts_as_xml(xmlpp::Element* xml_root, int time_code_rate, Standard s is->v_align(), is->v_position(), is->z_position(), + subtitle->find_or_add_variable_z_positions(is->variable_z_positions(), load_variable_z_index), is->direction(), is->rubies() ); @@ -802,7 +843,16 @@ TextAsset::texts_as_xml(xmlpp::Element* xml_root, int time_code_rate, Standard s if (auto ii = dynamic_pointer_cast<TextImage>(i)) { text.reset (); subtitle->children.push_back ( - make_shared<order::Image>(subtitle, ii->id(), ii->png_image(), ii->h_align(), ii->h_position(), ii->v_align(), ii->v_position(), ii->z_position()) + make_shared<order::Image>( + subtitle, ii->id(), + ii->png_image(), + ii->h_align(), + ii->h_position(), + ii->v_align(), + ii->v_position(), + ii->z_position(), + subtitle->find_or_add_variable_z_positions(ii->variable_z_positions(), load_variable_z_index) + ) ); } } diff --git a/src/text_asset.h b/src/text_asset.h index 4d739027..113896f8 100644 --- a/src/text_asset.h +++ b/src/text_asset.h @@ -44,6 +44,7 @@ #include "array_data.h" #include "asset.h" #include "dcp_time.h" +#include "load_variable_z.h" #include "subtitle_standard.h" #include "text_string.h" #include <libcxml/cxml.h> @@ -156,6 +157,7 @@ protected: boost::optional<float> v_position; boost::optional<VAlign> v_align; boost::optional<float> z_position; + boost::optional<std::string> variable_z; boost::optional<Direction> direction; boost::optional<Time> in; boost::optional<Time> out; @@ -167,6 +169,8 @@ protected: }; boost::optional<Type> type; float space_before = 0; + + std::vector<LoadVariableZ> load_variable_z; }; void parse_texts(xmlpp::Element const * node, std::vector<ParseState>& state, boost::optional<int> tcr, Standard standard); @@ -181,6 +185,7 @@ protected: /** All our texts, in no particular order */ std::vector<std::shared_ptr<Text>> _texts; + std::vector<LoadVariableZ> _load_variable_z; class Font { diff --git a/src/text_asset_internal.cc b/src/text_asset_internal.cc index 549bbec9..4ae5dbfe 100644 --- a/src/text_asset_internal.cc +++ b/src/text_asset_internal.cc @@ -44,9 +44,12 @@ #include <cmath> +using std::dynamic_pointer_cast; using std::string; using std::map; using std::shared_ptr; +using std::vector; +using boost::optional; using namespace dcp; @@ -166,7 +169,16 @@ order::Part::write_xml (xmlpp::Element* parent, order::Context& context) const static void -position_align (xmlpp::Element* e, order::Context& context, HAlign h_align, float h_position, VAlign v_align, float v_position, float z_position) +position_align( + xmlpp::Element* e, + order::Context& context, + HAlign h_align, + float h_position, + VAlign v_align, + float v_position, + float z_position, + optional<string> variable_z + ) { if (h_align != HAlign::CENTER) { if (context.standard == Standard::SMPTE) { @@ -207,6 +219,10 @@ position_align (xmlpp::Element* e, order::Context& context, HAlign h_align, floa if (fabs(z_position) > ALIGN_EPSILON && context.standard == Standard::SMPTE) { e->set_attribute("Zposition", fmt::format("{:.6}", z_position * 100)); } + + if (variable_z) { + e->set_attribute("VariableZ", *variable_z); + } } @@ -215,7 +231,7 @@ order::Text::as_xml (xmlpp::Element* parent, Context& context) const { auto e = cxml::add_child(parent, "Text"); - position_align(e, context, _h_align, _h_position, _v_align, _v_position, _z_position); + position_align(e, context, _h_align, _h_position, _v_align, _v_position, _z_position, _variable_z); /* Interop only supports "horizontal" or "vertical" for direction, so only write this for SMPTE. @@ -240,6 +256,24 @@ order::Text::as_xml (xmlpp::Element* parent, Context& context) const } +optional<string> +order::Subtitle::find_or_add_variable_z_positions(vector<dcp::Text::VariableZPosition> const& positions, int& load_variable_z_index) +{ + if (positions.empty()) { + return {}; + } + + auto iter = std::find_if(_load_variable_z.begin(), _load_variable_z.end(), [positions](LoadVariableZ const& load) { return positions == load.positions(); }); + if (iter == _load_variable_z.end()) { + auto const id = fmt::format("Zvector{}", load_variable_z_index++); + _load_variable_z.push_back(LoadVariableZ(id, positions)); + return id; + } + + return iter->id(); +} + + xmlpp::Element* order::Subtitle::as_xml (xmlpp::Element* parent, Context& context) const { @@ -254,6 +288,11 @@ order::Subtitle::as_xml (xmlpp::Element* parent, Context& context) const e->set_attribute("FadeUpTime", fmt::to_string(_fade_up.as_editable_units_ceil(context.time_code_rate))); e->set_attribute("FadeDownTime", fmt::to_string(_fade_down.as_editable_units_ceil(context.time_code_rate))); } + + for (auto const& vz: _load_variable_z) { + vz.as_xml(cxml::add_child(e, "LoadVariableZ")); + } + return e; } @@ -277,7 +316,7 @@ order::Image::as_xml (xmlpp::Element* parent, Context& context) const { auto e = cxml::add_child(parent, "Image"); - position_align(e, context, _h_align, _h_position, _v_align, _v_position, _z_position); + position_align(e, context, _h_align, _h_position, _v_align, _v_position, _z_position, _variable_z); if (context.standard == Standard::SMPTE) { e->add_child_text ("urn:uuid:" + _id); } else { @@ -286,3 +325,4 @@ order::Image::as_xml (xmlpp::Element* parent, Context& context) const return e; } + diff --git a/src/text_asset_internal.h b/src/text_asset_internal.h index ddbc8833..2dfccce9 100644 --- a/src/text_asset_internal.h +++ b/src/text_asset_internal.h @@ -44,6 +44,7 @@ #include "array_data.h" #include "dcp_time.h" #include "h_align.h" +#include "load_variable_z.h" #include "raw_convert.h" #include "v_align.h" #include "warnings.h" @@ -146,25 +147,41 @@ private: class Text : public Part { public: - Text(std::shared_ptr<Part> parent, HAlign h_align, float h_position, VAlign v_align, float v_position, float z_position, Direction direction, std::vector<Ruby> rubies) + Text( + std::shared_ptr<Part> parent, + HAlign h_align, + float h_position, + VAlign v_align, + float v_position, + float z_position, + boost::optional<std::string> variable_z, + Direction direction, + std::vector<Ruby> rubies + ) : Part (parent) , _h_align (h_align) , _h_position (h_position) , _v_align (v_align) , _v_position (v_position) , _z_position(z_position) + , _variable_z(variable_z) , _direction (direction) , _rubies(rubies) {} xmlpp::Element* as_xml (xmlpp::Element* parent, Context& context) const override; + boost::optional<std::string> variable_z() { + return _variable_z; + } + private: HAlign _h_align; float _h_position; VAlign _v_align; float _v_position; float _z_position; + boost::optional<std::string> _variable_z; Direction _direction; std::vector<Ruby> _rubies; }; @@ -181,6 +198,8 @@ public: , _fade_down (fade_down) {} + boost::optional<std::string> find_or_add_variable_z_positions(std::vector<dcp::Text::VariableZPosition> const& positions, int& load_variable_z_index); + xmlpp::Element* as_xml (xmlpp::Element* parent, Context& context) const override; private: @@ -188,13 +207,24 @@ private: Time _out; Time _fade_up; Time _fade_down; + std::vector<LoadVariableZ> _load_variable_z; }; class Image : public Part { public: - Image (std::shared_ptr<Part> parent, std::string id, ArrayData png_data, HAlign h_align, float h_position, VAlign v_align, float v_position, float z_position) + Image( + std::shared_ptr<Part> parent, + std::string id, + ArrayData png_data, + HAlign h_align, + float h_position, + VAlign v_align, + float v_position, + float z_position, + boost::optional<std::string> variable_z + ) : Part (parent) , _png_data (png_data) , _id (id) @@ -203,6 +233,7 @@ public: , _v_align (v_align) , _v_position (v_position) , _z_position(z_position) + , _variable_z(variable_z) {} xmlpp::Element* as_xml (xmlpp::Element* parent, Context& context) const override; @@ -215,6 +246,7 @@ private: VAlign _v_align; float _v_position; float _z_position; + boost::optional<std::string> _variable_z; }; diff --git a/src/text_image.cc b/src/text_image.cc index 7a6c4222..119a6301 100644 --- a/src/text_image.cc +++ b/src/text_image.cc @@ -47,6 +47,8 @@ using std::dynamic_pointer_cast; using std::ostream; using std::shared_ptr; using std::string; +using std::vector; +using boost::optional; using namespace dcp; @@ -59,10 +61,11 @@ TextImage::TextImage( float v_position, VAlign v_align, float z_position, + vector<VariableZPosition> variable_z_positions, Time fade_up_time, Time fade_down_time ) - : Text(in, out, h_position, h_align, v_position, v_align, z_position, fade_up_time, fade_down_time) + : Text(in, out, h_position, h_align, v_position, v_align, z_position, variable_z_positions, fade_up_time, fade_down_time) , _png_image (png_image) , _id (make_uuid ()) { @@ -80,10 +83,11 @@ TextImage::TextImage( float v_position, VAlign v_align, float z_position, + vector<VariableZPosition> variable_z_positions, Time fade_up_time, Time fade_down_time ) - : Text(in, out, h_position, h_align, v_position, v_align, z_position, fade_up_time, fade_down_time) + : Text(in, out, h_position, h_align, v_position, v_align, z_position, variable_z_positions, fade_up_time, fade_down_time) , _png_image (png_image) , _id (id) { diff --git a/src/text_image.h b/src/text_image.h index 1f1e464e..5b78f380 100644 --- a/src/text_image.h +++ b/src/text_image.h @@ -66,6 +66,7 @@ public: float v_position, VAlign v_align, float z_position, + std::vector<VariableZPosition> variable_z_positions, Time fade_up_time, Time fade_down_time ); @@ -80,6 +81,7 @@ public: float v_position, VAlign v_align, float z_position, + std::vector<VariableZPosition> variable_z_positions, Time fade_up_time, Time fade_down_time ); diff --git a/src/text_string.cc b/src/text_string.cc index 32f9e4ed..12e86fce 100644 --- a/src/text_string.cc +++ b/src/text_string.cc @@ -69,6 +69,7 @@ TextString::TextString( float v_position, VAlign v_align, float z_position, + vector<VariableZPosition> variable_z_positions, Direction direction, string text, Effect effect, @@ -78,7 +79,7 @@ TextString::TextString( float space_before, vector<Ruby> rubies ) - : Text(in, out, h_position, h_align, v_position, v_align, z_position, fade_up_time, fade_down_time) + : Text(in, out, h_position, h_align, v_position, v_align, z_position, variable_z_positions, fade_up_time, fade_down_time) , _font (font) , _italic (italic) , _bold (bold) @@ -127,6 +128,7 @@ dcp::operator==(TextString const & a, TextString const & b) a.v_position() == b.v_position() && a.v_align() == b.v_align() && a.z_position() == b.z_position() && + a.variable_z_positions() == b.variable_z_positions() && a.direction() == b.direction() && a.text() == b.text() && a.effect() == b.effect() && @@ -173,8 +175,8 @@ dcp::operator<<(ostream& s, TextString const & sub) << ", colour (" << sub.colour().r << ", " << sub.colour().g << ", " << sub.colour().b << ")" << ", vpos " << sub.v_position() << ", valign " << ((int) sub.v_align()) << ", hpos " << sub.h_position() << ", halign " << ((int) sub.h_align()) - << ", zpos " << sub.z_position() - << ", direction " << ((int) sub.direction()) + << ", zpos " << sub.z_position(); + s << ", direction " << ((int) sub.direction()) << ", effect " << ((int) sub.effect()) << ", effect colour (" << sub.effect_colour().r << ", " << sub.effect_colour().g << ", " << sub.effect_colour().b << ")" << ", space before " << sub.space_before(); diff --git a/src/text_string.h b/src/text_string.h index f532bafe..78788786 100644 --- a/src/text_string.h +++ b/src/text_string.h @@ -72,6 +72,7 @@ public: * @param v_align Vertical alignment point * @param z_position Z position as a proportion of the primary picture width between -1 and +1; * +ve moves the image away from the viewer, -ve moves it toward the viewer, 0 is in the plane of the screen. + * @param variable_z_positions List of variable Z positions for this text (or empty). * @param direction Direction of text * @param text The text to display * @param effect Effect to use @@ -95,6 +96,7 @@ public: float v_position, VAlign v_align, float z_position, + std::vector<VariableZPosition> variable_z_positions, Direction direction, std::string text, Effect effect, |
