#include "compose.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/bind/bind.hpp>
+#include <cstdlib>
#include <iostream>
#include <vector>
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
string name;
optional<string> font_name;
- int font_size;
+ int font_size; ///< points
Colour primary_colour;
/** outline colour */
optional<Colour> back_colour;
}
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;
sub.vertical_position.proportional = raw_convert<float>(bits[2]) / play_res_y;
} else if (boost::starts_with(style, "\\fs")) {
SUB_ASSERT (style.length() > 3);
- sub.font_size.set_points (raw_convert<int>(style.substr(3)));
+ sub.font_size.set_proportional(raw_convert<float>(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));
}
}
* @return List of RawSubtitles to represent line with vertical reference TOP_OF_SUBTITLE.
*/
vector<RawSubtitle>
-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,
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 */
}
}
- /* 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;
+ /* 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];
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 = "";
}
SUB_ASSERT (event_format.size() == event.size());
RawSubtitle sub;
+ optional<Style> style;
for (size_t i = 0; i < event.size(); ++i) {
trim (event[i]);
*/
trim_left_if (event[i], boost::is_any_of ("*"));
SUB_ASSERT (styles.find(event[i]) != styles.end());
- Style style = styles[event[i]];
- sub.font = style.font_name;
- sub.font_size = FontSize::from_points (style.font_size);
- sub.colour = style.primary_colour;
- sub.effect_colour = style.back_colour;
- sub.bold = style.bold;
- sub.italic = style.italic;
- sub.underline = style.underline;
- sub.effect = style.effect;
- sub.horizontal_position.reference = style.horizontal_reference;
- sub.vertical_position.reference = style.vertical_reference;
+ style = styles[event[i]];
+ sub.font = style->font_name;
+ sub.font_size = FontSize::from_proportional(static_cast<float>(style->font_size) / play_res_y);
+ sub.colour = style->primary_colour;
+ sub.effect_colour = style->back_colour;
+ sub.bold = style->bold;
+ sub.italic = style->italic;
+ sub.underline = style->underline;
+ sub.effect = style->effect;
+ sub.horizontal_position.reference = style->horizontal_reference;
+ sub.vertical_position.reference = style->vertical_reference;
if (sub.vertical_position.reference != sub::VERTICAL_CENTRE_OF_SCREEN) {
- sub.vertical_position.proportional = float(style.vertical_margin) / play_res_y;
+ sub.vertical_position.proportional = float(style->vertical_margin) / play_res_y;
}
} else if (event_format[i] == "MarginV") {
if (event[i] != "0" && sub.vertical_position.reference != sub::VERTICAL_CENTRE_OF_SCREEN) {
sub.vertical_position.proportional = raw_convert<float>(event[i]) / play_res_y;
}
} else if (event_format[i] == "Text") {
- for (auto j: parse_line (sub, event[i], play_res_x, play_res_y)) {
+ for (auto j: parse_line(sub, event[i], play_res_x, play_res_y, style ? style->primary_colour : Colour(1, 1, 1))) {
_subs.push_back (j);
}
}