2 Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <boost/lexical_cast.hpp>
21 #include "subtitle_asset.h"
24 using namespace boost;
25 using namespace libdcp;
27 SubtitleAsset::SubtitleAsset (string directory, string xml)
28 : Asset (directory, xml)
29 , XMLFile (path().string(), "DCSubtitle")
31 _subtitle_id = string_node ("SubtitleID");
32 _movie_title = string_node ("MovieTitle");
33 _reel_number = int64_node ("ReelNumber");
34 _language = string_node ("Language");
36 ignore_node ("LoadFont");
38 list<shared_ptr<FontNode> > font_nodes = sub_nodes<FontNode> ("Font");
39 _load_font_nodes = sub_nodes<LoadFontNode> ("LoadFont");
41 /* Now make Subtitle objects to represent the raw XML nodes
45 list<shared_ptr<FontNode> > current_font_nodes;
46 list<shared_ptr<SubtitleNode> > current_subtitle_nodes;
47 current_subtitle_nodes.push_back (shared_ptr<SubtitleNode> ());
48 examine_font_nodes (font_nodes, current_font_nodes, current_subtitle_nodes);
52 SubtitleAsset::examine_font_nodes (
53 list<shared_ptr<FontNode> > const & font_nodes,
54 list<shared_ptr<FontNode> >& current_font_nodes,
55 list<shared_ptr<SubtitleNode> >& current_subtitle_nodes
58 for (list<shared_ptr<FontNode> >::const_iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) {
60 current_font_nodes.push_back (*i);
62 for (list<shared_ptr<SubtitleNode> >::iterator j = (*i)->subtitle_nodes.begin(); j != (*i)->subtitle_nodes.end(); ++j) {
63 current_subtitle_nodes.push_back (*j);
64 examine_text_nodes (*j, (*j)->text_nodes, current_font_nodes);
65 examine_font_nodes ((*j)->font_nodes, current_font_nodes, current_subtitle_nodes);
66 current_subtitle_nodes.pop_back ();
69 examine_font_nodes ((*i)->font_nodes, current_font_nodes, current_subtitle_nodes);
70 examine_text_nodes (current_subtitle_nodes.back (), (*i)->text_nodes, current_font_nodes);
72 current_font_nodes.pop_back ();
77 SubtitleAsset::examine_text_nodes (
78 shared_ptr<SubtitleNode> subtitle_node,
79 list<shared_ptr<TextNode> > const & text_nodes,
80 list<shared_ptr<FontNode> >& current_font_nodes
83 for (list<shared_ptr<TextNode> >::const_iterator i = text_nodes.begin(); i != text_nodes.end(); ++i) {
84 FontNode effective (current_font_nodes);
85 _subtitles.push_back (
86 shared_ptr<Subtitle> (
88 font_id_to_name (effective.id),
89 effective.italic.get(),
90 effective.color.get(),
97 effective.effect.get(),
98 effective.effect_color.get(),
107 FontNode::FontNode (xmlpp::Node const * node)
110 id = optional_string_attribute ("Id");
111 size = optional_int64_attribute ("Size");
112 italic = optional_bool_attribute ("Italic");
113 color = optional_color_attribute ("Color");
114 string const e = optional_string_attribute ("Effect");
117 } else if (e == "border") {
119 } else if (e == "shadow") {
121 } else if (!e.empty ()) {
122 throw DCPReadError ("unknown subtitle effect type");
124 effect_color = optional_color_attribute ("EffectColor");
125 subtitle_nodes = sub_nodes<SubtitleNode> ("Subtitle");
126 font_nodes = sub_nodes<FontNode> ("Font");
127 text_nodes = sub_nodes<TextNode> ("Text");
130 FontNode::FontNode (list<shared_ptr<FontNode> > const & font_nodes)
134 , effect_color ("FFFFFFFF")
136 for (list<shared_ptr<FontNode> >::const_iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) {
137 if (!(*i)->id.empty ()) {
140 if ((*i)->size != 0) {
144 italic = (*i)->italic.get ();
147 color = (*i)->color.get ();
150 effect = (*i)->effect.get ();
152 if ((*i)->effect_color) {
153 effect_color = (*i)->effect_color.get ();
158 LoadFontNode::LoadFontNode (xmlpp::Node const * node)
161 id = string_attribute ("Id");
162 uri = string_attribute ("URI");
166 SubtitleNode::SubtitleNode (xmlpp::Node const * node)
169 in = time_attribute ("TimeIn");
170 out = time_attribute ("TimeOut");
171 font_nodes = sub_nodes<FontNode> ("Font");
172 text_nodes = sub_nodes<TextNode> ("Text");
175 TextNode::TextNode (xmlpp::Node const * node)
180 v_position = float_attribute ("VPosition");
181 string const v = optional_string_attribute ("VAlign");
184 } else if (v == "center") {
186 } else if (v == "bottom") {
190 fade_up_time = fade_time ("FadeUpTime");
191 fade_down_time = fade_time ("FadeUpTime");
196 TextNode::fade_time (string name)
198 string const u = optional_string_attribute (name);
202 t = Time (0, 0, 0, 20);
203 } else if (u.find (":") != string::npos) {
206 t = Time (0, 0, 0, lexical_cast<int> (u));
209 if (t > Time (0, 0, 8, 0)) {
210 t = Time (0, 0, 8, 0);
216 list<shared_ptr<Subtitle> >
217 SubtitleAsset::subtitles_at (Time t) const
219 list<shared_ptr<Subtitle> > s;
220 for (list<shared_ptr<Subtitle> >::const_iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) {
221 if ((*i)->in() <= t && t <= (*i)->out ()) {
230 SubtitleAsset::font_id_to_name (string id) const
232 list<shared_ptr<LoadFontNode> >::const_iterator i = _load_font_nodes.begin();
233 while (i != _load_font_nodes.end() && (*i)->id != id) {
237 if (i == _load_font_nodes.end ()) {
241 if ((*i)->uri == "arial.ttf") {
269 , _v_position (v_position)
273 , _effect_color (effect_color)
274 , _fade_up_time (fade_up_time)
275 , _fade_down_time (fade_down_time)
281 Subtitle::size_in_pixels (int screen_height) const
283 /* Size in the subtitle file is given in points as if the screen
284 height is 11 inches, so a 72pt font would be 1/11th of the screen
288 return _size * screen_height / (11 * 72);