X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fssa_reader.cc;h=dad0f2617215c99b8ef47a0b6656adf5199011e8;hb=8ff50a18013d3c57d1058368146c979354016663;hp=072fff8eea271eaa0d7eb0713b1880b46d69a622;hpb=cafee6f81257fa81ee302b5d3ffa82213a0a6a44;p=libsub.git diff --git a/src/ssa_reader.cc b/src/ssa_reader.cc index 072fff8..dad0f26 100644 --- a/src/ssa_reader.cc +++ b/src/ssa_reader.cc @@ -24,8 +24,8 @@ #include "subtitle.h" #include "compose.hpp" #include -#include -#include +#include +#include #include #include @@ -36,6 +36,9 @@ using std::cout; using boost::optional; using boost::function; using namespace boost::algorithm; +#if BOOST_VERSION >= 106100 +using namespace boost::placeholders; +#endif using namespace sub; /** @param s Subtitle string encoded in UTF-8 */ @@ -53,17 +56,24 @@ SSAReader::SSAReader (FILE* f) Colour h_colour (string s) { - /* There are both BGR and ABGR versions of these colours */ - if ((s.length() != 8 && s.length() != 10) || s[0] != '&' || s[1] != 'H') { + if (s.empty() || s[0] != '&' || s[1] != 'H') { throw SSAError(String::compose("Badly formatted colour tag %1", s)); } - int ir, ig, ib; - /* XXX: ignoring alpha channel here; note that 00 is opaque and FF is transparent */ - int const off = s.length() == 10 ? 4 : 2; - if (sscanf(s.c_str() + off, "%2x%2x%2x", &ib, &ig, &ir) < 3) { - throw SSAError(String::compose("Badly formatted colour tag %1", s)); + + auto start = s.c_str(); + auto const end = start + s.length(); + while (start < end && (*start == '&' || *start == 'H')) { + ++start; } - return sub::Colour(ir / 255.0, ig / 255.0, ib / 255.0); + + auto const colour = strtoll(start, nullptr, 16); + + /* XXX: ignoring alpha channel here; note that 00 is opaque and FF is transparent */ + return sub::Colour( + ((colour & 0x000000ff) >> 0) / 255.0, + ((colour & 0x0000ff00) >> 8) / 255.0, + ((colour & 0x00ff0000) >> 16) / 255.0 + ); } class Style @@ -123,28 +133,19 @@ public: effect = SHADOW; } } else if (keys[i] == "Alignment") { - /* These values from libass' source code */ - switch ((raw_convert (style[i]) - 1) % 3) { - case 0: - horizontal_reference = LEFT_OF_SCREEN; - break; - case 1: - horizontal_reference = HORIZONTAL_CENTRE_OF_SCREEN; - break; - case 2: - horizontal_reference = RIGHT_OF_SCREEN; - break; - } - switch (raw_convert (style[i]) & 12) { - case 4: + if (style[i] == "7" || style[i] == "8" || style[i] == "9") { vertical_reference = TOP_OF_SCREEN; - break; - case 8: + } else if (style[i] == "4" || style[i] == "5" || style[i] == "6") { vertical_reference = VERTICAL_CENTRE_OF_SCREEN; - break; - case 0: + } else { vertical_reference = BOTTOM_OF_SCREEN; - break; + } + if (style[i] == "1" || style[i] == "4" || style[i] == "7") { + horizontal_reference = LEFT_OF_SCREEN; + } else if (style[i] == "3" || style[i] == "6" || style[i] == "9") { + horizontal_reference = RIGHT_OF_SCREEN; + } else { + horizontal_reference = HORIZONTAL_CENTRE_OF_SCREEN; } } else if (keys[i] == "MarginV") { vertical_margin = raw_convert (style[i]); @@ -154,7 +155,7 @@ public: string name; optional font_name; - int font_size; + int font_size; ///< points Colour primary_colour; /** outline colour */ optional back_colour; @@ -199,7 +200,7 @@ SSAReader::parse_time (string t) const } void -SSAReader::parse_style (RawSubtitle& sub, string style, int play_res_x, int play_res_y) +SSAReader::parse_style(RawSubtitle& sub, string style, int play_res_x, int play_res_y, Colour primary_colour) { if (style == "\\i1") { sub.italic = true; @@ -250,13 +251,16 @@ SSAReader::parse_style (RawSubtitle& sub, string style, int play_res_x, int play sub.vertical_position.proportional = raw_convert(bits[2]) / play_res_y; } else if (boost::starts_with(style, "\\fs")) { SUB_ASSERT (style.length() > 3); - sub.font_size.set_points (raw_convert(style.substr(3))); + sub.font_size.set_proportional(raw_convert(style.substr(3)) / play_res_y); } else if (boost::starts_with(style, "\\c")) { /* \c&Hbbggrr& */ - if (style.length() <= 2) { + if (style.length() > 2) { + sub.colour = h_colour(style.substr(2, style.length() - 3)); + } else if (style.length() == 2) { + sub.colour = primary_colour; + } else { throw SSAError(String::compose("Badly formatted colour tag %1", style)); } - sub.colour = h_colour (style.substr(2, style.length() - 3)); } } @@ -265,7 +269,7 @@ SSAReader::parse_style (RawSubtitle& sub, string style, int play_res_x, int play * @return List of RawSubtitles to represent line with vertical reference TOP_OF_SUBTITLE. */ vector -SSAReader::parse_line (RawSubtitle base, string line, int play_res_x, int play_res_y) +SSAReader::parse_line(RawSubtitle base, string line, int play_res_x, int play_res_y, Colour primary_colour) { enum { TEXT, @@ -281,16 +285,19 @@ SSAReader::parse_line (RawSubtitle base, string line, int play_res_x, int play_r current.vertical_position.reference = BOTTOM_OF_SCREEN; } - if (!current.vertical_position.proportional) { - current.vertical_position.proportional = 0; - } + /* Any vertical_position that is set in base (and therefore current) is a margin, which + * we need to ignore if we end up vertically centering this subtitle. + * Clear out vertical_position from current; we'll re-add it from base later + * if required. + */ + current.vertical_position.proportional = 0; /* 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. */ - if (!current.font_size.points()) { - current.font_size.set_points (72); + if (!current.font_size.proportional()) { + current.font_size.set_proportional(72.0 / play_res_y); } /* Count the number of line breaks */ @@ -303,22 +310,8 @@ SSAReader::parse_line (RawSubtitle base, string line, int play_res_x, int play_r } } - /* Imagine that the screen is 792 points (i.e. 11 inches) high (as with DCP) */ - double const line_size = current.font_size.proportional(792) * 1.2; - - /* Tweak vertical_position accordingly */ - switch (current.vertical_position.reference.get()) { - case TOP_OF_SCREEN: - case TOP_OF_SUBTITLE: - /* Nothing to do */ - break; - case VERTICAL_CENTRE_OF_SCREEN: - current.vertical_position.proportional = current.vertical_position.proportional.get() - ((line_breaks + 1) * line_size) / 2; - break; - case BOTTOM_OF_SCREEN: - current.vertical_position.proportional = current.vertical_position.proportional.get() + line_breaks * line_size; - break; - } + /* There are vague indications that with ASS 1 point should equal 1 pixel */ + double const line_size = current.font_size.proportional(play_res_y) * 1.2; for (size_t i = 0; i < line.length(); ++i) { char const c = line[i]; @@ -338,7 +331,7 @@ SSAReader::parse_line (RawSubtitle base, string line, int play_res_x, int play_r subs.push_back (current); current.text = ""; } - parse_style (current, style, play_res_x, play_res_y); + parse_style(current, style, play_res_x, play_res_y, primary_colour); style = ""; } @@ -370,6 +363,28 @@ SSAReader::parse_line (RawSubtitle base, string line, int play_res_x, int play_r subs.push_back (current); } + /* Now we definitely know the vertical position reference we can finish off the position */ + for (auto& sub: subs) { + switch (sub.vertical_position.reference.get()) { + case TOP_OF_SCREEN: + case TOP_OF_SUBTITLE: + /* Just re-add any margins we came in with */ + sub.vertical_position.proportional = sub.vertical_position.proportional.get() + base.vertical_position.proportional.get_value_or(0); + break; + case VERTICAL_CENTRE_OF_SCREEN: + /* Margins are ignored, but we need to centre */ + sub.vertical_position.proportional = sub.vertical_position.proportional.get() - ((line_breaks + 1) * line_size) / 2; + break; + case BOTTOM_OF_SCREEN: + /* Re-add margins and account for each line */ + sub.vertical_position.proportional = + sub.vertical_position.proportional.get() + + base.vertical_position.proportional.get_value_or(0) + + line_breaks * line_size; + break; + } + } + return subs; } @@ -439,7 +454,7 @@ SSAReader::read (function ()> get_line) case EVENTS: if (type == "Format") { split (event_format, body, is_any_of (",")); - BOOST_FOREACH (string& i, event_format) { + for (auto& i: event_format) { trim (i); } } else if (type == "Dialogue") { @@ -460,6 +475,7 @@ SSAReader::read (function ()> get_line) SUB_ASSERT (event_format.size() == event.size()); RawSubtitle sub; + optional