From a5adc9221d0af15f345cd3dbc76f37ee47fe65d5 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 28 Jun 2024 21:49:44 +0200 Subject: Subtitle{,String,Image} -> Text{,String,Image}. --- src/equality_options.h | 8 +- src/exceptions.cc | 4 +- src/exceptions.h | 4 +- src/interop_text_asset.cc | 25 ++--- src/smpte_text_asset.cc | 61 +++++----- src/smpte_text_asset.h | 10 +- src/subtitle.cc | 131 ---------------------- src/subtitle.h | 170 ---------------------------- src/subtitle_image.cc | 182 ------------------------------ src/subtitle_image.h | 124 --------------------- src/subtitle_string.cc | 272 --------------------------------------------- src/subtitle_string.h | 238 --------------------------------------- src/text.cc | 131 ++++++++++++++++++++++ src/text.h | 170 ++++++++++++++++++++++++++++ src/text_asset.cc | 91 ++++++++------- src/text_asset.h | 30 ++--- src/text_asset_internal.cc | 4 +- src/text_asset_internal.h | 4 +- src/text_image.cc | 182 ++++++++++++++++++++++++++++++ src/text_image.h | 124 +++++++++++++++++++++ src/text_string.cc | 272 +++++++++++++++++++++++++++++++++++++++++++++ src/text_string.h | 239 +++++++++++++++++++++++++++++++++++++++ src/types.h | 6 +- src/verify.cc | 8 +- src/wscript | 12 +- 25 files changed, 1250 insertions(+), 1252 deletions(-) delete mode 100644 src/subtitle.cc delete mode 100644 src/subtitle.h delete mode 100644 src/subtitle_image.cc delete mode 100644 src/subtitle_image.h delete mode 100644 src/subtitle_string.cc delete mode 100644 src/subtitle_string.h create mode 100644 src/text.cc create mode 100644 src/text.h create mode 100644 src/text_image.cc create mode 100644 src/text_image.h create mode 100644 src/text_string.cc create mode 100644 src/text_string.h (limited to 'src') diff --git a/src/equality_options.h b/src/equality_options.h index 1c29be7e..1e890a09 100644 --- a/src/equality_options.h +++ b/src/equality_options.h @@ -77,10 +77,10 @@ public: bool load_font_nodes_can_differ = false; bool sound_assets_can_differ = false; bool keep_going = false; - /** true to save the last pair of different image subtitles to the current working directory */ - bool export_differing_subtitles = false; - /** The maximum allowable absolute difference between the vertical position of subtitles */ - float max_subtitle_vertical_position_error = 0; + /** true to save the last pair of different image subtitles/captions to the current working directory */ + bool export_differing_texts = false; + /** The maximum allowable absolute difference between the vertical position of texts */ + float max_text_vertical_position_error = 0; }; diff --git a/src/exceptions.cc b/src/exceptions.cc index 9c57011d..4420125c 100644 --- a/src/exceptions.cc +++ b/src/exceptions.cc @@ -121,8 +121,8 @@ ReadError::ReadError (string message, string detail) } -MissingSubtitleImageError::MissingSubtitleImageError (string id) - : runtime_error (String::compose("Could not load image for subtitle %1", id)) +MissingTextImageError::MissingTextImageError (string id) + : runtime_error (String::compose("Could not load image for subtitle/caption %1", id)) { } diff --git a/src/exceptions.h b/src/exceptions.h index 3858b763..145df25f 100644 --- a/src/exceptions.h +++ b/src/exceptions.h @@ -259,10 +259,10 @@ public: }; -class MissingSubtitleImageError : public std::runtime_error +class MissingTextImageError : public std::runtime_error { public: - MissingSubtitleImageError (std::string id); + MissingTextImageError (std::string id); }; diff --git a/src/interop_text_asset.cc b/src/interop_text_asset.cc index 31d00712..e9d94bc8 100644 --- a/src/interop_text_asset.cc +++ b/src/interop_text_asset.cc @@ -47,7 +47,7 @@ #include "interop_text_asset.h" #include "raw_convert.h" #include "text_asset_internal.h" -#include "subtitle_image.h" +#include "text_image.h" #include "util.h" #include "warnings.h" #include "xml.h" @@ -89,12 +89,12 @@ InteropTextAsset::InteropTextAsset(boost::filesystem::path file) 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(), Standard::INTEROP); + parse_texts (e, ps, optional(), Standard::INTEROP); } } - for (auto i: _subtitles) { - auto si = dynamic_pointer_cast(i); + for (auto i: _texts) { + auto si = dynamic_pointer_cast(i); if (si) { si->read_png_file (file.parent_path() / String::compose("%1.png", si->id())); } @@ -126,7 +126,7 @@ InteropTextAsset::xml_as_string() const load_font->set_attribute ("URI", i->uri); } - subtitles_as_xml (root, 250, Standard::INTEROP); + texts_as_xml(root, 250, Standard::INTEROP); return format_xml(doc, {}); } @@ -174,7 +174,7 @@ InteropTextAsset::equals(shared_ptr other_asset, EqualityOptions co } if (_movie_title != other->_movie_title) { - note (NoteType::ERROR, "Subtitle movie titles differ"); + note (NoteType::ERROR, "Subtitle or caption movie titles differ"); return false; } @@ -206,9 +206,8 @@ InteropTextAsset::write(boost::filesystem::path p) const _file = p; /* Image subtitles */ - for (auto i: _subtitles) { - auto im = dynamic_pointer_cast (i); - if (im) { + for (auto i: _texts) { + if (auto im = dynamic_pointer_cast(i)) { im->write_png_file(p.parent_path() / String::compose("%1.png", im->id())); } } @@ -284,8 +283,8 @@ InteropTextAsset::add_to_assetmap(AssetMap& asset_map, boost::filesystem::path r { Asset::add_to_assetmap(asset_map, root); - for (auto i: _subtitles) { - auto im = dynamic_pointer_cast(i); + for (auto i: _texts) { + auto im = dynamic_pointer_cast(i); if (im) { DCP_ASSERT(im->file()); add_file_to_assetmap(asset_map, root, im->file().get(), im->id()); @@ -299,8 +298,8 @@ InteropTextAsset::add_to_pkl(shared_ptr pkl, boost::filesystem::path root) { Asset::add_to_pkl (pkl, root); - for (auto i: _subtitles) { - auto im = dynamic_pointer_cast (i); + for (auto i: _texts) { + 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", root.filename().string()); diff --git a/src/smpte_text_asset.cc b/src/smpte_text_asset.cc index 987715cb..f92a091a 100644 --- a/src/smpte_text_asset.cc +++ b/src/smpte_text_asset.cc @@ -46,7 +46,7 @@ #include "raw_convert.h" #include "smpte_load_font_node.h" #include "smpte_text_asset.h" -#include "subtitle_image.h" +#include "text_image.h" #include "util.h" #include "warnings.h" #include "xml.h" @@ -140,8 +140,8 @@ SMPTETextAsset::SMPTETextAsset(boost::filesystem::path file) /* Try to read PNG files from the same folder that the XML is in; the wisdom of this is debatable, at best... */ - for (auto i: _subtitles) { - auto im = dynamic_pointer_cast(i); + for (auto i: _texts) { + auto im = dynamic_pointer_cast(i); if (im && im->png_image().size() == 0) { /* Even more dubious; allow .png or urn:uuid:.png */ auto p = file.parent_path() / String::compose("%1.png", im->id()); @@ -159,10 +159,10 @@ SMPTETextAsset::SMPTETextAsset(boost::filesystem::path file) } /* Check that all required image data have been found */ - for (auto i: _subtitles) { - auto im = dynamic_pointer_cast(i); + for (auto i: _texts) { + auto im = dynamic_pointer_cast(i); if (im && im->png_image().size() == 0) { - throw MissingSubtitleImageError (im->id()); + throw MissingTextImageError (im->id()); } } } @@ -212,12 +212,12 @@ SMPTETextAsset::parse_xml(shared_ptr xml) for (auto i: xml->node()->get_children()) { auto const e = dynamic_cast(i); if (e && e->get_name() == "SubtitleList") { - parse_subtitles (e, ps, _time_code_rate, Standard::SMPTE); + parse_texts(e, ps, _time_code_rate, Standard::SMPTE); } } /* Guess intrinsic duration */ - _intrinsic_duration = latest_subtitle_out().as_editable_units_ceil(_edit_rate.numerator / _edit_rate.denominator); + _intrinsic_duration = latest_text_out().as_editable_units_ceil(_edit_rate.numerator / _edit_rate.denominator); } @@ -266,13 +266,13 @@ SMPTETextAsset::read_mxf_resources(shared_ptr reade } case ASDCP::TimedText::MT_PNG: { - auto j = _subtitles.begin(); - while (j != _subtitles.end() && ((!dynamic_pointer_cast(*j)) || dynamic_pointer_cast(*j)->id() != id)) { + auto j = _texts.begin(); + while (j != _texts.end() && ((!dynamic_pointer_cast(*j)) || dynamic_pointer_cast(*j)->id() != id)) { ++j; } - if (j != _subtitles.end()) { - dynamic_pointer_cast(*j)->set_png_image(ArrayData(buffer.RoData(), buffer.Size())); + if (j != _texts.end()) { + dynamic_pointer_cast(*j)->set_png_image(ArrayData(buffer.RoData(), buffer.Size())); } break; } @@ -396,7 +396,7 @@ SMPTETextAsset::xml_as_string() const load_font->set_attribute ("ID", i->id); } - subtitles_as_xml(cxml::add_child(root, "SubtitleList"), _time_code_rate, Standard::SMPTE); + texts_as_xml(cxml::add_child(root, "SubtitleList"), _time_code_rate, Standard::SMPTE); return format_xml(doc, std::make_pair(string{}, schema_namespace())); } @@ -433,8 +433,8 @@ SMPTETextAsset::write(boost::filesystem::path p) const /* Image subtitle references */ - for (auto i: _subtitles) { - auto si = dynamic_pointer_cast(i); + for (auto i: _texts) { + auto si = dynamic_pointer_cast(i); if (si) { ASDCP::TimedText::TimedTextResourceDescriptor res; unsigned int c; @@ -456,7 +456,7 @@ SMPTETextAsset::write(boost::filesystem::path p) const /* This header size is a guess. Empirically it seems that each subtitle reference is 90 bytes, and we need some extra. The default size is not enough for some feature-length PNG sub projects (see DCP-o-matic #1561). */ - ASDCP::Result_t r = writer.OpenWrite(dcp::filesystem::fix_long_path(p).string().c_str(), writer_info, descriptor, _subtitles.size() * 90 + 16384); + ASDCP::Result_t r = writer.OpenWrite(dcp::filesystem::fix_long_path(p).string().c_str(), writer_info, descriptor, _texts.size() * 90 + 16384); if (ASDCP_FAILURE (r)) { boost::throw_exception (FileError ("could not open subtitle MXF for writing", p.string(), r)); } @@ -489,9 +489,8 @@ SMPTETextAsset::write(boost::filesystem::path p) const /* Image subtitle payload */ - for (auto i: _subtitles) { - auto si = dynamic_pointer_cast(i); - if (si) { + for (auto i: _texts) { + if (auto si = dynamic_pointer_cast(i)) { ASDCP::TimedText::FrameBuffer buffer; buffer.SetData (si->png_image().data(), si->png_image().size()); buffer.Size (si->png_image().size()); @@ -516,7 +515,7 @@ SMPTETextAsset::equals(shared_ptr other_asset, EqualityOptions cons auto other = dynamic_pointer_cast(other_asset); if (!other) { - note (NoteType::ERROR, "Subtitles are in different standards"); + note (NoteType::ERROR, "Subtitles/captions are in different standards"); return false; } @@ -539,46 +538,46 @@ SMPTETextAsset::equals(shared_ptr other_asset, EqualityOptions cons } if (_content_title_text != other->_content_title_text) { - note (NoteType::ERROR, "Subtitle content title texts differ"); + note (NoteType::ERROR, "Subtitle/caption content title texts differ"); return false; } if (_language != other->_language) { - note (NoteType::ERROR, String::compose("Subtitle languages differ (`%1' vs `%2')", _language.get_value_or("[none]"), other->_language.get_value_or("[none]"))); + note (NoteType::ERROR, String::compose("Subtitle/caption languages differ (`%1' vs `%2')", _language.get_value_or("[none]"), other->_language.get_value_or("[none]"))); return false; } if (_annotation_text != other->_annotation_text) { - note (NoteType::ERROR, "Subtitle annotation texts differ"); + note (NoteType::ERROR, "Subtitle/caption annotation texts differ"); return false; } if (_issue_date != other->_issue_date) { if (options.issue_dates_can_differ) { - note (NoteType::NOTE, "Subtitle issue dates differ"); + note (NoteType::NOTE, "Subtitle/caption issue dates differ"); } else { - note (NoteType::ERROR, "Subtitle issue dates differ"); + note (NoteType::ERROR, "Subtitle/caption issue dates differ"); return false; } } if (_reel_number != other->_reel_number) { - note (NoteType::ERROR, "Subtitle reel numbers differ"); + note (NoteType::ERROR, "Subtitle/caption reel numbers differ"); return false; } if (_edit_rate != other->_edit_rate) { - note (NoteType::ERROR, "Subtitle edit rates differ"); + note (NoteType::ERROR, "Subtitle/caption edit rates differ"); return false; } if (_time_code_rate != other->_time_code_rate) { - note (NoteType::ERROR, "Subtitle time code rates differ"); + note (NoteType::ERROR, "Subtitle/caption time code rates differ"); return false; } if (_start_time != other->_start_time) { - note (NoteType::ERROR, "Subtitle start times differ"); + note (NoteType::ERROR, "Subtitle/caption start times differ"); return false; } @@ -596,10 +595,10 @@ SMPTETextAsset::add_font(string load_id, dcp::ArrayData data) void -SMPTETextAsset::add(shared_ptr s) +SMPTETextAsset::add(shared_ptr s) { TextAsset::add(s); - _intrinsic_duration = latest_subtitle_out().as_editable_units_ceil(_edit_rate.numerator / _edit_rate.denominator); + _intrinsic_duration = latest_text_out().as_editable_units_ceil(_edit_rate.numerator / _edit_rate.denominator); } diff --git a/src/smpte_text_asset.h b/src/smpte_text_asset.h index b5b95c5d..24665d3a 100644 --- a/src/smpte_text_asset.h +++ b/src/smpte_text_asset.h @@ -70,7 +70,7 @@ class SMPTELoadFontNode; /** @class SMPTETextAsset - * @brief A set of subtitles to be read and/or written in the SMPTE format + * @brief A set of subtitles/captions to be read and/or written in the SMPTE format */ class SMPTETextAsset : public TextAsset, public MXF { @@ -95,7 +95,7 @@ public: /** Write this content to a MXF file */ void write (boost::filesystem::path path) const override; - void add (std::shared_ptr) override; + void add(std::shared_ptr) override; void add_font (std::string id, dcp::ArrayData data) override; void set_key (Key key) override; @@ -135,7 +135,7 @@ public: return _intrinsic_duration; } - /** @return title of the film that these subtitles are for, + /** @return title of the film that these subtitles/captions are for, * to be presented to the user */ std::string content_title_text () const { @@ -167,8 +167,8 @@ public: return _edit_rate; } - /** @return subdivision of 1 second that is used for subtitle times; - * e.g. a time_code_rate of 250 means that a subtitle time of 0:0:0:001 + /** @return subdivision of 1 second that is used for text times; + * e.g. a time_code_rate of 250 means that a text time of 0:0:0:001 * represents 4ms. */ int time_code_rate () const override { diff --git a/src/subtitle.cc b/src/subtitle.cc deleted file mode 100644 index 248d0cff..00000000 --- a/src/subtitle.cc +++ /dev/null @@ -1,131 +0,0 @@ -/* - Copyright (C) 2012-2021 Carl Hetherington - - This file is part of libdcp. - - libdcp is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - libdcp is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with libdcp. If not, see . - - In addition, as a special exception, the copyright holders give - permission to link the code of portions of this program with the - OpenSSL library under certain conditions as described in each - individual source file, and distribute linked combinations - including the two. - - You must obey the GNU General Public License in all respects - for all of the code used other than OpenSSL. If you modify - file(s) with this exception, you may extend this exception to your - version of the file(s), but you are not obligated to do so. If you - do not wish to do so, delete this exception statement from your - version. If you delete this exception statement from all source - files in the program, then also delete it here. -*/ - - -/** @file src/subtitle.cc - * @brief Subtitle class - */ - - -#include "compose.hpp" -#include "dcp_time.h" -#include "equality_options.h" -#include "subtitle.h" - - -using std::shared_ptr; -using namespace dcp; - - -/** @param v_position Vertical position as a fraction of the screen height (between 0 and 1) from v_align */ -Subtitle::Subtitle ( - Time in, - Time out, - float h_position, - HAlign h_align, - float v_position, - VAlign v_align, - float z_position, - Time fade_up_time, - Time fade_down_time - ) - : _in (in) - , _out (out) - , _h_position (h_position) - , _h_align (h_align) - , _v_position (v_position) - , _v_align (v_align) - , _z_position(z_position) - , _fade_up_time (fade_up_time) - , _fade_down_time (fade_down_time) -{ - -} - - -bool -Subtitle::equals(shared_ptr other, EqualityOptions const& options, NoteHandler note) const -{ - bool same = true; - - if (in() != other->in()) { - note(NoteType::ERROR, "subtitle in times differ"); - same = false; - } - - if (out() != other->out()) { - note(NoteType::ERROR, "subtitle out times differ"); - same = false; - } - - if (h_position() != other->h_position()) { - note(NoteType::ERROR, "subtitle horizontal positions differ"); - same = false; - } - - if (h_align() != other->h_align()) { - note(NoteType::ERROR, "subtitle horizontal alignments differ"); - same = false; - } - - auto const vpos = std::abs(v_position() - other->v_position()); - if (vpos > options.max_subtitle_vertical_position_error) { - note( - NoteType::ERROR, - String::compose("subtitle vertical positions differ by %1 (more than the allowed difference of %2)", vpos, options.max_subtitle_vertical_position_error) - ); - same = false; - } - - if (v_align() != other->v_align()) { - note(NoteType::ERROR, "subtitle vertical alignments differ"); - same = false; - } - - if (z_position() != other->z_position()) { - note(NoteType::ERROR, "subtitle Z positions differ"); - same = false; - } - - if (fade_up_time() != other->fade_up_time()) { - note(NoteType::ERROR, "subtitle fade-up times differ"); - same = false; - } - - if (fade_down_time() != other->fade_down_time()) { - note(NoteType::ERROR, "subtitle fade-down times differ"); - same = false; - } - - return same; -} diff --git a/src/subtitle.h b/src/subtitle.h deleted file mode 100644 index 1ca3f9d4..00000000 --- a/src/subtitle.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - Copyright (C) 2012-2021 Carl Hetherington - - This file is part of libdcp. - - libdcp is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - libdcp is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with libdcp. If not, see . - - In addition, as a special exception, the copyright holders give - permission to link the code of portions of this program with the - OpenSSL library under certain conditions as described in each - individual source file, and distribute linked combinations - including the two. - - You must obey the GNU General Public License in all respects - for all of the code used other than OpenSSL. If you modify - file(s) with this exception, you may extend this exception to your - version of the file(s), but you are not obligated to do so. If you - do not wish to do so, delete this exception statement from your - version. If you delete this exception statement from all source - files in the program, then also delete it here. -*/ - - -/** @file src/subtitle.h - * @brief Subtitle class - */ - - -#ifndef LIBDCP_SUBTITLE_H -#define LIBDCP_SUBTITLE_H - - -#include "dcp_time.h" -#include "h_align.h" -#include "v_align.h" - - -namespace dcp { - - -class EqualityOptions; - - -class Subtitle -{ -public: - virtual ~Subtitle () {} - - /** @return subtitle start time (relative to the start of the reel) */ - Time in () const { - return _in; - } - - /** @return subtitle finish time (relative to the start of the reel) */ - Time out () const { - return _out; - } - - float h_position () const { - return _h_position; - } - - HAlign h_align () const { - return _h_align; - } - - /** @return vertical position as a proportion of the screen height from the - * vertical alignment point. - * (between 0 and 1) - */ - float v_position () const { - return _v_position; - } - - VAlign v_align () const { - return _v_align; - } - - float z_position() const { - return _z_position; - } - - Time fade_up_time () const { - return _fade_up_time; - } - - Time fade_down_time () const { - return _fade_down_time; - } - - void set_in (Time i) { - _in = i; - } - - void set_out (Time o) { - _out = o; - } - - void set_h_position (float p) { - _h_position = p; - } - - /** @param p New vertical position as a proportion of the screen height - * from the top (between 0 and 1) - */ - void set_v_position (float p) { - _v_position = p; - } - - void set_z_position(float z) { - _z_position = z; - } - - void set_fade_up_time (Time t) { - _fade_up_time = t; - } - - void set_fade_down_time (Time t) { - _fade_down_time = t; - } - - virtual bool equals(std::shared_ptr other, EqualityOptions const& options, NoteHandler note) const; - -protected: - - Subtitle ( - Time in, - Time out, - float h_position, - HAlign h_align, - float v_position, - VAlign v_align, - float z_position, - Time fade_up_time, - Time fade_down_time - ); - - Time _in; - Time _out; - /** Horizontal position as a proportion of the screen width from the _h_align - * (between 0 and 1) - */ - float _h_position = 0; - HAlign _h_align = HAlign::CENTER; - /** Vertical position as a proportion of the screen height from the _v_align - * (between 0 and 1) - */ - float _v_position = 0; - VAlign _v_align = VAlign::CENTER; - float _z_position = 0; - Time _fade_up_time; - Time _fade_down_time; -}; - - -} - - -#endif diff --git a/src/subtitle_image.cc b/src/subtitle_image.cc deleted file mode 100644 index 9340bc54..00000000 --- a/src/subtitle_image.cc +++ /dev/null @@ -1,182 +0,0 @@ -/* - Copyright (C) 2018-2021 Carl Hetherington - - This file is part of libdcp. - - libdcp is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - libdcp is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with libdcp. If not, see . - - In addition, as a special exception, the copyright holders give - permission to link the code of portions of this program with the - OpenSSL library under certain conditions as described in each - individual source file, and distribute linked combinations - including the two. - - You must obey the GNU General Public License in all respects - for all of the code used other than OpenSSL. If you modify - file(s) with this exception, you may extend this exception to your - version of the file(s), but you are not obligated to do so. If you - do not wish to do so, delete this exception statement from your - version. If you delete this exception statement from all source - files in the program, then also delete it here. -*/ - - -/** @file src/subtitle_image.cc - * @brief SubtitleImage class - */ - - -#include "equality_options.h" -#include "filesystem.h" -#include "subtitle_image.h" -#include "util.h" - - -using std::dynamic_pointer_cast; -using std::ostream; -using std::shared_ptr; -using std::string; -using namespace dcp; - - -SubtitleImage::SubtitleImage ( - ArrayData png_image, - Time in, - Time out, - float h_position, - HAlign h_align, - float v_position, - VAlign v_align, - float z_position, - Time fade_up_time, - Time fade_down_time - ) - : Subtitle(in, out, h_position, h_align, v_position, v_align, z_position, fade_up_time, fade_down_time) - , _png_image (png_image) - , _id (make_uuid ()) -{ - -} - - -SubtitleImage::SubtitleImage ( - ArrayData png_image, - string id, - Time in, - Time out, - float h_position, - HAlign h_align, - float v_position, - VAlign v_align, - float z_position, - Time fade_up_time, - Time fade_down_time - ) - : Subtitle(in, out, h_position, h_align, v_position, v_align, z_position, fade_up_time, fade_down_time) - , _png_image (png_image) - , _id (id) -{ - -} - - -void -SubtitleImage::read_png_file (boost::filesystem::path file) -{ - _file = file; - _png_image = ArrayData (file); -} - - -void -SubtitleImage::write_png_file (boost::filesystem::path file) const -{ - _file = file; - png_image().write (file); -} - - -bool -dcp::operator== (SubtitleImage const & a, SubtitleImage const & b) -{ - return ( - a.png_image() == b.png_image() && - a.id() == b.id() && - a.in() == b.in() && - a.out() == b.out() && - a.h_position() == b.h_position() && - a.h_align() == b.h_align() && - a.v_position() == b.v_position() && - a.v_align() == b.v_align() && - a.z_position() == b.z_position() && - a.fade_up_time() == b.fade_up_time() && - a.fade_down_time() == b.fade_down_time() - ); -} - - -bool -dcp::operator!= (SubtitleImage const & a, SubtitleImage const & b) -{ - return !(a == b); -} - - -bool -SubtitleImage::equals(shared_ptr other_sub, EqualityOptions const& options, NoteHandler note) const -{ - if (!Subtitle::equals(other_sub, options, note)) { - return false; - } - - auto other = dynamic_pointer_cast(other_sub); - if (!other) { - note(NoteType::ERROR, "Subtitle types differ: string vs image"); - return false; - } - - if (png_image() != other->png_image()) { - note (NoteType::ERROR, "subtitle image PNG data differs"); - if (options.export_differing_subtitles) { - string const base = "dcpdiff_subtitle_"; - if (filesystem::exists(base + "A.png")) { - note (NoteType::ERROR, "could not export subtitle as " + base + "A.png already exists"); - } else { - png_image().write(base + "A.png"); - } - if (filesystem::exists(base + "B.png")) { - note (NoteType::ERROR, "could not export subtitle as " + base + "B.png already exists"); - } else { - other->png_image().write(base + "B.png"); - } - } - return false; - } - - return true; -} - - -ostream& -dcp::operator<< (ostream& s, SubtitleImage const & sub) -{ - s << "\n[IMAGE] from " << sub.in() << " to " << sub.out() << ";\n" - << "fade up " << sub.fade_up_time() << ", fade down " << sub.fade_down_time() << ";\n" - << "v pos " << sub.v_position() << ", valign " << ((int) sub.v_align()) - << ", hpos " << sub.h_position() << ", halign " << ((int) sub.h_align()) - << ", zpos " << sub.z_position() << "\n"; - - return s; -} - diff --git a/src/subtitle_image.h b/src/subtitle_image.h deleted file mode 100644 index ae733fe4..00000000 --- a/src/subtitle_image.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - Copyright (C) 2018-2021 Carl Hetherington - - This file is part of libdcp. - - libdcp is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - libdcp is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with libdcp. If not, see . - - In addition, as a special exception, the copyright holders give - permission to link the code of portions of this program with the - OpenSSL library under certain conditions as described in each - individual source file, and distribute linked combinations - including the two. - - You must obey the GNU General Public License in all respects - for all of the code used other than OpenSSL. If you modify - file(s) with this exception, you may extend this exception to your - version of the file(s), but you are not obligated to do so. If you - do not wish to do so, delete this exception statement from your - version. If you delete this exception statement from all source - files in the program, then also delete it here. -*/ - - -/** @file src/subtitle_image.h - * @brief SubtitleImage class - */ - - -#ifndef LIBDCP_SUBTITLE_IMAGE_H -#define LIBDCP_SUBTITLE_IMAGE_H - - -#include "array_data.h" -#include "subtitle.h" -#include "dcp_time.h" -#include -#include - - -namespace dcp { - - -/** @class SubtitleImage - * @brief A bitmap subtitle with all the associated attributes - */ -class SubtitleImage : public Subtitle -{ -public: - SubtitleImage ( - ArrayData png_image, - Time in, - Time out, - float h_position, - HAlign h_align, - float v_position, - VAlign v_align, - float z_position, - Time fade_up_time, - Time fade_down_time - ); - - SubtitleImage ( - ArrayData png_image, - std::string id, - Time in, - Time out, - float h_position, - HAlign h_align, - float v_position, - VAlign v_align, - float z_position, - Time fade_up_time, - Time fade_down_time - ); - - ArrayData png_image () const { - return _png_image; - } - - void set_png_image (ArrayData png) { - _png_image = png; - } - - void read_png_file (boost::filesystem::path file); - void write_png_file (boost::filesystem::path file) const; - - std::string id () const { - return _id; - } - - /** @return the most recent disk file used to read or write this asset, if there is one */ - boost::optional file () const { - return _file; - } - - bool equals(std::shared_ptr other_sub, EqualityOptions const& options, NoteHandler note) const override; - -private: - ArrayData _png_image; - std::string _id; - mutable boost::optional _file; -}; - - -bool operator== (SubtitleImage const & a, SubtitleImage const & b); -bool operator!= (SubtitleImage const & a, SubtitleImage const & b); -std::ostream& operator<< (std::ostream& s, SubtitleImage const & sub); - - -} - - -#endif diff --git a/src/subtitle_string.cc b/src/subtitle_string.cc deleted file mode 100644 index af61d928..00000000 --- a/src/subtitle_string.cc +++ /dev/null @@ -1,272 +0,0 @@ -/* - Copyright (C) 2012-2021 Carl Hetherington - - This file is part of libdcp. - - libdcp is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - libdcp is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with libdcp. If not, see . - - In addition, as a special exception, the copyright holders give - permission to link the code of portions of this program with the - OpenSSL library under certain conditions as described in each - individual source file, and distribute linked combinations - including the two. - - You must obey the GNU General Public License in all respects - for all of the code used other than OpenSSL. If you modify - file(s) with this exception, you may extend this exception to your - version of the file(s), but you are not obligated to do so. If you - do not wish to do so, delete this exception statement from your - version. If you delete this exception statement from all source - files in the program, then also delete it here. -*/ - - -/** @file src/subtitle_string.cc - * @brief SubtitleString class - */ - - -#include "compose.hpp" -#include "subtitle_string.h" -#include "xml.h" -#include - - -using std::dynamic_pointer_cast; -using std::max; -using std::min; -using std::ostream; -using std::shared_ptr; -using std::string; -using std::vector; -using boost::optional; -using namespace dcp; - - -SubtitleString::SubtitleString ( - optional font, - bool italic, - bool bold, - bool underline, - Colour colour, - int size, - float aspect_adjust, - Time in, - Time out, - float h_position, - HAlign h_align, - float v_position, - VAlign v_align, - float z_position, - Direction direction, - string text, - Effect effect, - Colour effect_colour, - Time fade_up_time, - Time fade_down_time, - float space_before, - vector rubies - ) - : Subtitle(in, out, h_position, h_align, v_position, v_align, z_position, fade_up_time, fade_down_time) - , _font (font) - , _italic (italic) - , _bold (bold) - , _underline (underline) - , _colour (colour) - , _size (size) - , _aspect_adjust (aspect_adjust) - , _direction (direction) - , _text (text) - , _effect (effect) - , _effect_colour (effect_colour) - , _space_before (space_before) - , _rubies(rubies) -{ - _aspect_adjust = max(min(_aspect_adjust, 4.0f), 0.25f); -} - - -float -SubtitleString::size_in_pixels (int screen_height) const -{ - /* Size in the subtitle file is given in points as if the screen - height is 11 inches, so a 72pt font would be 1/11th of the screen - height. - */ - - return _size * static_cast(screen_height) / (11.0f * 72.0f); -} - - -bool -dcp::operator== (SubtitleString const & a, SubtitleString const & b) -{ - return ( - a.font() == b.font() && - a.italic() == b.italic() && - a.bold() == b.bold() && - a.underline() == b.underline() && - a.colour() == b.colour() && - a.size() == b.size() && - fabs (a.aspect_adjust() - b.aspect_adjust()) < ASPECT_ADJUST_EPSILON && - a.in() == b.in() && - a.out() == b.out() && - a.h_position() == b.h_position() && - a.h_align() == b.h_align() && - a.v_position() == b.v_position() && - a.v_align() == b.v_align() && - a.z_position() == b.z_position() && - a.direction() == b.direction() && - a.text() == b.text() && - a.effect() == b.effect() && - a.effect_colour() == b.effect_colour() && - a.fade_up_time() == b.fade_up_time() && - a.fade_down_time() == b.fade_down_time() && - fabs (a.space_before() - b.space_before()) < SPACE_BEFORE_EPSILON && - a.rubies() == b.rubies() - ); -} - - -bool -dcp::operator!= (SubtitleString const & a, SubtitleString const & b) -{ - return !(a == b); -} - - -ostream& -dcp::operator<< (ostream& s, SubtitleString const & sub) -{ - s << "\n`" << sub.text() << "' from " << sub.in() << " to " << sub.out() << ";\n" - << "fade up " << sub.fade_up_time() << ", fade down " << sub.fade_down_time() << ";\n" - << "font " << sub.font().get_value_or ("[default]") << ", "; - - if (sub.italic()) { - s << "italic, "; - } else { - s << "non-italic, "; - } - - if (sub.bold()) { - s << "bold, "; - } else { - s << "normal, "; - } - - if (sub.underline()) { - s << "underlined, "; - } - - s << "size " << sub.size() << ", aspect " << sub.aspect_adjust() - << ", colour (" << sub.colour().r << ", " << sub.colour().g << ", " << sub.colour().b << ")" - << ", vpos " << sub.v_position() << ", valign " << ((int) sub.v_align()) - << ", hpos " << sub.h_position() << ", halign " << ((int) sub.h_align()) - << ", zpos " << sub.z_position() - << ", direction " << ((int) sub.direction()) - << ", effect " << ((int) sub.effect()) - << ", effect colour (" << sub.effect_colour().r << ", " << sub.effect_colour().g << ", " << sub.effect_colour().b << ")" - << ", space before " << sub.space_before(); - - for (auto ruby: sub.rubies()) { - s << ", ruby " << ruby.base << " " << ruby.annotation; - } - - return s; -} - - -bool -SubtitleString::equals(shared_ptr other_sub, EqualityOptions const& options, NoteHandler note) const -{ - if (!Subtitle::equals(other_sub, options, note)) { - return false; - } - - auto other = dynamic_pointer_cast(other_sub); - if (!other) { - note(NoteType::ERROR, "Subtitle types differ: string vs image"); - return false; - } - - bool same = true; - - if (_font != other->_font) { - note(NoteType::ERROR, String::compose("subtitle font differs: %1 vs %2", _font.get_value_or("[none]"), other->_font.get_value_or("[none]"))); - same = false; - } - - if (_italic != other->_italic) { - note(NoteType::ERROR, String::compose("subtitle italic flag differs: %1 vs %2", _italic ? "true" : "false", other->_italic ? "true" : "false")); - same = false; - } - - if (_bold != other->_bold) { - note(NoteType::ERROR, String::compose("subtitle bold flag differs: %1 vs %2", _bold ? "true" : "false", other->_bold ? "true" : "false")); - same = false; - } - - if (_underline != other->_underline) { - note(NoteType::ERROR, String::compose("subtitle underline flag differs: %1 vs %2", _underline ? "true" : "false", other->_underline ? "true" : "false")); - same = false; - } - - if (_colour != other->_colour) { - note(NoteType::ERROR, String::compose("subtitle colour differs: %1 vs %2", _colour.to_rgb_string(), other->_colour.to_rgb_string())); - same = false; - } - - if (_size != other->_size) { - note(NoteType::ERROR, String::compose("subtitle size differs: %1 vs %2", _size, other->_size)); - same = false; - } - - if (_aspect_adjust != other->_aspect_adjust) { - note(NoteType::ERROR, String::compose("subtitle aspect_adjust differs: %1 vs %2", _aspect_adjust, other->_aspect_adjust)); - same = false; - } - - if (_direction != other->_direction) { - note(NoteType::ERROR, String::compose("subtitle direction differs: %1 vs %2", direction_to_string(_direction), direction_to_string(other->_direction))); - same = false; - } - - if (_text != other->_text) { - note(NoteType::ERROR, String::compose("subtitle text differs: %1 vs %2", _text, other->_text)); - same = false; - } - - if (_effect != other->_effect) { - note(NoteType::ERROR, String::compose("subtitle effect differs: %1 vs %2", effect_to_string(_effect), effect_to_string(other->_effect))); - same = false; - } - - if (_effect_colour != other->_effect_colour) { - note(NoteType::ERROR, String::compose("subtitle effect colour differs: %1 vs %2", _effect_colour.to_rgb_string(), other->_effect_colour.to_rgb_string())); - same = false; - } - - if (_space_before != other->_space_before) { - note(NoteType::ERROR, String::compose("subtitle space before differs: %1 vs %2", _space_before, other->_space_before)); - same = false; - } - - if (_rubies != other->_rubies) { - note(NoteType::ERROR, "rubies differ"); - same = false; - } - - return same; -} - diff --git a/src/subtitle_string.h b/src/subtitle_string.h deleted file mode 100644 index 1ef57ff2..00000000 --- a/src/subtitle_string.h +++ /dev/null @@ -1,238 +0,0 @@ -/* - Copyright (C) 2012-2021 Carl Hetherington - - This file is part of libdcp. - - libdcp is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - libdcp is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with libdcp. If not, see . - - In addition, as a special exception, the copyright holders give - permission to link the code of portions of this program with the - OpenSSL library under certain conditions as described in each - individual source file, and distribute linked combinations - including the two. - - You must obey the GNU General Public License in all respects - for all of the code used other than OpenSSL. If you modify - file(s) with this exception, you may extend this exception to your - version of the file(s), but you are not obligated to do so. If you - do not wish to do so, delete this exception statement from your - version. If you delete this exception statement from all source - files in the program, then also delete it here. -*/ - - -/** @file src/subtitle_string.h - * @brief SubtitleString class - */ - - -#ifndef LIBDCP_SUBTITLE_STRING_H -#define LIBDCP_SUBTITLE_STRING_H - - -#include "dcp_time.h" -#include "ruby.h" -#include "subtitle.h" -#include -#include - - -namespace dcp { - - -/** @class SubtitleString - * @brief A single line of subtitle text with all the associated attributes. - */ -class SubtitleString : public Subtitle -{ -public: - /** @param font Font ID, or empty to use the default - * @param italic true for italic text - * @param bold true for bold text - * @param underline true for underlined text - * @param colour Colour of the text - * @param size Size in points as if the screen height is 11 inches, so a 72pt font would be 1/11th of the screen height - * @param aspect_adjust greater than 1 to stretch text to be wider, less than 1 to shrink text to be narrower (must be between 0.25 and 4) - * @param in start time - * @param out finish time - * @param h_position Horizontal position as a fraction of the screen width (between 0 and 1) from h_align - * @param h_align Horizontal alignment point - * @param v_position Vertical position as a fraction of the screen height (between 0 and 1) from v_align - * @param v_align Vertical alignment point - * @param z_position Z position as a proportion of the primary picture width between -1 and +1; - * +ve moves the image away from the viewer, -ve moves it toward the viewer, 0 is in the plane of the screen. - * @param direction Direction of text - * @param text The text to display - * @param effect Effect to use - * @param effect_colour Colour of the effect - * @param fade_up_time Time to fade the text in - * @param fade_down_time Time to fade the text out - * @param space_before Space to add before this string, in ems (could be negative to remove space). - */ - SubtitleString ( - boost::optional font, - bool italic, - bool bold, - bool underline, - Colour colour, - int size, - float aspect_adjust, - Time in, - Time out, - float h_position, - HAlign h_align, - float v_position, - VAlign v_align, - float z_position, - Direction direction, - std::string text, - Effect effect, - Colour effect_colour, - Time fade_up_time, - Time fade_down_time, - float space_before, - std::vector rubies - ); - - /** @return font ID */ - boost::optional font () const { - return _font; - } - - bool italic () const { - return _italic; - } - - bool bold () const { - return _bold; - } - - bool underline () const { - return _underline; - } - - Colour colour () const { - return _colour; - } - - std::string text () const { - return _text; - } - - Direction direction () const { - return _direction; - } - - Effect effect () const { - return _effect; - } - - Colour effect_colour () const { - return _effect_colour; - } - - int size () const { - return _size; - } - - float size_in_pixels (int screen_height) const; - - float space_before () const { - return _space_before; - } - - /** @return Aspect ratio `adjustment' of the font size. - * Values greater than 1 widen each character, values less than 1 narrow each character, - * and the value must be between 0.25 and 4. - */ - float aspect_adjust () const { - return _aspect_adjust; - } - - std::vector const& rubies() const { - return _rubies; - } - - void set_font (std::string id) { - _font = id; - } - - void unset_font () { - _font = boost::optional(); - } - - void set_size (int s) { - _size = s; - } - - void set_aspect_adjust (float a) { - _aspect_adjust = a; - } - - void set_text (std::string t) { - _text = t; - } - - void set_colour (Colour c) { - _colour = c; - } - - void set_effect (Effect e) { - _effect = e; - } - - void set_effect_colour (Colour c) { - _effect_colour = c; - } - - void set_rubies(std::vector rubies) { - _rubies = std::move(rubies); - } - - bool equals(std::shared_ptr other_sub, EqualityOptions const& options, NoteHandler node) const override; - -private: - /** font ID */ - boost::optional _font; - /** true if the text is italic */ - bool _italic; - /** true if the weight is bold, false for normal */ - bool _bold; - /** true to enable underlining, false otherwise */ - bool _underline; - /** text colour */ - Colour _colour; - /** Size in points as if the screen height is 11 inches, so a 72pt font - * would be 1/11th of the screen height. - */ - int _size; - float _aspect_adjust; - Direction _direction; - std::string _text; - Effect _effect; - Colour _effect_colour; - float _space_before; - std::vector _rubies; -}; - -bool operator== (SubtitleString const & a, SubtitleString const & b); -bool operator!= (SubtitleString const & a, SubtitleString const & b); -std::ostream& operator<< (std::ostream& s, SubtitleString const & sub); - - -} - - -#endif - diff --git a/src/text.cc b/src/text.cc new file mode 100644 index 00000000..158af38c --- /dev/null +++ b/src/text.cc @@ -0,0 +1,131 @@ +/* + Copyright (C) 2012-2021 Carl Hetherington + + This file is part of libdcp. + + libdcp is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + libdcp is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libdcp. If not, see . + + In addition, as a special exception, the copyright holders give + permission to link the code of portions of this program with the + OpenSSL library under certain conditions as described in each + individual source file, and distribute linked combinations + including the two. + + You must obey the GNU General Public License in all respects + for all of the code used other than OpenSSL. If you modify + file(s) with this exception, you may extend this exception to your + version of the file(s), but you are not obligated to do so. If you + do not wish to do so, delete this exception statement from your + version. If you delete this exception statement from all source + files in the program, then also delete it here. +*/ + + +/** @file src/text.cc + * @brief Text class + */ + + +#include "compose.hpp" +#include "dcp_time.h" +#include "equality_options.h" +#include "text.h" + + +using std::shared_ptr; +using namespace dcp; + + +/** @param v_position Vertical position as a fraction of the screen height (between 0 and 1) from v_align */ +Text::Text( + Time in, + Time out, + float h_position, + HAlign h_align, + float v_position, + VAlign v_align, + float z_position, + Time fade_up_time, + Time fade_down_time + ) + : _in (in) + , _out (out) + , _h_position (h_position) + , _h_align (h_align) + , _v_position (v_position) + , _v_align (v_align) + , _z_position(z_position) + , _fade_up_time (fade_up_time) + , _fade_down_time (fade_down_time) +{ + +} + + +bool +Text::equals(shared_ptr other, EqualityOptions const& options, NoteHandler note) const +{ + bool same = true; + + if (in() != other->in()) { + note(NoteType::ERROR, "text in times differ"); + same = false; + } + + if (out() != other->out()) { + note(NoteType::ERROR, "text out times differ"); + same = false; + } + + if (h_position() != other->h_position()) { + note(NoteType::ERROR, "text horizontal positions differ"); + same = false; + } + + if (h_align() != other->h_align()) { + note(NoteType::ERROR, "text horizontal alignments differ"); + same = false; + } + + auto const vpos = std::abs(v_position() - other->v_position()); + if (vpos > options.max_text_vertical_position_error) { + note( + NoteType::ERROR, + String::compose("text vertical positions differ by %1 (more than the allowed difference of %2)", vpos, options.max_text_vertical_position_error) + ); + same = false; + } + + if (v_align() != other->v_align()) { + note(NoteType::ERROR, "text vertical alignments differ"); + same = false; + } + + if (z_position() != other->z_position()) { + note(NoteType::ERROR, "text Z positions differ"); + same = false; + } + + if (fade_up_time() != other->fade_up_time()) { + note(NoteType::ERROR, "text fade-up times differ"); + same = false; + } + + if (fade_down_time() != other->fade_down_time()) { + note(NoteType::ERROR, "text fade-down times differ"); + same = false; + } + + return same; +} diff --git a/src/text.h b/src/text.h new file mode 100644 index 00000000..b8f15757 --- /dev/null +++ b/src/text.h @@ -0,0 +1,170 @@ +/* + Copyright (C) 2012-2021 Carl Hetherington + + This file is part of libdcp. + + libdcp is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + libdcp is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libdcp. If not, see . + + In addition, as a special exception, the copyright holders give + permission to link the code of portions of this program with the + OpenSSL library under certain conditions as described in each + individual source file, and distribute linked combinations + including the two. + + You must obey the GNU General Public License in all respects + for all of the code used other than OpenSSL. If you modify + file(s) with this exception, you may extend this exception to your + version of the file(s), but you are not obligated to do so. If you + do not wish to do so, delete this exception statement from your + version. If you delete this exception statement from all source + files in the program, then also delete it here. +*/ + + +/** @file src/text.h + * @brief Text class + */ + + +#ifndef LIBDCP_TEXT_H +#define LIBDCP_TEXT_H + + +#include "dcp_time.h" +#include "h_align.h" +#include "v_align.h" + + +namespace dcp { + + +class EqualityOptions; + + +class Text +{ +public: + virtual ~Text() {} + + /** @return text start time (relative to the start of the reel) */ + Time in () const { + return _in; + } + + /** @return text finish time (relative to the start of the reel) */ + Time out () const { + return _out; + } + + float h_position () const { + return _h_position; + } + + HAlign h_align () const { + return _h_align; + } + + /** @return vertical position as a proportion of the screen height from the + * vertical alignment point. + * (between 0 and 1) + */ + float v_position () const { + return _v_position; + } + + VAlign v_align () const { + return _v_align; + } + + float z_position() const { + return _z_position; + } + + Time fade_up_time () const { + return _fade_up_time; + } + + Time fade_down_time () const { + return _fade_down_time; + } + + void set_in (Time i) { + _in = i; + } + + void set_out (Time o) { + _out = o; + } + + void set_h_position (float p) { + _h_position = p; + } + + /** @param p New vertical position as a proportion of the screen height + * from the top (between 0 and 1) + */ + void set_v_position (float p) { + _v_position = p; + } + + void set_z_position(float z) { + _z_position = z; + } + + void set_fade_up_time (Time t) { + _fade_up_time = t; + } + + void set_fade_down_time (Time t) { + _fade_down_time = t; + } + + virtual bool equals(std::shared_ptr other, EqualityOptions const& options, NoteHandler note) const; + +protected: + + Text( + Time in, + Time out, + float h_position, + HAlign h_align, + float v_position, + VAlign v_align, + float z_position, + Time fade_up_time, + Time fade_down_time + ); + + Time _in; + Time _out; + /** Horizontal position as a proportion of the screen width from the _h_align + * (between 0 and 1) + */ + float _h_position = 0; + HAlign _h_align = HAlign::CENTER; + /** Vertical position as a proportion of the screen height from the _v_align + * (between 0 and 1) + */ + float _v_position = 0; + VAlign _v_align = VAlign::CENTER; + float _z_position = 0; + Time _fade_up_time; + Time _fade_down_time; +}; + + +} + + +#endif diff --git a/src/text_asset.cc b/src/text_asset.cc index 4ba3b623..ff662b69 100644 --- a/src/text_asset.cc +++ b/src/text_asset.cc @@ -42,8 +42,8 @@ #include "load_font_node.h" #include "raw_convert.h" #include "reel_asset.h" -#include "subtitle_image.h" -#include "subtitle_string.h" +#include "text_image.h" +#include "text_string.h" #include "text_asset.h" #include "text_asset_internal.h" #include "util.h" @@ -276,7 +276,7 @@ TextAsset::fade_time(xmlpp::Element const * node, string name, optional tcr void -TextAsset::parse_subtitles(xmlpp::Element const * node, vector& state, optional tcr, Standard standard) +TextAsset::parse_texts(xmlpp::Element const * node, vector& state, optional tcr, Standard standard) { if (node->get_name() == "Font") { state.push_back (font_node_state (node, standard)); @@ -366,7 +366,7 @@ TextAsset::parse_subtitles(xmlpp::Element const * node, vector& stat /* Handle actual content e.g. text */ auto const v = dynamic_cast(i); if (v) { - maybe_add_subtitle (v->get_content(), state, space_before, standard, rubies); + maybe_add_text(v->get_content(), state, space_before, standard, rubies); space_before = 0; } @@ -383,7 +383,7 @@ TextAsset::parse_subtitles(xmlpp::Element const * node, vector& stat } space_before += raw_convert(size); } else if (e->get_name() != "Ruby") { - parse_subtitles (e, state, tcr, standard); + parse_texts (e, state, tcr, standard); } } } @@ -393,7 +393,7 @@ TextAsset::parse_subtitles(xmlpp::Element const * node, vector& stat void -TextAsset::maybe_add_subtitle( +TextAsset::maybe_add_text( string text, vector const & parse_state, float space_before, @@ -482,8 +482,8 @@ TextAsset::maybe_add_subtitle( switch (ps.type.get()) { case ParseState::Type::TEXT: - _subtitles.push_back ( - make_shared( + _texts.push_back ( + make_shared( ps.font_id, ps.italic.get_value_or (false), ps.bold.get_value_or (false), @@ -530,9 +530,9 @@ TextAsset::maybe_add_subtitle( break; } - /* Add a subtitle with no image data and we'll fill that in later */ - _subtitles.push_back ( - make_shared( + /* Add a text with no image data and we'll fill that in later */ + _texts.push_back( + make_shared( ArrayData(), text, ps.in.get(), @@ -552,22 +552,22 @@ TextAsset::maybe_add_subtitle( } -vector> -TextAsset::subtitles() const +vector> +TextAsset::texts() const { - vector> s; - for (auto i: _subtitles) { + vector> s; + for (auto i: _texts) { s.push_back (i); } return s; } -vector> -TextAsset::subtitles_during(Time from, Time to, bool starting) const +vector> +TextAsset::texts_during(Time from, Time to, bool starting) const { - vector> s; - for (auto i: _subtitles) { + vector> s; + for (auto i: _texts) { if ((starting && from <= i->in() && i->in() < to) || (!starting && i->out() >= from && i->in() <= to)) { s.push_back (i); } @@ -578,17 +578,17 @@ TextAsset::subtitles_during(Time from, Time to, bool starting) const void -TextAsset::add(shared_ptr s) +TextAsset::add(shared_ptr s) { - _subtitles.push_back (s); + _texts.push_back(s); } Time -TextAsset::latest_subtitle_out() const +TextAsset::latest_text_out() const { Time t; - for (auto i: _subtitles) { + for (auto i: _texts) { if (i->out() > t) { t = i->out (); } @@ -610,22 +610,22 @@ TextAsset::equals(shared_ptr other_asset, EqualityOptions const& op return false; } - if (_subtitles.size() != other->_subtitles.size()) { - note (NoteType::ERROR, String::compose("different number of subtitles: %1 vs %2", _subtitles.size(), other->_subtitles.size())); + if (_texts.size() != other->_texts.size()) { + note (NoteType::ERROR, String::compose("different number of texts: %1 vs %2", _texts.size(), other->_texts.size())); return false; } - auto i = _subtitles.begin(); - auto j = other->_subtitles.begin(); + auto i = _texts.begin(); + auto j = other->_texts.begin(); - while (i != _subtitles.end()) { - auto string_i = dynamic_pointer_cast (*i); - auto string_j = dynamic_pointer_cast (*j); - auto image_i = dynamic_pointer_cast (*i); - auto image_j = dynamic_pointer_cast (*j); + while (i != _texts.end()) { + auto string_i = dynamic_pointer_cast(*i); + auto string_j = dynamic_pointer_cast(*j); + auto image_i = dynamic_pointer_cast(*i); + auto image_j = dynamic_pointer_cast(*j); if ((string_i && !string_j) || (image_i && !image_j)) { - note (NoteType::ERROR, "subtitles differ: string vs. image"); + note (NoteType::ERROR, "texts differ: string vs. image"); return false; } @@ -645,9 +645,9 @@ TextAsset::equals(shared_ptr other_asset, EqualityOptions const& op } -struct SubtitleSorter +struct TextSorter { - bool operator() (shared_ptr a, shared_ptr b) { + bool operator()(shared_ptr a, shared_ptr b) { if (a->in() != b->in()) { return a->in() < b->in(); } @@ -724,12 +724,12 @@ TextAsset::pull_fonts(shared_ptr part) * class because the differences between the two are fairly subtle. */ void -TextAsset::subtitles_as_xml(xmlpp::Element* xml_root, int time_code_rate, Standard standard) const +TextAsset::texts_as_xml(xmlpp::Element* xml_root, int time_code_rate, Standard standard) const { - auto sorted = _subtitles; - std::stable_sort(sorted.begin(), sorted.end(), SubtitleSorter()); + auto sorted = _texts; + std::stable_sort(sorted.begin(), sorted.end(), TextSorter()); - /* Gather our subtitles into a hierarchy of Subtitle/Text/String objects, writing + /* Gather our texts into a hierarchy of Subtitle/Text/String objects, writing font information into the bottom level (String) objects. */ @@ -766,7 +766,7 @@ TextAsset::subtitles_as_xml(xmlpp::Element* xml_root, int time_code_rate, Standa text.reset (); } - auto is = dynamic_pointer_cast(i); + auto is = dynamic_pointer_cast(i); if (is) { if (!text || last_h_align != is->h_align() || @@ -799,8 +799,7 @@ TextAsset::subtitles_as_xml(xmlpp::Element* xml_root, int time_code_rate, Standa text->children.push_back (make_shared(text, order::Font (is, standard), is->text(), is->space_before())); } - auto ii = dynamic_pointer_cast(i); - if (ii) { + if (auto ii = dynamic_pointer_cast(i)) { text.reset (); subtitle->children.push_back ( make_shared(subtitle, ii->id(), ii->png_image(), ii->h_align(), ii->h_position(), ii->v_align(), ii->v_position(), ii->z_position()) @@ -876,8 +875,8 @@ TextAsset::fix_empty_font_ids() } } - for (auto i: _subtitles) { - auto j = dynamic_pointer_cast (i); + for (auto i: _texts) { + auto j = dynamic_pointer_cast(i); if (j && j->font() && j->font().get() == "") { j->set_font (empty_id); } @@ -957,8 +956,8 @@ format_xml_node (xmlpp::Node const* node, State& state) /** Format XML much as write_to_string_formatted() would do, except without adding any white space - * to nodes. This is an attempt to avoid changing what is actually displayed as subtitles - * while also formatting the XML in such a way as to avoid DoM bug 2205. + * to nodes. This is an attempt to avoid changing what is actually displayed while also + * formatting the XML in such a way as to avoid DoM bug 2205. * * xml_namespace is an optional namespace for the root node; it would be nicer to set this up with * set_namespace_declaration in the caller and then to extract it here but I couldn't find a way diff --git a/src/text_asset.h b/src/text_asset.h index e1cb48c7..4d739027 100644 --- a/src/text_asset.h +++ b/src/text_asset.h @@ -45,7 +45,7 @@ #include "asset.h" #include "dcp_time.h" #include "subtitle_standard.h" -#include "subtitle_string.h" +#include "text_string.h" #include #include #include @@ -70,13 +70,13 @@ struct pull_fonts_test3; namespace dcp { -class SubtitleString; -class SubtitleImage; class FontNode; -class TextNode; -class SubtitleNode; class LoadFontNode; class ReelAsset; +class SubtitleNode; +class TextImage; +class TextNode; +class TextString; namespace order { @@ -88,7 +88,7 @@ namespace order { /** @class TextAsset * @brief A parent for classes representing a file containing subtitles or captions * - * This class holds a list of Subtitle objects which it can extract + * This class holds a list of Text objects which it can extract * from the appropriate part of either an Interop or SMPTE XML file. * Its subclasses InteropTextAsset and SMPTETextAsset handle the * differences between the two types. @@ -105,10 +105,10 @@ public: NoteHandler note ) const override; - std::vector> subtitles_during (Time from, Time to, bool starting) const; - std::vector> subtitles () const; + std::vector> texts_during(Time from, Time to, bool starting) const; + std::vector> texts() const; - virtual void add (std::shared_ptr); + virtual void add(std::shared_ptr); virtual void add_font (std::string id, dcp::ArrayData data) = 0; void ensure_font(std::string id, dcp::ArrayData data); std::map font_data () const; @@ -117,7 +117,7 @@ public: virtual void write (boost::filesystem::path) const = 0; virtual std::string xml_as_string () const = 0; - Time latest_subtitle_out () const; + Time latest_text_out() const; void fix_empty_font_ids (); @@ -169,7 +169,7 @@ protected: float space_before = 0; }; - void parse_subtitles (xmlpp::Element const * node, std::vector& state, boost::optional tcr, Standard standard); + void parse_texts(xmlpp::Element const * node, std::vector& state, boost::optional tcr, Standard standard); ParseState font_node_state (xmlpp::Element const * node, Standard standard) const; ParseState text_node_state (xmlpp::Element const * node) const; ParseState image_node_state (xmlpp::Element const * node) const; @@ -177,10 +177,10 @@ protected: Time fade_time (xmlpp::Element const * node, std::string name, boost::optional tcr) const; void position_align (ParseState& ps, xmlpp::Element const * node) const; - void subtitles_as_xml (xmlpp::Element* root, int time_code_rate, Standard standard) const; + void texts_as_xml(xmlpp::Element* root, int time_code_rate, Standard standard) const; - /** All our subtitles, in no particular order */ - std::vector> _subtitles; + /** All our texts, in no particular order */ + std::vector> _texts; class Font { @@ -216,7 +216,7 @@ private: friend struct ::pull_fonts_test2; friend struct ::pull_fonts_test3; - void maybe_add_subtitle( + void maybe_add_text( std::string text, std::vector const & parse_state, float space_before, diff --git a/src/text_asset_internal.cc b/src/text_asset_internal.cc index 51821c78..aba26edd 100644 --- a/src/text_asset_internal.cc +++ b/src/text_asset_internal.cc @@ -38,7 +38,7 @@ #include "text_asset_internal.h" -#include "subtitle_string.h" +#include "text_string.h" #include "compose.hpp" #include @@ -49,7 +49,7 @@ using std::shared_ptr; using namespace dcp; -order::Font::Font (shared_ptr s, Standard standard) +order::Font::Font(shared_ptr s, Standard standard) { if (s->font()) { if (standard == Standard::SMPTE) { diff --git a/src/text_asset_internal.h b/src/text_asset_internal.h index c8231219..ddbc8833 100644 --- a/src/text_asset_internal.h +++ b/src/text_asset_internal.h @@ -63,7 +63,7 @@ namespace dcp { class Ruby; -class SubtitleString; +class TextString; namespace order { @@ -82,7 +82,7 @@ class Font public: Font () {} - Font (std::shared_ptr s, Standard standard); + Font (std::shared_ptr s, Standard standard); xmlpp::Element* as_xml (xmlpp::Element* parent, Context& context) const; diff --git a/src/text_image.cc b/src/text_image.cc new file mode 100644 index 00000000..7a6c4222 --- /dev/null +++ b/src/text_image.cc @@ -0,0 +1,182 @@ +/* + Copyright (C) 2018-2021 Carl Hetherington + + This file is part of libdcp. + + libdcp is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + libdcp is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libdcp. If not, see . + + In addition, as a special exception, the copyright holders give + permission to link the code of portions of this program with the + OpenSSL library under certain conditions as described in each + individual source file, and distribute linked combinations + including the two. + + You must obey the GNU General Public License in all respects + for all of the code used other than OpenSSL. If you modify + file(s) with this exception, you may extend this exception to your + version of the file(s), but you are not obligated to do so. If you + do not wish to do so, delete this exception statement from your + version. If you delete this exception statement from all source + files in the program, then also delete it here. +*/ + + +/** @file src/text_image.cc + * @brief TextImage class + */ + + +#include "equality_options.h" +#include "filesystem.h" +#include "text_image.h" +#include "util.h" + + +using std::dynamic_pointer_cast; +using std::ostream; +using std::shared_ptr; +using std::string; +using namespace dcp; + + +TextImage::TextImage( + ArrayData png_image, + Time in, + Time out, + float h_position, + HAlign h_align, + float v_position, + VAlign v_align, + float z_position, + Time fade_up_time, + Time fade_down_time + ) + : Text(in, out, h_position, h_align, v_position, v_align, z_position, fade_up_time, fade_down_time) + , _png_image (png_image) + , _id (make_uuid ()) +{ + +} + + +TextImage::TextImage( + ArrayData png_image, + string id, + Time in, + Time out, + float h_position, + HAlign h_align, + float v_position, + VAlign v_align, + float z_position, + Time fade_up_time, + Time fade_down_time + ) + : Text(in, out, h_position, h_align, v_position, v_align, z_position, fade_up_time, fade_down_time) + , _png_image (png_image) + , _id (id) +{ + +} + + +void +TextImage::read_png_file(boost::filesystem::path file) +{ + _file = file; + _png_image = ArrayData (file); +} + + +void +TextImage::write_png_file(boost::filesystem::path file) const +{ + _file = file; + png_image().write (file); +} + + +bool +dcp::operator==(TextImage const & a, TextImage const & b) +{ + return ( + a.png_image() == b.png_image() && + a.id() == b.id() && + a.in() == b.in() && + a.out() == b.out() && + a.h_position() == b.h_position() && + a.h_align() == b.h_align() && + a.v_position() == b.v_position() && + a.v_align() == b.v_align() && + a.z_position() == b.z_position() && + a.fade_up_time() == b.fade_up_time() && + a.fade_down_time() == b.fade_down_time() + ); +} + + +bool +dcp::operator!=(TextImage const & a, TextImage const & b) +{ + return !(a == b); +} + + +bool +TextImage::equals(shared_ptr other_sub, EqualityOptions const& options, NoteHandler note) const +{ + if (!Text::equals(other_sub, options, note)) { + return false; + } + + auto other = dynamic_pointer_cast(other_sub); + if (!other) { + note(NoteType::ERROR, "Text types differ: string vs image"); + return false; + } + + if (png_image() != other->png_image()) { + note (NoteType::ERROR, "text image PNG data differs"); + if (options.export_differing_texts) { + string const base = "dcpdiff_text_"; + if (filesystem::exists(base + "A.png")) { + note (NoteType::ERROR, "could not export text as " + base + "A.png already exists"); + } else { + png_image().write(base + "A.png"); + } + if (filesystem::exists(base + "B.png")) { + note (NoteType::ERROR, "could not export text as " + base + "B.png already exists"); + } else { + other->png_image().write(base + "B.png"); + } + } + return false; + } + + return true; +} + + +ostream& +dcp::operator<<(ostream& s, TextImage const& text) +{ + s << "\n[IMAGE] from " << text.in() << " to " << text.out() << ";\n" + << "fade up " << text.fade_up_time() << ", fade down " << text.fade_down_time() << ";\n" + << "v pos " << text.v_position() << ", valign " << ((int) text.v_align()) + << ", hpos " << text.h_position() << ", halign " << ((int) text.h_align()) + << ", zpos " << text.z_position() << "\n"; + + return s; +} + diff --git a/src/text_image.h b/src/text_image.h new file mode 100644 index 00000000..1f1e464e --- /dev/null +++ b/src/text_image.h @@ -0,0 +1,124 @@ +/* + Copyright (C) 2018-2021 Carl Hetherington + + This file is part of libdcp. + + libdcp is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + libdcp is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libdcp. If not, see . + + In addition, as a special exception, the copyright holders give + permission to link the code of portions of this program with the + OpenSSL library under certain conditions as described in each + individual source file, and distribute linked combinations + including the two. + + You must obey the GNU General Public License in all respects + for all of the code used other than OpenSSL. If you modify + file(s) with this exception, you may extend this exception to your + version of the file(s), but you are not obligated to do so. If you + do not wish to do so, delete this exception statement from your + version. If you delete this exception statement from all source + files in the program, then also delete it here. +*/ + + +/** @file src/text_image.h + * @brief TextImage class + */ + + +#ifndef LIBDCP_TEXT_IMAGE_H +#define LIBDCP_TEXT_IMAGE_H + + +#include "array_data.h" +#include "text.h" +#include "dcp_time.h" +#include +#include + + +namespace dcp { + + +/** @class TextImage + * @brief A bitmap subtitle or caption with all the associated attributes + */ +class TextImage : public Text +{ +public: + TextImage( + ArrayData png_image, + Time in, + Time out, + float h_position, + HAlign h_align, + float v_position, + VAlign v_align, + float z_position, + Time fade_up_time, + Time fade_down_time + ); + + TextImage( + ArrayData png_image, + std::string id, + Time in, + Time out, + float h_position, + HAlign h_align, + float v_position, + VAlign v_align, + float z_position, + Time fade_up_time, + Time fade_down_time + ); + + ArrayData png_image () const { + return _png_image; + } + + void set_png_image (ArrayData png) { + _png_image = png; + } + + void read_png_file (boost::filesystem::path file); + void write_png_file (boost::filesystem::path file) const; + + std::string id () const { + return _id; + } + + /** @return the most recent disk file used to read or write this asset, if there is one */ + boost::optional file () const { + return _file; + } + + bool equals(std::shared_ptr other_text, EqualityOptions const& options, NoteHandler note) const override; + +private: + ArrayData _png_image; + std::string _id; + mutable boost::optional _file; +}; + + +bool operator==(TextImage const & a, TextImage const& b); +bool operator!=(TextImage const & a, TextImage const& b); +std::ostream& operator<<(std::ostream& s, TextImage const& text); + + +} + + +#endif diff --git a/src/text_string.cc b/src/text_string.cc new file mode 100644 index 00000000..32f9e4ed --- /dev/null +++ b/src/text_string.cc @@ -0,0 +1,272 @@ +/* + Copyright (C) 2012-2021 Carl Hetherington + + This file is part of libdcp. + + libdcp is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + libdcp is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libdcp. If not, see . + + In addition, as a special exception, the copyright holders give + permission to link the code of portions of this program with the + OpenSSL library under certain conditions as described in each + individual source file, and distribute linked combinations + including the two. + + You must obey the GNU General Public License in all respects + for all of the code used other than OpenSSL. If you modify + file(s) with this exception, you may extend this exception to your + version of the file(s), but you are not obligated to do so. If you + do not wish to do so, delete this exception statement from your + version. If you delete this exception statement from all source + files in the program, then also delete it here. +*/ + + +/** @file src/text_string.cc + * @brief TextString class + */ + + +#include "compose.hpp" +#include "text_string.h" +#include "xml.h" +#include + + +using std::dynamic_pointer_cast; +using std::max; +using std::min; +using std::ostream; +using std::shared_ptr; +using std::string; +using std::vector; +using boost::optional; +using namespace dcp; + + +TextString::TextString( + optional font, + bool italic, + bool bold, + bool underline, + Colour colour, + int size, + float aspect_adjust, + Time in, + Time out, + float h_position, + HAlign h_align, + float v_position, + VAlign v_align, + float z_position, + Direction direction, + string text, + Effect effect, + Colour effect_colour, + Time fade_up_time, + Time fade_down_time, + float space_before, + vector rubies + ) + : Text(in, out, h_position, h_align, v_position, v_align, z_position, fade_up_time, fade_down_time) + , _font (font) + , _italic (italic) + , _bold (bold) + , _underline (underline) + , _colour (colour) + , _size (size) + , _aspect_adjust (aspect_adjust) + , _direction (direction) + , _text (text) + , _effect (effect) + , _effect_colour (effect_colour) + , _space_before (space_before) + , _rubies(rubies) +{ + _aspect_adjust = max(min(_aspect_adjust, 4.0f), 0.25f); +} + + +float +TextString::size_in_pixels(int screen_height) const +{ + /* Size in the subtitle file is given in points as if the screen + height is 11 inches, so a 72pt font would be 1/11th of the screen + height. + */ + + return _size * static_cast(screen_height) / (11.0f * 72.0f); +} + + +bool +dcp::operator==(TextString const & a, TextString const & b) +{ + return ( + a.font() == b.font() && + a.italic() == b.italic() && + a.bold() == b.bold() && + a.underline() == b.underline() && + a.colour() == b.colour() && + a.size() == b.size() && + fabs (a.aspect_adjust() - b.aspect_adjust()) < ASPECT_ADJUST_EPSILON && + a.in() == b.in() && + a.out() == b.out() && + a.h_position() == b.h_position() && + a.h_align() == b.h_align() && + a.v_position() == b.v_position() && + a.v_align() == b.v_align() && + a.z_position() == b.z_position() && + a.direction() == b.direction() && + a.text() == b.text() && + a.effect() == b.effect() && + a.effect_colour() == b.effect_colour() && + a.fade_up_time() == b.fade_up_time() && + a.fade_down_time() == b.fade_down_time() && + fabs (a.space_before() - b.space_before()) < SPACE_BEFORE_EPSILON && + a.rubies() == b.rubies() + ); +} + + +bool +dcp::operator!=(TextString const & a, TextString const & b) +{ + return !(a == b); +} + + +ostream& +dcp::operator<<(ostream& s, TextString const & sub) +{ + s << "\n`" << sub.text() << "' from " << sub.in() << " to " << sub.out() << ";\n" + << "fade up " << sub.fade_up_time() << ", fade down " << sub.fade_down_time() << ";\n" + << "font " << sub.font().get_value_or ("[default]") << ", "; + + if (sub.italic()) { + s << "italic, "; + } else { + s << "non-italic, "; + } + + if (sub.bold()) { + s << "bold, "; + } else { + s << "normal, "; + } + + if (sub.underline()) { + s << "underlined, "; + } + + s << "size " << sub.size() << ", aspect " << sub.aspect_adjust() + << ", colour (" << sub.colour().r << ", " << sub.colour().g << ", " << sub.colour().b << ")" + << ", vpos " << sub.v_position() << ", valign " << ((int) sub.v_align()) + << ", hpos " << sub.h_position() << ", halign " << ((int) sub.h_align()) + << ", zpos " << sub.z_position() + << ", direction " << ((int) sub.direction()) + << ", effect " << ((int) sub.effect()) + << ", effect colour (" << sub.effect_colour().r << ", " << sub.effect_colour().g << ", " << sub.effect_colour().b << ")" + << ", space before " << sub.space_before(); + + for (auto ruby: sub.rubies()) { + s << ", ruby " << ruby.base << " " << ruby.annotation; + } + + return s; +} + + +bool +TextString::equals(shared_ptr other_sub, EqualityOptions const& options, NoteHandler note) const +{ + if (!Text::equals(other_sub, options, note)) { + return false; + } + + auto other = dynamic_pointer_cast(other_sub); + if (!other) { + note(NoteType::ERROR, "Text types differ: string vs image"); + return false; + } + + bool same = true; + + if (_font != other->_font) { + note(NoteType::ERROR, String::compose("text font differs: %1 vs %2", _font.get_value_or("[none]"), other->_font.get_value_or("[none]"))); + same = false; + } + + if (_italic != other->_italic) { + note(NoteType::ERROR, String::compose("text italic flag differs: %1 vs %2", _italic ? "true" : "false", other->_italic ? "true" : "false")); + same = false; + } + + if (_bold != other->_bold) { + note(NoteType::ERROR, String::compose("text bold flag differs: %1 vs %2", _bold ? "true" : "false", other->_bold ? "true" : "false")); + same = false; + } + + if (_underline != other->_underline) { + note(NoteType::ERROR, String::compose("text underline flag differs: %1 vs %2", _underline ? "true" : "false", other->_underline ? "true" : "false")); + same = false; + } + + if (_colour != other->_colour) { + note(NoteType::ERROR, String::compose("text colour differs: %1 vs %2", _colour.to_rgb_string(), other->_colour.to_rgb_string())); + same = false; + } + + if (_size != other->_size) { + note(NoteType::ERROR, String::compose("text size differs: %1 vs %2", _size, other->_size)); + same = false; + } + + if (_aspect_adjust != other->_aspect_adjust) { + note(NoteType::ERROR, String::compose("text aspect_adjust differs: %1 vs %2", _aspect_adjust, other->_aspect_adjust)); + same = false; + } + + if (_direction != other->_direction) { + note(NoteType::ERROR, String::compose("text direction differs: %1 vs %2", direction_to_string(_direction), direction_to_string(other->_direction))); + same = false; + } + + if (_text != other->_text) { + note(NoteType::ERROR, String::compose("text text differs: %1 vs %2", _text, other->_text)); + same = false; + } + + if (_effect != other->_effect) { + note(NoteType::ERROR, String::compose("text effect differs: %1 vs %2", effect_to_string(_effect), effect_to_string(other->_effect))); + same = false; + } + + if (_effect_colour != other->_effect_colour) { + note(NoteType::ERROR, String::compose("text effect colour differs: %1 vs %2", _effect_colour.to_rgb_string(), other->_effect_colour.to_rgb_string())); + same = false; + } + + if (_space_before != other->_space_before) { + note(NoteType::ERROR, String::compose("text space before differs: %1 vs %2", _space_before, other->_space_before)); + same = false; + } + + if (_rubies != other->_rubies) { + note(NoteType::ERROR, "rubies differ"); + same = false; + } + + return same; +} + diff --git a/src/text_string.h b/src/text_string.h new file mode 100644 index 00000000..f532bafe --- /dev/null +++ b/src/text_string.h @@ -0,0 +1,239 @@ +/* + Copyright (C) 2012-2021 Carl Hetherington + + This file is part of libdcp. + + libdcp is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + libdcp is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libdcp. If not, see . + + In addition, as a special exception, the copyright holders give + permission to link the code of portions of this program with the + OpenSSL library under certain conditions as described in each + individual source file, and distribute linked combinations + including the two. + + You must obey the GNU General Public License in all respects + for all of the code used other than OpenSSL. If you modify + file(s) with this exception, you may extend this exception to your + version of the file(s), but you are not obligated to do so. If you + do not wish to do so, delete this exception statement from your + version. If you delete this exception statement from all source + files in the program, then also delete it here. +*/ + + +/** @file src/text_string.h + * @brief TextString class + */ + + +#ifndef LIBDCP_TEXT_STRING_H +#define LIBDCP_TEXT_STRING_H + + +#include "dcp_time.h" +#include "ruby.h" +#include "text.h" +#include +#include + + +namespace dcp { + + +/** @class TextString + * @brief A single line of subtitle text with all the associated attributes. + */ +class TextString : public Text +{ +public: + /** @param font Font ID, or empty to use the default + * @param italic true for italic text + * @param bold true for bold text + * @param underline true for underlined text + * @param colour Colour of the text + * @param size Size in points as if the screen height is 11 inches, so a 72pt font would be 1/11th of the screen height + * @param aspect_adjust greater than 1 to stretch text to be wider, less than 1 to shrink text to be narrower (must be between 0.25 and 4) + * @param in start time + * @param out finish time + * @param h_position Horizontal position as a fraction of the screen width (between 0 and 1) from h_align + * @param h_align Horizontal alignment point + * @param v_position Vertical position as a fraction of the screen height (between 0 and 1) from v_align + * @param v_align Vertical alignment point + * @param z_position Z position as a proportion of the primary picture width between -1 and +1; + * +ve moves the image away from the viewer, -ve moves it toward the viewer, 0 is in the plane of the screen. + * @param direction Direction of text + * @param text The text to display + * @param effect Effect to use + * @param effect_colour Colour of the effect + * @param fade_up_time Time to fade the text in + * @param fade_down_time Time to fade the text out + * @param space_before Space to add before this string, in ems (could be negative to remove space). + */ + TextString( + boost::optional font, + bool italic, + bool bold, + bool underline, + Colour colour, + int size, + float aspect_adjust, + Time in, + Time out, + float h_position, + HAlign h_align, + float v_position, + VAlign v_align, + float z_position, + Direction direction, + std::string text, + Effect effect, + Colour effect_colour, + Time fade_up_time, + Time fade_down_time, + float space_before, + std::vector rubies + ); + + /** @return font ID */ + boost::optional font () const { + return _font; + } + + bool italic () const { + return _italic; + } + + bool bold () const { + return _bold; + } + + bool underline () const { + return _underline; + } + + Colour colour () const { + return _colour; + } + + std::string text () const { + return _text; + } + + Direction direction () const { + return _direction; + } + + Effect effect () const { + return _effect; + } + + Colour effect_colour () const { + return _effect_colour; + } + + int size () const { + return _size; + } + + float size_in_pixels (int screen_height) const; + + float space_before () const { + return _space_before; + } + + /** @return Aspect ratio `adjustment' of the font size. + * Values greater than 1 widen each character, values less than 1 narrow each character, + * and the value must be between 0.25 and 4. + */ + float aspect_adjust () const { + return _aspect_adjust; + } + + std::vector const& rubies() const { + return _rubies; + } + + void set_font (std::string id) { + _font = id; + } + + void unset_font () { + _font = boost::optional(); + } + + void set_size (int s) { + _size = s; + } + + void set_aspect_adjust (float a) { + _aspect_adjust = a; + } + + void set_text (std::string t) { + _text = t; + } + + void set_colour (Colour c) { + _colour = c; + } + + void set_effect (Effect e) { + _effect = e; + } + + void set_effect_colour (Colour c) { + _effect_colour = c; + } + + void set_rubies(std::vector rubies) { + _rubies = std::move(rubies); + } + + bool equals(std::shared_ptr other_sub, EqualityOptions const& options, NoteHandler node) const override; + +private: + /** font ID */ + boost::optional _font; + /** true if the text is italic */ + bool _italic; + /** true if the weight is bold, false for normal */ + bool _bold; + /** true to enable underlining, false otherwise */ + bool _underline; + /** text colour */ + Colour _colour; + /** Size in points as if the screen height is 11 inches, so a 72pt font + * would be 1/11th of the screen height. + */ + int _size; + float _aspect_adjust; + Direction _direction; + std::string _text; + Effect _effect; + Colour _effect_colour; + float _space_before; + std::vector _rubies; +}; + + +bool operator==(TextString const & a, TextString const & b); +bool operator!=(TextString const & a, TextString const & b); +std::ostream& operator<<(std::ostream& s, TextString const & sub); + + +} + + +#endif + diff --git a/src/types.h b/src/types.h index 65840e6d..80ee8933 100644 --- a/src/types.h +++ b/src/types.h @@ -260,19 +260,19 @@ extern bool operator!= (Colour const & a, Colour const & b); typedef boost::function NoteHandler; -/** Maximum absolute difference between dcp::SubtitleString::aspect_adjust values that +/** Maximum absolute difference between dcp::TextString::aspect_adjust values that * are considered equal */ constexpr float ASPECT_ADJUST_EPSILON = 1e-3; -/** Maximum absolute difference between dcp::SubtitleString alignment values that +/** Maximum absolute difference between dcp::TextString alignment values that * are considered equal. */ constexpr float ALIGN_EPSILON = 1e-3; -/** Maximum absolute difference between dcp::SubtitleString space_before values that +/** Maximum absolute difference between dcp::TextString space_before values that * are considered equal. */ constexpr float SPACE_BEFORE_EPSILON = 1e-3; diff --git a/src/verify.cc b/src/verify.cc index ee20e106..9abda0ff 100644 --- a/src/verify.cc +++ b/src/verify.cc @@ -803,7 +803,7 @@ verify_smpte_timed_text_asset ( void verify_interop_text_asset(Context& context, shared_ptr asset) { - if (asset->subtitles().empty()) { + if (asset->texts().empty()) { context.error(VerificationNote::Code::MISSING_SUBTITLE, asset->id(), asset->file().get()); } auto const unresolved = asset->unresolved_fonts(); @@ -1230,7 +1230,7 @@ dcp::verify_text_lines_and_characters( vector> events; - auto position = [](shared_ptr sub) { + auto position = [](shared_ptr sub) { switch (sub->v_align()) { case VAlign::TOP: return lrintf(sub->v_position() * 100); @@ -1244,8 +1244,8 @@ dcp::verify_text_lines_and_characters( }; /* Make a list of "subtitle starts" and "subtitle ends" events */ - for (auto j: asset->subtitles()) { - auto text = dynamic_pointer_cast(j); + for (auto j: asset->texts()) { + auto text = dynamic_pointer_cast(j); if (text) { auto in = make_shared(text->in(), position(text), text->text().length()); events.push_back(in); diff --git a/src/wscript b/src/wscript index c61cd2e1..1f0190fc 100644 --- a/src/wscript +++ b/src/wscript @@ -117,12 +117,12 @@ def build(bld): stereo_j2k_picture_asset.cc stereo_j2k_picture_asset_writer.cc stereo_j2k_picture_frame.cc - subtitle.cc text_asset.cc text_asset_internal.cc - subtitle_image.cc + text.cc + text_image.cc subtitle_standard.cc - subtitle_string.cc + text_string.cc transfer_function.cc types.cc utc_offset.cc @@ -234,11 +234,11 @@ def build(bld): stereo_j2k_picture_asset_reader.h stereo_j2k_picture_asset_writer.h stereo_j2k_picture_frame.h - subtitle.h + text.h text_asset.h - subtitle_image.h + text_image.h subtitle_standard.h - subtitle_string.h + text_string.h text_type.h transfer_function.h types.h -- cgit v1.2.3