From 8edb46702b372b6e672d0ac8f810e151e1aa5707 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 20 Mar 2025 21:02:55 +0100 Subject: Read/write subtitle variable Z. --- src/text.cc | 17 +++++++++++++++ src/text.h | 13 ++++++++++++ src/text_asset.cc | 52 +++++++++++++++++++++++++++++++++++++++++++++- src/text_asset.h | 5 +++++ src/text_asset_internal.cc | 46 +++++++++++++++++++++++++++++++++++++--- src/text_asset_internal.h | 36 ++++++++++++++++++++++++++++++-- src/text_image.cc | 8 +++++-- src/text_image.h | 2 ++ src/text_string.cc | 8 ++++--- src/text_string.h | 2 ++ 10 files changed, 178 insertions(+), 11 deletions(-) (limited to 'src') 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 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 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 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; +} + diff --git a/src/text.h b/src/text.h index 70dfa3a6..f3b6ecea 100644 --- a/src/text.h +++ b/src/text.h @@ -97,6 +97,10 @@ public: int64_t duration; }; + std::vector 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 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 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 _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(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 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(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& 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 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( 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 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( @@ -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(i)) { text.reset (); subtitle->children.push_back ( - make_shared(subtitle, ii->id(), ii->png_image(), ii->h_align(), ii->h_position(), ii->v_align(), ii->v_position(), ii->z_position()) + make_shared( + 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 @@ -156,6 +157,7 @@ protected: boost::optional v_position; boost::optional v_align; boost::optional z_position; + boost::optional variable_z; boost::optional direction; boost::optional