diff options
| author | Carl Hetherington <cth@carlh.net> | 2024-05-22 23:29:58 +0200 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2024-05-22 23:30:01 +0200 |
| commit | 43d18fd59efb58004daa68f0161277efc423deef (patch) | |
| tree | d76356c3d908ba4fdf76a22c9f697ff46f55133c | |
| parent | affaca1e5bc1c4dfdd7f2bd0f0dbbd9ec825b157 (diff) | |
Support MarginL and MarginR in SSA subtitles (DoM #2811).v1.6.49
| -rw-r--r-- | src/ssa_reader.cc | 50 | ||||
| -rw-r--r-- | src/ssa_reader.h | 8 | ||||
| -rw-r--r-- | test/data/horizontal_margin.ssa | 23 | ||||
| -rw-r--r-- | test/ssa_reader_test.cc | 46 |
4 files changed, 119 insertions, 8 deletions
diff --git a/src/ssa_reader.cc b/src/ssa_reader.cc index 262bba7..1302b6b 100644 --- a/src/ssa_reader.cc +++ b/src/ssa_reader.cc @@ -149,6 +149,10 @@ public: } } else if (keys[i] == "MarginV") { vertical_margin = raw_convert<int> (style[i]); + } else if (keys[i] == "MarginL") { + left_margin = raw_convert<int>(style[i]); + } else if (keys[i] == "MarginR") { + right_margin = raw_convert<int>(style[i]); } } } @@ -166,6 +170,8 @@ public: HorizontalReference horizontal_reference; VerticalReference vertical_reference; int vertical_margin; + int left_margin = 0; + int right_margin = 0; private: Colour colour (string c) const @@ -185,6 +191,24 @@ private: } }; + +void +SSAReader::Context::update_horizontal_position(RawSubtitle& sub) const +{ + switch (sub.horizontal_position.reference) { + case LEFT_OF_SCREEN: + sub.horizontal_position.proportional = static_cast<float>(left_margin) / play_res_x; + break; + case HORIZONTAL_CENTRE_OF_SCREEN: + sub.horizontal_position.proportional = static_cast<float>(left_margin - right_margin) / (2 * play_res_x); + break; + case RIGHT_OF_SCREEN: + sub.horizontal_position.proportional = static_cast<float>(right_margin) / play_res_x; + break; + } +} + + Time SSAReader::parse_time (string t) const { @@ -218,30 +242,39 @@ SSAReader::parse_tag(RawSubtitle& sub, string tag, Context const& context) } else if (tag == "\\an1") { sub.horizontal_position.reference = sub::LEFT_OF_SCREEN; sub.vertical_position.reference = sub::BOTTOM_OF_SCREEN; + context.update_horizontal_position(sub); } else if (tag == "\\an2") { sub.horizontal_position.reference = sub::HORIZONTAL_CENTRE_OF_SCREEN; sub.vertical_position.reference = sub::BOTTOM_OF_SCREEN; + context.update_horizontal_position(sub); } else if (tag == "\\an3") { sub.horizontal_position.reference = sub::RIGHT_OF_SCREEN; sub.vertical_position.reference = sub::BOTTOM_OF_SCREEN; + context.update_horizontal_position(sub); } else if (tag == "\\an4") { sub.horizontal_position.reference = sub::LEFT_OF_SCREEN; sub.vertical_position.reference = sub::VERTICAL_CENTRE_OF_SCREEN; + context.update_horizontal_position(sub); } else if (tag == "\\an5") { sub.horizontal_position.reference = sub::HORIZONTAL_CENTRE_OF_SCREEN; sub.vertical_position.reference = sub::VERTICAL_CENTRE_OF_SCREEN; + context.update_horizontal_position(sub); } else if (tag == "\\an6") { sub.horizontal_position.reference = sub::RIGHT_OF_SCREEN; sub.vertical_position.reference = sub::VERTICAL_CENTRE_OF_SCREEN; + context.update_horizontal_position(sub); } else if (tag == "\\an7") { sub.horizontal_position.reference = sub::LEFT_OF_SCREEN; sub.vertical_position.reference = sub::TOP_OF_SCREEN; + context.update_horizontal_position(sub); } else if (tag == "\\an8") { sub.horizontal_position.reference = sub::HORIZONTAL_CENTRE_OF_SCREEN; sub.vertical_position.reference = sub::TOP_OF_SCREEN; + context.update_horizontal_position(sub); } else if (tag == "\\an9") { sub.horizontal_position.reference = sub::RIGHT_OF_SCREEN; sub.vertical_position.reference = sub::TOP_OF_SCREEN; + context.update_horizontal_position(sub); } else if (boost::starts_with(tag, "\\pos")) { vector<string> bits; boost::algorithm::split (bits, tag, boost::is_any_of("(,")); @@ -293,6 +326,8 @@ SSAReader::parse_line(RawSubtitle base, string line, Context const& context) */ current.vertical_position.proportional = 0; + context.update_horizontal_position(current); + /* We must have a font size, as there could be a margin specified in pixels and in that case we must know how big the subtitle lines are to work out the position on screen. @@ -477,6 +512,8 @@ SSAReader::read (function<optional<string> ()> get_line) RawSubtitle sub; optional<Style> style; + int left_margin = 0; + int right_margin = 0; for (size_t i = 0; i < event.size(); ++i) { trim (event[i]); @@ -512,13 +549,24 @@ SSAReader::read (function<optional<string> ()> get_line) if (sub.vertical_position.reference != sub::VERTICAL_CENTRE_OF_SCREEN) { sub.vertical_position.proportional = float(style->vertical_margin) / play_res_y; } + left_margin = style->left_margin; + right_margin = style->right_margin; } else if (event_format[i] == "MarginV") { if (event[i] != "0" && sub.vertical_position.reference != sub::VERTICAL_CENTRE_OF_SCREEN) { /* Override the style if its non-zero */ sub.vertical_position.proportional = raw_convert<float>(event[i]) / play_res_y; } + } else if (event_format[i] == "MarginL") { + if (event[i] != "0") { + left_margin = raw_convert<int>(event[i]); + } + } else if (event_format[i] == "MarginR") { + if (event[i] != "0") { + right_margin = raw_convert<int>(event[i]); + } } else if (event_format[i] == "Text") { - for (auto j: parse_line(sub, event[i], Context(play_res_x, play_res_y, style ? style->primary_colour : Colour(1, 1, 1)))) { + auto context = Context(play_res_x, play_res_y, style ? style->primary_colour : Colour(1, 1, 1), left_margin, right_margin); + for (auto j: parse_line(sub, event[i], context)) { _subs.push_back (j); } } diff --git a/src/ssa_reader.h b/src/ssa_reader.h index 5de660c..e8c2a52 100644 --- a/src/ssa_reader.h +++ b/src/ssa_reader.h @@ -44,15 +44,21 @@ public: class Context { public: - Context(int play_res_x_, int play_res_y_, Colour primary_colour_) + Context(int play_res_x_, int play_res_y_, Colour primary_colour_, int left_margin_ = 0, int right_margin_ = 0) : play_res_x(play_res_x_) , play_res_y(play_res_y_) , primary_colour(primary_colour_) + , left_margin(left_margin_) + , right_margin(right_margin_) {} int play_res_x; int play_res_y; Colour primary_colour; + int left_margin; + int right_margin; + + void update_horizontal_position(RawSubtitle& sub) const; }; static std::vector<RawSubtitle> parse_line(RawSubtitle base, std::string line, Context const& context); diff --git a/test/data/horizontal_margin.ssa b/test/data/horizontal_margin.ssa new file mode 100644 index 0000000..c5a9f9e --- /dev/null +++ b/test/data/horizontal_margin.ssa @@ -0,0 +1,23 @@ +[Script Info] +Title: libsub test +ScriptType: v4.00 +WrapStyle: 0 +ScaledBorderAndShadow: yes +PlayResX: 1920 +PlayResY: 1080 + +[V4 Styles] +Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding +Style: Default,Arial,20,16777215,255,0,0,0,0,1,2,2,2,200,100,10,0,1 + +[Fonts] + +[Graphics] + +[Events] +Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text +Dialogue: Marked=0,0:00:01.23,0:00:04.55,Default,,100,0,0,,Hello world +Dialogue: Marked=0,0:01:01.23,0:01:04.55,Default,,10,0,0,,Left of centre +Dialogue: Marked=0,0:02:01.23,0:02:04.55,Default,,10,0,0,,{\an4}Left +Dialogue: Marked=0,0:03:01.23,0:03:04.55,Default,,10,0,0,,{\an6}Right +Dialogue: Marked=0,0:04:01.23,0:04:04.55,Default,,0,100,0,,{\an4}Style left diff --git a/test/ssa_reader_test.cc b/test/ssa_reader_test.cc index 89a543c..8820bf4 100644 --- a/test/ssa_reader_test.cc +++ b/test/ssa_reader_test.cc @@ -254,7 +254,7 @@ BOOST_AUTO_TEST_CASE (ssa_reader_test3) /* Alignments */ SUB_START (sub::Time::from_hms (0, 0, 9, 230), sub::Time::from_hms (0, 0, 11, 560)); - LINE ((10.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::LEFT_OF_SCREEN); + LINE ((10.0 / 1080), sub::BOTTOM_OF_SCREEN, (10.0 / 1920), sub::LEFT_OF_SCREEN); BLOCK("bottom left", "Arial", fs(20), false, false, false); SUB_END (); @@ -264,13 +264,13 @@ BOOST_AUTO_TEST_CASE (ssa_reader_test3) SUB_END (); SUB_START (sub::Time::from_hms (0, 0, 9, 250), sub::Time::from_hms (0, 0, 11, 560)); - LINE ((10.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::RIGHT_OF_SCREEN); + LINE ((10.0 / 1080), sub::BOTTOM_OF_SCREEN, (10.0 / 1920), sub::RIGHT_OF_SCREEN); BLOCK("bottom right", "Arial", fs(20), false, false, false); SUB_END (); SUB_START (sub::Time::from_hms (0, 0, 9, 260), sub::Time::from_hms (0, 0, 11, 560)); /* Position is half of a 20pt line (with line spacing) above vertical centre */ - LINE (-vp(10), sub::VERTICAL_CENTRE_OF_SCREEN, 0, sub::LEFT_OF_SCREEN); + LINE (-vp(10), sub::VERTICAL_CENTRE_OF_SCREEN, (10.0 / 1920), sub::LEFT_OF_SCREEN); BLOCK("middle left", "Arial", fs(20), false, false, false); SUB_END (); @@ -280,12 +280,12 @@ BOOST_AUTO_TEST_CASE (ssa_reader_test3) SUB_END (); SUB_START (sub::Time::from_hms (0, 0, 9, 280), sub::Time::from_hms (0, 0, 11, 560)); - LINE (-vp(10), sub::VERTICAL_CENTRE_OF_SCREEN, 0, sub::RIGHT_OF_SCREEN); + LINE (-vp(10), sub::VERTICAL_CENTRE_OF_SCREEN, (10.0 / 1920), sub::RIGHT_OF_SCREEN); BLOCK("middle right", "Arial", fs(20), false, false, false); SUB_END (); SUB_START (sub::Time::from_hms (0, 0, 9, 290), sub::Time::from_hms (0, 0, 11, 560)); - LINE ((10.0 / 1080), sub::TOP_OF_SCREEN, 0, sub::LEFT_OF_SCREEN); + LINE ((10.0 / 1080), sub::TOP_OF_SCREEN, (10.0 / 1920), sub::LEFT_OF_SCREEN); BLOCK("top left", "Arial", fs(20), false, false, false); SUB_END (); @@ -295,7 +295,7 @@ BOOST_AUTO_TEST_CASE (ssa_reader_test3) SUB_END (); SUB_START (sub::Time::from_hms (0, 0, 9, 310), sub::Time::from_hms (0, 0, 11, 560)); - LINE ((10.0 / 1080), sub::TOP_OF_SCREEN, 0, sub::RIGHT_OF_SCREEN); + LINE ((10.0 / 1080), sub::TOP_OF_SCREEN, (10.0 / 1920), sub::RIGHT_OF_SCREEN); BLOCK("top right", "Arial", fs(20), false, false, false); SUB_END (); @@ -637,3 +637,37 @@ BOOST_AUTO_TEST_CASE (ssa_reader_c) test_c("", "ff00ff"); } + +BOOST_AUTO_TEST_CASE(ssa_reader_horizontal_margin) +{ + auto subs = read_file("test/data/horizontal_margin.ssa"); + BOOST_REQUIRE_EQUAL(subs.size(), 5U); + + int n = 0; + + BOOST_REQUIRE_EQUAL(subs[n].lines.size(), 1U); + BOOST_CHECK(subs[n].lines[0].horizontal_position.reference == sub::HORIZONTAL_CENTRE_OF_SCREEN); + BOOST_CHECK_CLOSE(subs[n].lines[0].horizontal_position.proportional, 0, 1); + ++n; + + BOOST_REQUIRE_EQUAL(subs[n].lines.size(), 1U); + BOOST_CHECK(subs[n].lines[0].horizontal_position.reference == sub::HORIZONTAL_CENTRE_OF_SCREEN); + BOOST_CHECK_CLOSE(subs[n].lines[0].horizontal_position.proportional, -90.0f / (2 * 1920.0f), 1); + ++n; + + BOOST_REQUIRE_EQUAL(subs[n].lines.size(), 1U); + BOOST_CHECK(subs[n].lines[0].horizontal_position.reference == sub::LEFT_OF_SCREEN); + BOOST_CHECK_CLOSE(subs[n].lines[0].horizontal_position.proportional, 10.0f / 1920.f, 1); + ++n; + + BOOST_REQUIRE_EQUAL(subs[n].lines.size(), 1U); + BOOST_CHECK(subs[n].lines[0].horizontal_position.reference == sub::RIGHT_OF_SCREEN); + BOOST_CHECK_CLOSE(subs[n].lines[0].horizontal_position.proportional, 100.0f / 1920.f, 1); + ++n; + + BOOST_REQUIRE_EQUAL(subs[n].lines.size(), 1U); + BOOST_CHECK(subs[n].lines[0].horizontal_position.reference == sub::LEFT_OF_SCREEN); + BOOST_CHECK_CLOSE(subs[n].lines[0].horizontal_position.proportional, 200.0f / 1920.f, 1); + ++n; +} + |
