40 #include "compose.hpp"
51 LIBDCP_DISABLE_WARNINGS
52 #include <libxml++/libxml++.h>
53 LIBDCP_ENABLE_WARNINGS
54 #include <boost/weak_ptr.hpp>
62 using std::shared_ptr;
63 using std::dynamic_pointer_cast;
65 using std::make_shared;
66 using boost::optional;
70 InteropSubtitleAsset::InteropSubtitleAsset (boost::filesystem::path file)
73 _raw_xml = dcp::file_to_string (file);
75 auto xml = make_shared<cxml::Document>(
"DCSubtitle");
76 xml->read_file (file);
77 _id = xml->string_child (
"SubtitleID");
78 _reel_number = xml->string_child (
"ReelNumber");
79 _language = xml->string_child (
"Language");
80 _movie_title = xml->string_child (
"MovieTitle");
81 _load_font_nodes = type_children<InteropLoadFontNode> (xml,
"LoadFont");
85 vector<ParseState> ps;
86 for (
auto i: xml->node()->get_children()) {
87 auto e =
dynamic_cast<xmlpp::Element
const *
>(i);
88 if (e && (e->get_name() ==
"Font" || e->get_name() ==
"Subtitle")) {
89 parse_subtitles (e, ps, optional<int>(), Standard::INTEROP);
93 for (
auto i: _subtitles) {
94 auto si = dynamic_pointer_cast<SubtitleImage>(i);
96 si->read_png_file (file.parent_path() / String::compose(
"%1.png", si->id()));
102 InteropSubtitleAsset::InteropSubtitleAsset ()
109 InteropSubtitleAsset::xml_as_string ()
const
112 auto root = doc.create_root_node (
"DCSubtitle");
113 root->set_attribute (
"Version",
"1.0");
115 root->add_child(
"SubtitleID")->add_child_text (_id);
116 root->add_child(
"MovieTitle")->add_child_text (_movie_title);
117 root->add_child(
"ReelNumber")->add_child_text (raw_convert<string> (_reel_number));
118 root->add_child(
"Language")->add_child_text (_language);
120 for (
auto i: _load_font_nodes) {
121 xmlpp::Element* load_font = root->add_child(
"LoadFont");
122 load_font->set_attribute (
"Id", i->id);
123 load_font->set_attribute (
"URI", i->uri);
128 return doc.write_to_string (
"UTF-8");
133 InteropSubtitleAsset::add_font (
string load_id,
dcp::ArrayData data)
135 _fonts.push_back (Font(load_id, make_uuid(), data));
136 auto const uri = String::compose(
"font_%1.ttf", _load_font_nodes.size());
137 _load_font_nodes.push_back (shared_ptr<InteropLoadFontNode>(
new InteropLoadFontNode(load_id, uri)));
142 InteropSubtitleAsset::equals (shared_ptr<const Asset> other_asset,
EqualityOptions options, NoteHandler note)
const
144 if (!SubtitleAsset::equals (other_asset, options, note)) {
148 auto other = dynamic_pointer_cast<const InteropSubtitleAsset> (other_asset);
153 if (!options.load_font_nodes_can_differ) {
154 auto i = _load_font_nodes.begin();
155 auto j = other->_load_font_nodes.begin();
157 while (i != _load_font_nodes.end ()) {
158 if (j == other->_load_font_nodes.end ()) {
159 note (NoteType::ERROR,
"<LoadFont> nodes differ");
164 note (NoteType::ERROR,
"<LoadFont> nodes differ");
173 if (_movie_title != other->_movie_title) {
174 note (NoteType::ERROR,
"Subtitle movie titles differ");
182 vector<shared_ptr<LoadFontNode>>
183 InteropSubtitleAsset::load_font_nodes ()
const
185 vector<shared_ptr<LoadFontNode>> lf;
186 copy (_load_font_nodes.begin(), _load_font_nodes.end(), back_inserter (lf));
196 throw FileError (
"Could not open file for writing", p, -1);
208 auto im = dynamic_pointer_cast<dcp::SubtitleImage> (i);
210 im->write_png_file(p.parent_path() / String::compose(
"%1.png", im->id()));
215 for (
auto i: _load_font_nodes) {
216 auto file = p.parent_path() / i->uri;
218 while (j !=
_fonts.end() && j->load_id != i->id) {
222 j->data.write (
file);
236 for (
auto i: assets) {
237 auto font = dynamic_pointer_cast<FontAsset> (i);
242 for (
auto j: _load_font_nodes) {
244 for (
auto const& k:
_fonts) {
245 if (k.load_id == j->id) {
251 if (!got && font->file() && j->uri == font->file()->leaf().string()) {
252 _fonts.push_back (
Font (j->id, i->id(), font->file().get()));
260 InteropSubtitleAsset::add_font_assets (vector<shared_ptr<Asset>>& assets)
262 for (
auto const& i:
_fonts) {
264 assets.push_back (make_shared<FontAsset>(i.uuid, i.file.get()));
270 InteropSubtitleAsset::write_to_assetmap (xmlpp::Node* node, boost::filesystem::path root)
const
272 Asset::write_to_assetmap (node, root);
275 auto im = dynamic_pointer_cast<dcp::SubtitleImage> (i);
277 DCP_ASSERT (im->file());
278 write_file_to_assetmap (node, root, im->file().get(), im->id());
285 InteropSubtitleAsset::add_to_pkl (shared_ptr<PKL> pkl, boost::filesystem::path root)
const
287 Asset::add_to_pkl (pkl, root);
290 auto im = dynamic_pointer_cast<dcp::SubtitleImage> (i);
292 auto png_image = im->png_image ();
293 pkl->add_asset (im->id(), optional<string>(),
make_digest(png_image), png_image.size(),
"image/png");
300 InteropSubtitleAsset::set_font_file (
string load_id, boost::filesystem::path file)
303 if (i.load_id == load_id) {
308 for (
auto i: _load_font_nodes) {
309 if (i->id == load_id) {
310 i->uri =
file.filename().string();
Class to hold an arbitrary block of data.
boost::optional< boost::filesystem::path > file() const
boost::optional< boost::filesystem::path > _file
An exception related to a file.
void write(boost::filesystem::path path) const override
void resolve_fonts(std::vector< std::shared_ptr< Asset >> assets)
A parent for classes representing a file containing subtitles.
std::vector< std::shared_ptr< Subtitle > > _subtitles
std::vector< Font > _fonts
void subtitles_as_xml(xmlpp::Element *root, int time_code_rate, Standard standard) const
boost::optional< std::string > _raw_xml
InteropLoadFontNode class.
InteropSubtitleAsset class.
Namespace for everything in libdcp.
std::string make_digest(boost::filesystem::path filename, boost::function< void(float)>)
FILE * fopen_boost(boost::filesystem::path, std::string)
Methods for conversion to/from string.
A class to describe what "equality" means for a particular test.
Internal SubtitleAsset helpers.
Utility methods and classes.
Helpers for XML reading with libcxml.