X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Finterop_subtitle_asset.cc;h=a7be5d1a4eecab08c449fe0a464b899d23b5fe56;hb=4f9802e8a7225fc1b3db105b45e3688a64af3588;hp=9951122285b17d51b00808b61e0f54e26d247c9a;hpb=3e24098b32d6160759378e671bfca241dd9025d9;p=libdcp.git diff --git a/src/interop_subtitle_asset.cc b/src/interop_subtitle_asset.cc index 99511222..a7be5d1a 100644 --- a/src/interop_subtitle_asset.cc +++ b/src/interop_subtitle_asset.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2015 Carl Hetherington + Copyright (C) 2012-2021 Carl Hetherington This file is part of libdcp. @@ -31,62 +31,88 @@ files in the program, then also delete it here. */ -#include "interop_subtitle_asset.h" + +/** @file src/interop_subtitle_asset.cc + * @brief InteropSubtitleAsset class + */ + + +#include "compose.hpp" +#include "dcp_assert.h" +#include "font_asset.h" #include "interop_load_font_node.h" -#include "xml.h" +#include "interop_subtitle_asset.h" #include "raw_convert.h" +#include "subtitle_asset_internal.h" +#include "subtitle_image.h" #include "util.h" -#include "font_asset.h" -#include "dcp_assert.h" +#include "warnings.h" +#include "xml.h" +LIBDCP_DISABLE_WARNINGS #include -#include +LIBDCP_ENABLE_WARNINGS +#include #include #include + using std::list; using std::string; using std::cout; using std::cerr; using std::map; -using boost::shared_ptr; +using std::shared_ptr; +using std::dynamic_pointer_cast; +using std::vector; +using std::make_shared; using boost::shared_array; using boost::optional; -using boost::dynamic_pointer_cast; using namespace dcp; + InteropSubtitleAsset::InteropSubtitleAsset (boost::filesystem::path file) : SubtitleAsset (file) { - shared_ptr xml (new cxml::Document ("DCSubtitle")); + _raw_xml = dcp::file_to_string (file); + + auto xml = make_shared("DCSubtitle"); xml->read_file (file); _id = xml->string_child ("SubtitleID"); _reel_number = xml->string_child ("ReelNumber"); _language = xml->string_child ("Language"); _movie_title = xml->string_child ("MovieTitle"); - _load_font_nodes = type_children (xml, "LoadFont"); + _load_font_nodes = type_children (xml, "LoadFont"); /* Now we need to drop down to xmlpp */ - list ps; - xmlpp::Node::NodeList c = xml->node()->get_children (); - for (xmlpp::Node::NodeList::const_iterator i = c.begin(); i != c.end(); ++i) { - xmlpp::Element const * e = dynamic_cast (*i); + vector ps; + for (auto i: xml->node()->get_children()) { + auto e = dynamic_cast(i); if (e && (e->get_name() == "Font" || e->get_name() == "Subtitle")) { - parse_subtitles (e, ps, optional(), INTEROP); + parse_subtitles (e, ps, optional(), Standard::INTEROP); + } + } + + for (auto i: _subtitles) { + auto si = dynamic_pointer_cast(i); + if (si) { + si->read_png_file (file.parent_path() / String::compose("%1.png", si->id())); } } } + InteropSubtitleAsset::InteropSubtitleAsset () { } + string InteropSubtitleAsset::xml_as_string () const { xmlpp::Document doc; - xmlpp::Element* root = doc.create_root_node ("DCSubtitle"); + auto root = doc.create_root_node ("DCSubtitle"); root->set_attribute ("Version", "1.0"); root->add_child("SubtitleID")->add_child_text (_id); @@ -94,24 +120,27 @@ InteropSubtitleAsset::xml_as_string () const root->add_child("ReelNumber")->add_child_text (raw_convert (_reel_number)); root->add_child("Language")->add_child_text (_language); - for (list >::const_iterator i = _load_font_nodes.begin(); i != _load_font_nodes.end(); ++i) { + for (auto i: _load_font_nodes) { xmlpp::Element* load_font = root->add_child("LoadFont"); - load_font->set_attribute ("Id", (*i)->id); - load_font->set_attribute ("URI", (*i)->uri); + load_font->set_attribute ("Id", i->id); + load_font->set_attribute ("URI", i->uri); } - subtitles_as_xml (root, 250, INTEROP); + subtitles_as_xml (root, 250, Standard::INTEROP); - return doc.write_to_string_formatted ("UTF-8"); + return doc.write_to_string ("UTF-8"); } + void -InteropSubtitleAsset::add_font (string load_id, boost::filesystem::path file) +InteropSubtitleAsset::add_font (string load_id, dcp::ArrayData data) { - _fonts.push_back (Font (load_id, make_uuid(), file)); - _load_font_nodes.push_back (shared_ptr (new InteropLoadFontNode (load_id, file.leaf().string ()))); + _fonts.push_back (Font(load_id, make_uuid(), data)); + auto const uri = String::compose("font_%1.ttf", _load_font_nodes.size()); + _load_font_nodes.push_back (shared_ptr(new InteropLoadFontNode(load_id, uri))); } + bool InteropSubtitleAsset::equals (shared_ptr other_asset, EqualityOptions options, NoteHandler note) const { @@ -119,101 +148,170 @@ InteropSubtitleAsset::equals (shared_ptr other_asset, EqualityOptio return false; } - shared_ptr other = dynamic_pointer_cast (other_asset); + auto other = dynamic_pointer_cast (other_asset); if (!other) { return false; } - list >::const_iterator i = _load_font_nodes.begin (); - list >::const_iterator j = other->_load_font_nodes.begin (); + if (!options.load_font_nodes_can_differ) { + auto i = _load_font_nodes.begin(); + auto j = other->_load_font_nodes.begin(); - while (i != _load_font_nodes.end ()) { - if (j == other->_load_font_nodes.end ()) { - note (DCP_ERROR, " nodes differ"); - return false; - } + while (i != _load_font_nodes.end ()) { + if (j == other->_load_font_nodes.end ()) { + note (NoteType::ERROR, " nodes differ"); + return false; + } - if (**i != **j) { - note (DCP_ERROR, " nodes differ"); - return false; - } + if (**i != **j) { + note (NoteType::ERROR, " nodes differ"); + return false; + } - ++i; - ++j; + ++i; + ++j; + } } if (_movie_title != other->_movie_title) { - note (DCP_ERROR, "Subtitle movie titles differ"); + note (NoteType::ERROR, "Subtitle movie titles differ"); return false; } return true; } -list > + +vector> InteropSubtitleAsset::load_font_nodes () const { - list > lf; + vector> lf; copy (_load_font_nodes.begin(), _load_font_nodes.end(), back_inserter (lf)); return lf; } -/** Write this content to an XML file with its fonts alongside */ + void InteropSubtitleAsset::write (boost::filesystem::path p) const { - FILE* f = fopen_boost (p, "w"); + auto f = fopen_boost (p, "w"); if (!f) { throw FileError ("Could not open file for writing", p, -1); } - string const s = xml_as_string (); + _raw_xml = xml_as_string (); /* length() here gives bytes not characters */ - fwrite (s.c_str(), 1, s.length(), f); + fwrite (_raw_xml->c_str(), 1, _raw_xml->length(), f); fclose (f); _file = p; - BOOST_FOREACH (shared_ptr i, _load_font_nodes) { - boost::filesystem::path file = p.parent_path() / i->uri; - FILE* f = fopen_boost (file, "wb"); - if (!f) { - throw FileError ("could not open font file for writing", file, errno); + /* Image subtitles */ + for (auto i: _subtitles) { + auto im = dynamic_pointer_cast (i); + if (im) { + im->write_png_file(p.parent_path() / String::compose("%1.png", im->id())); } - list::const_iterator j = _fonts.begin (); + } + + /* Fonts */ + for (auto i: _load_font_nodes) { + auto file = p.parent_path() / i->uri; + auto j = _fonts.begin(); while (j != _fonts.end() && j->load_id != i->id) { ++j; } if (j != _fonts.end ()) { - fwrite (j->data.data().get(), 1, j->data.size(), f); + j->data.write (file); j->file = file; } - fclose (f); } } + +/** Look at a supplied list of assets and find the fonts. Then match these + * fonts up with anything requested by a so that _fonts contains + * a list of font ID, load ID and data. + */ void -InteropSubtitleAsset::resolve_fonts (list > assets) +InteropSubtitleAsset::resolve_fonts (vector> assets) { - BOOST_FOREACH (shared_ptr i, assets) { - shared_ptr font = dynamic_pointer_cast (i); + for (auto i: assets) { + auto font = dynamic_pointer_cast (i); if (!font) { continue; } - BOOST_FOREACH (shared_ptr j, _load_font_nodes) { - if (font->file() && j->uri == font->file()->leaf().string ()) { + for (auto j: _load_font_nodes) { + bool got = false; + for (auto const& k: _fonts) { + if (k.load_id == j->id) { + got = true; + break; + } + } + + if (!got && font->file() && j->uri == font->file()->leaf().string()) { _fonts.push_back (Font (j->id, i->id(), font->file().get())); } } } } + void -InteropSubtitleAsset::add_font_assets (list >& assets) +InteropSubtitleAsset::add_font_assets (vector>& assets) { - BOOST_FOREACH (Font const & i, _fonts) { + for (auto const& i: _fonts) { DCP_ASSERT (i.file); - assets.push_back (shared_ptr (new FontAsset (i.uuid, i.file.get ()))); + assets.push_back (make_shared(i.uuid, i.file.get())); + } +} + + +void +InteropSubtitleAsset::write_to_assetmap (xmlpp::Node* node, boost::filesystem::path root) const +{ + Asset::write_to_assetmap (node, root); + + for (auto i: _subtitles) { + auto im = dynamic_pointer_cast (i); + if (im) { + DCP_ASSERT (im->file()); + write_file_to_assetmap (node, root, im->file().get(), im->id()); + } } } + + +void +InteropSubtitleAsset::add_to_pkl (shared_ptr pkl, boost::filesystem::path root) const +{ + Asset::add_to_pkl (pkl, root); + + for (auto i: _subtitles) { + auto im = dynamic_pointer_cast (i); + if (im) { + auto png_image = im->png_image (); + pkl->add_asset (im->id(), optional(), make_digest(png_image), png_image.size(), "image/png"); + } + } +} + + +void +InteropSubtitleAsset::set_font_file (string load_id, boost::filesystem::path file) +{ + for (auto& i: _fonts) { + if (i.load_id == load_id) { + i.file = file; + } + } + + for (auto i: _load_font_nodes) { + if (i->id == load_id) { + i->uri = file.filename().string(); + } + } +} +