summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2015-07-02 13:21:16 +0100
committerCarl Hetherington <cth@carlh.net>2015-07-02 13:21:16 +0100
commit4d406c620b0211a5e27c19187d963241120f8838 (patch)
tree4ec7f4a1652ee89fc1b45faccb4d2d72a512a698
parentb20c6fd0047a7b8ad63d19c46c3ea0e2185babc2 (diff)
Add support for reading <font> tags in SubRip.
-rw-r--r--src/colour.cc18
-rw-r--r--src/colour.h7
-rw-r--r--src/dcp/font.cc8
-rw-r--r--src/subrip_reader.cc27
-rw-r--r--src/wscript2
-rw-r--r--test/subrip_reader_test.cc55
-rw-r--r--wscript9
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)
diff --git a/wscript b/wscript
index 2056713..12143d8 100644
--- a/wscript
+++ b/wscript
@@ -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')