}
} 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]);
}
}
}
HorizontalReference horizontal_reference;
VerticalReference vertical_reference;
int vertical_margin;
+ int left_margin = 0;
+ int right_margin = 0;
private:
Colour colour (string c) const
}
};
+
+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
{
} 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("(,"));
*/
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.
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]);
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);
}
}
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);
--- /dev/null
+[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
/* 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 ();
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 ();
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 ();
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 ();
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;
+}
+