diff options
| author | Carl Hetherington <cth@carlh.net> | 2015-07-02 13:21:16 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2015-07-02 13:21:16 +0100 |
| commit | 4d406c620b0211a5e27c19187d963241120f8838 (patch) | |
| tree | 4ec7f4a1652ee89fc1b45faccb4d2d72a512a698 | |
| parent | b20c6fd0047a7b8ad63d19c46c3ea0e2185babc2 (diff) | |
Add support for reading <font> tags in SubRip.
| -rw-r--r-- | src/colour.cc | 18 | ||||
| -rw-r--r-- | src/colour.h | 7 | ||||
| -rw-r--r-- | src/dcp/font.cc | 8 | ||||
| -rw-r--r-- | src/subrip_reader.cc | 27 | ||||
| -rw-r--r-- | src/wscript | 2 | ||||
| -rw-r--r-- | test/subrip_reader_test.cc | 55 | ||||
| -rw-r--r-- | wscript | 9 |
7 files changed, 99 insertions, 27 deletions
diff --git a/src/colour.cc b/src/colour.cc index f163424..a47e633 100644 --- a/src/colour.cc +++ b/src/colour.cc @@ -25,16 +25,26 @@ using std::string; using namespace sub; -Colour::Colour (string argb_hex) +Colour +Colour::from_argb_hex (string argb_hex) { int alpha, ir, ig, ib; if (sscanf (argb_hex.c_str(), "%2x%2x%2x%2x", &alpha, &ir, &ig, &ib) < 4) { throw XMLError ("could not parse colour string"); } - r = float (ir) / 255; - g = float (ig) / 255; - b = float (ib) / 255; + return Colour (float (ir) / 255, float (ig) / 255, float (ib) / 255); +} + +Colour +Colour::from_rgb_hex (string rgb_hex) +{ + int ir, ig, ib; + if (sscanf (rgb_hex.c_str(), "%2x%2x%2x", &ir, &ig, &ib) < 3) { + throw XMLError ("could not parse colour string"); + } + + return Colour (float (ir) / 255, float (ig) / 255, float (ib) / 255); } bool diff --git a/src/colour.h b/src/colour.h index 673bb9f..55d2239 100644 --- a/src/colour.h +++ b/src/colour.h @@ -35,14 +35,15 @@ public: , g (0) , b (0) {} - + Colour (float r, float g, float b) : r (r) , g (g) , b (b) {} - Colour (std::string); + static Colour from_argb_hex (std::string); + static Colour from_rgb_hex (std::string); /** red component (from 0 to 1) */ float r; @@ -54,7 +55,7 @@ public: bool operator== (Colour const & a, Colour const & b); - + } #endif diff --git a/src/dcp/font.cc b/src/dcp/font.cc index b2fd128..64787c7 100644 --- a/src/dcp/font.cc +++ b/src/dcp/font.cc @@ -35,7 +35,7 @@ dcp::Font::Font (cxml::ConstNodePtr node) italic = node->optional_bool_attribute ("Italic"); optional<string> c = node->optional_string_attribute ("Color"); if (c) { - colour = Colour (c.get ()); + colour = Colour::from_argb_hex (c.get ()); } optional<string> const e = node->optional_string_attribute ("Effect"); if (e) { @@ -43,15 +43,15 @@ dcp::Font::Font (cxml::ConstNodePtr node) } c = node->optional_string_attribute ("EffectColor"); if (c) { - effect_colour = Colour (c.get ()); + effect_colour = Colour::from_argb_hex (c.get ()); } } dcp::Font::Font (std::list<boost::shared_ptr<Font> > const & font_nodes) : size (0) , italic (false) - , colour ("FFFFFFFF") - , effect_colour ("FFFFFFFF") + , colour (Colour::from_argb_hex ("FFFFFFFF")) + , effect_colour (Colour::from_argb_hex ("FFFFFFFF")) { for (list<shared_ptr<Font> >::const_iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) { if ((*i)->id) { diff --git a/src/subrip_reader.cc b/src/subrip_reader.cc index 3f1c23d..134ca3e 100644 --- a/src/subrip_reader.cc +++ b/src/subrip_reader.cc @@ -21,12 +21,17 @@ #include "exceptions.h" #include <boost/algorithm/string.hpp> #include <boost/lexical_cast.hpp> +#include <boost/regex.hpp> #include <cstdio> #include <vector> using std::string; using std::vector; +using std::list; +using std::cout; +using std::hex; using boost::lexical_cast; +using boost::to_upper; using namespace sub; SubripReader::SubripReader (FILE* f) @@ -60,7 +65,7 @@ SubripReader::SubripReader (FILE* f) static_cast<unsigned char> (line[1]) == 0xbb && static_cast<unsigned char> (line[2]) == 0xbf ) { - + /* Skip Unicode byte order mark */ line = line.substr (3); } @@ -88,7 +93,7 @@ SubripReader::SubripReader (FILE* f) to = convert_time (p[2]); /* XXX: should not ignore coordinate specifications */ - + state = CONTENT; break; } @@ -132,7 +137,7 @@ SubripReader::convert_line (string t, int line_number, Time from, Time to) TEXT, TAG } state = TEXT; - + string tag; RawSubtitle p; @@ -144,7 +149,10 @@ SubripReader::convert_line (string t, int line_number, Time from, Time to) /* XXX: arbitrary */ p.vertical_position.lines = 32; p.vertical_position.reference = TOP_OF_SUBTITLE; - + + list<Colour> colours; + colours.push_back (Colour (1, 1, 1)); + /* XXX: missing <font> support */ /* XXX: nesting of tags e.g. <b>foo<i>bar<b>baz</b>fred</i>jim</b> might not work, I think. @@ -179,6 +187,17 @@ SubripReader::convert_line (string t, int line_number, Time from, Time to) } else if (tag == "/u") { maybe_content (p); p.underline = false; + } else if (boost::starts_with (tag, "font")) { + maybe_content (p); + boost::regex re (".*color=\"#([0123456789abcdef]+)\""); + boost::smatch match; + if (boost::regex_search (tag, match, re) && string (match[1]).size() == 6) { + p.colour = Colour::from_rgb_hex (match[1]); + colours.push_back (p.colour); + } + } else if (tag == "/font") { + colours.pop_back (); + p.colour = colours.back (); } tag.clear (); state = TEXT; diff --git a/src/wscript b/src/wscript index 89c6e89..6afe1d9 100644 --- a/src/wscript +++ b/src/wscript @@ -8,7 +8,7 @@ def build(bld): obj.name = 'libsub%s' % bld.env.API_VERSION obj.target = 'sub%s' % bld.env.API_VERSION - obj.uselib = 'CXML DCP BOOST_FILESYSTEM BOOST_LOCALE' + obj.uselib = 'CXML DCP BOOST_FILESYSTEM BOOST_LOCALE BOOST_REGEX' obj.use = 'libkumu-libsub%s libasdcp-libsub%s' % (bld.env.API_VERSION, bld.env.API_VERSION) obj.export_includes = ['.'] obj.source = """ diff --git a/test/subrip_reader_test.cc b/test/subrip_reader_test.cc index 91437f2..dcd506a 100644 --- a/test/subrip_reader_test.cc +++ b/test/subrip_reader_test.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2014 Carl Hetherington <cth@carlh.net> + Copyright (C) 2014-2015 Carl Hetherington <cth@carlh.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,11 +24,13 @@ #include <boost/test/unit_test.hpp> #include <boost/filesystem.hpp> #include <fstream> +#include <cmath> using std::list; using std::cerr; using std::ifstream; using std::vector; +using std::fabs; /* Test reading of a Subrip file */ BOOST_AUTO_TEST_CASE (subrip_reader_test) @@ -40,13 +42,13 @@ BOOST_AUTO_TEST_CASE (subrip_reader_test) list<sub::Subtitle>::iterator i = subs.begin (); - + /* First subtitle */ BOOST_CHECK (i != subs.end ()); BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 0, 41, 90)); BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 0, 42, 210)); - + list<sub::Line>::iterator j = i->lines.begin (); BOOST_CHECK (j != i->lines.end ()); BOOST_CHECK_EQUAL (j->blocks.size(), 1); @@ -74,13 +76,13 @@ BOOST_AUTO_TEST_CASE (subrip_reader_test) BOOST_CHECK_EQUAL (j->vertical_position.reference.get(), sub::TOP_OF_SUBTITLE); ++i; - + /* Second subtitle */ - + BOOST_CHECK (i != subs.end ()); BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 1, 1, 10)); BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 1, 2, 100)); - + BOOST_CHECK_EQUAL (i->lines.size(), 1); sub::Line l = i->lines.front (); BOOST_CHECK_EQUAL (l.blocks.size(), 7); @@ -88,7 +90,7 @@ BOOST_AUTO_TEST_CASE (subrip_reader_test) BOOST_CHECK_EQUAL (l.vertical_position.reference.get(), sub::TOP_OF_SUBTITLE); list<sub::Block>::iterator k = l.blocks.begin (); - + BOOST_CHECK (k != l.blocks.end ()); BOOST_CHECK_EQUAL (k->text, "This is some "); BOOST_CHECK_EQUAL (k->font.get(), "Arial"); @@ -151,7 +153,7 @@ BOOST_AUTO_TEST_CASE (subrip_reader_test) BOOST_CHECK_EQUAL (k->italic, false); BOOST_CHECK_EQUAL (k->underline, false); ++k; - + BOOST_CHECK (k == l.blocks.end ()); } @@ -217,7 +219,7 @@ BOOST_AUTO_TEST_CASE (subrip_reader_test2) BOOST_AUTO_TEST_CASE (subrip_reader_convert_line_test) { sub::SubripReader r; - + r.convert_line ("Hello world", 0, sub::Time (), sub::Time ()); BOOST_CHECK_EQUAL (r._subs.size(), 1); BOOST_CHECK_EQUAL (r._subs.front().text, "Hello world"); @@ -261,7 +263,7 @@ BOOST_AUTO_TEST_CASE (subrip_reader_convert_line_test) r.convert_line ("<b>This is <i>nesting</i> of subtitles</b>", 0, sub::Time (), sub::Time ()); BOOST_CHECK_EQUAL (r._subs.size(), 3); - list<sub::RawSubtitle>::iterator i = r._subs.begin (); + list<sub::RawSubtitle>::iterator i = r._subs.begin (); BOOST_CHECK_EQUAL (i->text, "This is "); BOOST_CHECK_EQUAL (i->bold, true); BOOST_CHECK_EQUAL (i->italic, false); @@ -275,8 +277,39 @@ BOOST_AUTO_TEST_CASE (subrip_reader_convert_line_test) BOOST_CHECK_EQUAL (i->italic, false); ++i; r._subs.clear (); -} + r.convert_line ("<font color=\"#ff0000\">some red text <b>in bold</b></font>", 0, sub::Time (), sub::Time ()); + BOOST_CHECK_EQUAL (r._subs.size(), 2); + i = r._subs.begin (); + BOOST_CHECK_EQUAL (i->text, "some red text "); + BOOST_CHECK_EQUAL (i->bold, false); + BOOST_CHECK_CLOSE (i->colour.r, 1, 0.1); + BOOST_CHECK (fabs (i->colour.g) < 0.01); + BOOST_CHECK (fabs (i->colour.b) < 0.01); + ++i; + BOOST_CHECK_EQUAL (i->text, "in bold"); + BOOST_CHECK_EQUAL (i->bold, true); + BOOST_CHECK_CLOSE (i->colour.r, 1, 0.1); + BOOST_CHECK (fabs (i->colour.g) < 0.01); + BOOST_CHECK (fabs (i->colour.b) < 0.01); + r._subs.clear (); + + r.convert_line ("<font color=\"#0000ff\">some blue text <b>in bold</b></font>", 0, sub::Time (), sub::Time ()); + BOOST_CHECK_EQUAL (r._subs.size(), 2); + i = r._subs.begin (); + BOOST_CHECK_EQUAL (i->text, "some blue text "); + BOOST_CHECK_EQUAL (i->bold, false); + BOOST_CHECK (fabs (i->colour.r) < 0.01); + BOOST_CHECK (fabs (i->colour.g) < 0.01); + BOOST_CHECK_CLOSE (i->colour.b, 1, 0.1); + ++i; + BOOST_CHECK_EQUAL (i->text, "in bold"); + BOOST_CHECK_EQUAL (i->bold, true); + BOOST_CHECK (fabs (i->colour.r) < 0.01); + BOOST_CHECK (fabs (i->colour.g) < 0.01); + BOOST_CHECK_CLOSE (i->colour.b, 1, 0.1); + r._subs.clear (); +} /** Test SubripReader::convert_time */ BOOST_AUTO_TEST_CASE (subrip_reader_convert_time_test) @@ -72,6 +72,15 @@ def configure(conf): lib=['boost_locale%s' % boost_lib_suffix, 'boost_system%s' % boost_lib_suffix], uselib_store='BOOST_LOCALE') + conf.check_cxx(fragment=""" + #include <boost/regex.hpp>\n + int main() { boost::regex re ("foo"); }\n + """, + msg='Checking for boost regex library', + libpath='/usr/local/lib', + lib=['boost_regex%s' % boost_lib_suffix, 'boost_system%s' % boost_lib_suffix], + uselib_store='BOOST_REGEX') + if not conf.env.DISABLE_TESTS: conf.recurse('test') conf.recurse('asdcplib') |
