Pick up effect and effect color.
[libdcp.git] / src / subtitle_asset.cc
1 /*
2     Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
3
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.
8
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.
13
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.
17
18 */
19
20 #include "subtitle_asset.h"
21
22 using namespace std;
23 using namespace boost;
24 using namespace libdcp;
25
26 SubtitleAsset::SubtitleAsset (string directory, string xml)
27         : Asset (directory, xml)
28         , XMLFile (path().string(), "DCSubtitle")
29 {
30         _subtitle_id = string_node ("SubtitleID");
31         _movie_title = string_node ("MovieTitle");
32         _reel_number = int64_node ("ReelNumber");
33         _language = string_node ("Language");
34
35         ignore_node ("LoadFont");
36
37         list<shared_ptr<FontNode> > font_nodes = sub_nodes<FontNode> ("Font");
38         _load_font_nodes = sub_nodes<LoadFontNode> ("LoadFont");
39
40         /* Now make Subtitle objects to represent the raw XML nodes
41            in a sane way.
42         */
43
44         list<shared_ptr<FontNode> > current_font_nodes;
45         for (list<shared_ptr<FontNode> >::iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) {
46                 examine_font_node (*i, current_font_nodes);
47         }
48 }
49
50 void
51 SubtitleAsset::examine_font_node (shared_ptr<FontNode> font_node, list<shared_ptr<FontNode> >& current_font_nodes)
52 {
53         current_font_nodes.push_back (font_node);
54
55         for (list<shared_ptr<SubtitleNode> >::iterator j = font_node->subtitle_nodes.begin(); j != font_node->subtitle_nodes.end(); ++j) {
56                 for (list<shared_ptr<TextNode> >::iterator k = (*j)->text_nodes.begin(); k != (*j)->text_nodes.end(); ++k) {
57                         FontNode effective (current_font_nodes);
58                         _subtitles.push_back (
59                                 shared_ptr<Subtitle> (
60                                         new Subtitle (
61                                                 font_id_to_name (effective.id),
62                                                 effective.italic.get(),
63                                                 effective.color.get(),
64                                                 effective.size,
65                                                 (*j)->in,
66                                                 (*j)->out,
67                                                 (*k)->v_position,
68                                                 (*k)->text,
69                                                 effective.effect,
70                                                 effective.effect_color.get()
71                                                 )
72                                         )
73                                 );
74                 }
75         }
76
77         for (list<shared_ptr<FontNode> >::iterator j = font_node->font_nodes.begin(); j != font_node->font_nodes.end(); ++j) {
78                 examine_font_node (*j, current_font_nodes);
79         }
80
81         current_font_nodes.pop_back ();
82 }
83
84 FontNode::FontNode (xmlpp::Node const * node)
85         : XMLNode (node)
86 {
87         id = optional_string_attribute ("Id");
88         size = optional_int64_attribute ("Size");
89         italic = optional_bool_attribute ("Italic");
90         color = optional_color_attribute ("Color");
91         effect = optional_string_attribute ("Effect");
92         effect_color = optional_color_attribute ("EffectColor");
93         subtitle_nodes = sub_nodes<SubtitleNode> ("Subtitle");
94         font_nodes = sub_nodes<FontNode> ("Font");
95 }
96
97 FontNode::FontNode (list<shared_ptr<FontNode> > const & font_nodes)
98         : size (0)
99         , italic (false)
100         , color ("FFFFFFFF")
101 {
102         for (list<shared_ptr<FontNode> >::const_iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) {
103                 if (!(*i)->id.empty ()) {
104                         id = (*i)->id;
105                 }
106                 if ((*i)->size != 0) {
107                         size = (*i)->size;
108                 }
109                 if ((*i)->italic) {
110                         italic = (*i)->italic.get ();
111                 }
112                 if ((*i)->color) {
113                         color = (*i)->color.get ();
114                 }
115                 if (!(*i)->effect.empty ()) {
116                         effect = (*i)->effect;
117                 }
118                 if ((*i)->effect_color) {
119                         effect_color = (*i)->effect_color.get ();
120                 }
121         }
122 }
123
124 LoadFontNode::LoadFontNode (xmlpp::Node const * node)
125         : XMLNode (node)
126 {
127         id = string_attribute ("Id");
128         uri = string_attribute ("URI");
129 }
130         
131
132 SubtitleNode::SubtitleNode (xmlpp::Node const * node)
133         : XMLNode (node)
134 {
135         in = time_attribute ("TimeIn");
136         out = time_attribute ("TimeOut");
137         text_nodes = sub_nodes<TextNode> ("Text");
138 }
139
140 TextNode::TextNode (xmlpp::Node const * node)
141         : XMLNode (node)
142 {
143         text = content ();
144         v_position = float_attribute ("VPosition");
145 }
146
147 list<shared_ptr<Subtitle> >
148 SubtitleAsset::subtitles_at (Time t) const
149 {
150         list<shared_ptr<Subtitle> > s;
151         for (list<shared_ptr<Subtitle> >::const_iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) {
152                 if ((*i)->in() <= t && t <= (*i)->out ()) {
153                         s.push_back (*i);
154                 }
155         }
156
157         return s;
158 }
159
160 std::string
161 SubtitleAsset::font_id_to_name (string id) const
162 {
163         list<shared_ptr<LoadFontNode> >::const_iterator i = _load_font_nodes.begin();
164         while (i != _load_font_nodes.end() && (*i)->id != id) {
165                 ++i;
166         }
167
168         if (i == _load_font_nodes.end ()) {
169                 return "";
170         }
171
172         if ((*i)->uri == "arial.ttf") {
173                 return "Arial";
174         }
175
176         return "";
177 }
178
179 Subtitle::Subtitle (
180         string font,
181         bool italic,
182         Color color,
183         int size,
184         Time in,
185         Time out,
186         float v_position,
187         string text,
188         string effect,
189         Color effect_color
190         )
191         : _font (font)
192         , _italic (italic)
193         , _color (color)
194         , _size (size)
195         , _in (in)
196         , _out (out)
197         , _v_position (v_position)
198         , _text (text)
199         , _effect (effect)
200         , _effect_color (effect_color)
201 {
202
203 }
204
205 int
206 Subtitle::size_in_pixels (int screen_height) const
207 {
208         /* Size in the subtitle file is given in points as if the screen
209            height is 11 inches, so a 72pt font would be 1/11th of the screen
210            height.
211         */
212         
213         return _size * screen_height / (11 * 72);
214 }