+2015-11-08 Carl Hetherington <cth@carlh.net>
+
+ * Allow configuration of SubRip subtitle colour and outlines.
+
2015-11-06 Carl Hetherington <cth@carlh.net>
* Sort cinemas in KDM dialog and standalone creator (#726).
uint8_t* op = other->data()[0] + oy * other->stride()[0];
for (int tx = start_tx, ox = start_ox; tx < size().width && ox < other->size().width; ++tx, ++ox) {
float const alpha = float (op[3]) / 255;
- /* Blend high bytes */
- tp[1] = op[0] * alpha + tp[1] * (1 - alpha);
+ /* Blend high bytes; the RGBA in op appears to be BGRA */
+ tp[1] = op[2] * alpha + tp[1] * (1 - alpha);
tp[3] = op[1] * alpha + tp[3] * (1 - alpha);
- tp[5] = op[2] * alpha + tp[5] * (1 - alpha);
+ tp[5] = op[0] * alpha + tp[5] * (1 - alpha);
tp += this_bpp;
op += other_bpp;
property == ContentProperty::TRIM_END ||
property == ContentProperty::PATH ||
property == VideoContentProperty::VIDEO_FRAME_TYPE ||
- property == DCPContentProperty::CAN_BE_PLAYED
+ property == DCPContentProperty::CAN_BE_PLAYED ||
+ property == SubRipContentProperty::SUBTITLE_COLOUR ||
+ property == SubRipContentProperty::SUBTITLE_OUTLINE ||
+ property == SubRipContentProperty::SUBTITLE_OUTLINE_COLOUR
) {
_have_valid_pieces = false;
std::string const SubRipContent::font_id = "font";
+int const SubRipContentProperty::SUBTITLE_COLOUR = 300;
+int const SubRipContentProperty::SUBTITLE_OUTLINE = 301;
+int const SubRipContentProperty::SUBTITLE_OUTLINE_COLOUR = 302;
+
SubRipContent::SubRipContent (shared_ptr<const Film> film, boost::filesystem::path path)
: Content (film, path)
, SubtitleContent (film, path)
+ , _colour (255, 255, 255)
+ , _outline (false)
+ , _outline_colour (0, 0, 0)
{
}
, SubtitleContent (film, node, version)
, _length (node->number_child<ContentTime::Type> ("Length"))
, _frame_rate (node->optional_number_child<double>("SubtitleFrameRate"))
+ , _colour (
+ node->optional_number_child<int>("Red").get_value_or(255),
+ node->optional_number_child<int>("Green").get_value_or(255),
+ node->optional_number_child<int>("Blue").get_value_or(255)
+ )
+ , _outline (node->optional_bool_child("Outline").get_value_or(false))
+ , _outline_colour (
+ node->optional_number_child<int>("OutlineRed").get_value_or(255),
+ node->optional_number_child<int>("OutlineGreen").get_value_or(255),
+ node->optional_number_child<int>("OutlineBlue").get_value_or(255)
+ )
{
}
Content::as_xml (node);
SubtitleContent::as_xml (node);
node->add_child("Length")->add_child_text (raw_convert<string> (_length.get ()));
+ node->add_child("Red")->add_child_text (raw_convert<string> (_colour.r));
+ node->add_child("Green")->add_child_text (raw_convert<string> (_colour.g));
+ node->add_child("Blue")->add_child_text (raw_convert<string> (_colour.b));
+ node->add_child("Outline")->add_child_text (raw_convert<string> (_outline));
+ node->add_child("OutlineRed")->add_child_text (raw_convert<string> (_outline_colour.r));
+ node->add_child("OutlineGreen")->add_child_text (raw_convert<string> (_outline_colour.g));
+ node->add_child("OutlineBlue")->add_child_text (raw_convert<string> (_outline_colour.b));
}
DCPTime
*/
return film()->active_frame_rate_change(position()).source;
}
+
+void
+SubRipContent::set_colour (dcp::Colour colour)
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ if (_colour == colour) {
+ return;
+ }
+
+ _colour = colour;
+ }
+
+ signal_changed (SubRipContentProperty::SUBTITLE_COLOUR);
+}
+
+void
+SubRipContent::set_outline (bool o)
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ if (_outline == o) {
+ return;
+ }
+
+ _outline = o;
+ }
+
+ signal_changed (SubRipContentProperty::SUBTITLE_OUTLINE);
+}
+
+void
+SubRipContent::set_outline_colour (dcp::Colour colour)
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ if (_outline_colour == colour) {
+ return;
+ }
+
+ _outline_colour = colour;
+ }
+
+ signal_changed (SubRipContentProperty::SUBTITLE_OUTLINE_COLOUR);
+}
#include "subtitle_content.h"
+class SubRipContentProperty
+{
+public:
+ static int const SUBTITLE_COLOUR;
+ static int const SUBTITLE_OUTLINE;
+ static int const SUBTITLE_OUTLINE_COLOUR;
+};
+
+
class SubRipContent : public SubtitleContent
{
public:
double subtitle_video_frame_rate () const;
void set_subtitle_video_frame_rate (int r);
+ void set_colour (dcp::Colour);
+
+ dcp::Colour colour () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _colour;
+ }
+
+ void set_outline (bool);
+
+ bool outline () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _outline;
+ }
+
+ void set_outline_colour (dcp::Colour);
+
+ dcp::Colour outline_colour () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _outline_colour;
+ }
+
static std::string const font_id;
private:
ContentTime _length;
/** Video frame rate that this content has been prepared for, if known */
boost::optional<double> _frame_rate;
+ dcp::Colour _colour;
+ bool _outline;
+ dcp::Colour _outline_colour;
};
using std::cout;
using boost::shared_ptr;
using boost::optional;
+using boost::dynamic_pointer_cast;
SubRipDecoder::SubRipDecoder (shared_ptr<const SubRipContent> content)
: SubtitleDecoder (content)
/* XXX: we are ignoring positioning specified in the file */
+ shared_ptr<const SubRipContent> content = dynamic_pointer_cast<const SubRipContent> (_subtitle_content);
+ DCPOMATIC_ASSERT (content);
+
list<dcp::SubtitleString> out;
for (list<sub::Line>::const_iterator i = _subtitles[_next].lines.begin(); i != _subtitles[_next].lines.end(); ++i) {
for (list<sub::Block>::const_iterator j = i->blocks.begin(); j != i->blocks.end(); ++j) {
dcp::SubtitleString (
SubRipContent::font_id,
j->italic,
- dcp::Colour (j->colour.r * 255, j->colour.g * 255, j->colour.b * 255),
+ /* force the colour to whatever is configured */
+ content->colour(),
j->font_size.points (72 * 11),
1.0,
dcp::Time (_subtitles[_next].from.all_as_seconds(), 1000),
i->vertical_position.line.get() * (1.5 / 22) + 0.8,
dcp::VALIGN_TOP,
j->text,
- dcp::NONE,
- dcp::Colour (255, 255, 255),
+ content->outline() ? dcp::BORDER : dcp::NONE,
+ content->outline_colour(),
dcp::Time (0, 1000),
dcp::Time (0, 1000)
)
std::list<ContentImageSubtitle> _decoded_image_subtitles;
std::list<ContentTextSubtitle> _decoded_text_subtitles;
+ boost::shared_ptr<const SubtitleContent> _subtitle_content;
private:
template <class T>
*/
virtual std::list<ContentTimePeriod> image_subtitles_during (ContentTimePeriod period, bool starting) const = 0;
virtual std::list<ContentTimePeriod> text_subtitles_during (ContentTimePeriod period, bool starting) const = 0;
-
- boost::shared_ptr<const SubtitleContent> _subtitle_content;
};
#endif
--- /dev/null
+/*
+ Copyright (C) 2015 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "subtitle_appearance_dialog.h"
+#include "lib/subrip_content.h"
+#include <wx/wx.h>
+#include <wx/clrpicker.h>
+
+using boost::shared_ptr;
+
+SubtitleAppearanceDialog::SubtitleAppearanceDialog (wxWindow* parent, shared_ptr<SubRipContent> content)
+ : TableDialog (parent, _("Subtitle appearance"), 2, 1, true)
+ , _content (content)
+{
+ add (_("Colour"), true);
+ _colour = new wxColourPickerCtrl (this, wxID_ANY);
+ add (_colour);
+
+ _outline = new wxCheckBox (this, wxID_ANY, _("Outline"));
+ add (_outline);
+ add_spacer ();
+
+ add (_("Outline colour"), true);
+ _outline_colour = new wxColourPickerCtrl (this, wxID_ANY);
+ add (_outline_colour);
+
+ layout ();
+
+ _colour->SetColour (wxColour (_content->colour().r, _content->colour().g, _content->colour().b));
+ _outline->SetValue (_content->outline ());
+ _outline_colour->SetColour (wxColour (_content->outline_colour().r, _content->outline_colour().g, _content->outline_colour().b));
+}
+
+void
+SubtitleAppearanceDialog::apply ()
+{
+ wxColour const c = _colour->GetColour ();
+ _content->set_colour (dcp::Colour (c.Red(), c.Green(), c.Blue()));
+ _content->set_outline (_outline->GetValue ());
+ wxColour const oc = _outline_colour->GetColour ();
+ _content->set_outline_colour (dcp::Colour (oc.Red(), oc.Green(), oc.Blue()));
+}
--- /dev/null
+/*
+ Copyright (C) 2015 Carl Hetherington <cth@carlh.net>
+
+ This program 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.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "table_dialog.h"
+#include <boost/shared_ptr.hpp>
+
+class wxCheckBox;
+class wxColourPickerCtrl;
+class SubRipContent;
+
+class SubtitleAppearanceDialog : public TableDialog
+{
+public:
+ SubtitleAppearanceDialog (wxWindow* parent, boost::shared_ptr<SubRipContent> content);
+
+ void apply ();
+
+private:
+ wxColourPickerCtrl* _colour;
+ wxCheckBox* _outline;
+ wxColourPickerCtrl* _outline_colour;
+
+ boost::shared_ptr<SubRipContent> _content;
+};
#include "subtitle_view.h"
#include "content_panel.h"
#include "fonts_dialog.h"
+#include "subtitle_appearance_dialog.h"
#include "lib/ffmpeg_content.h"
#include "lib/subrip_content.h"
#include "lib/ffmpeg_subtitle_stream.h"
s->Add (_subtitle_view_button, 1, wxALL, DCPOMATIC_SIZER_GAP);
_fonts_dialog_button = new wxButton (this, wxID_ANY, _("Fonts..."));
s->Add (_fonts_dialog_button, 1, wxALL, DCPOMATIC_SIZER_GAP);
+ _appearance_dialog_button = new wxButton (this, wxID_ANY, _("Appearance..."));
+ s->Add (_appearance_dialog_button, 1, wxALL, DCPOMATIC_SIZER_GAP);
grid->Add (s, wxGBPosition (r, 0), wxGBSpan (1, 2));
++r;
_x_scale->SetRange (10, 1000);
_y_scale->SetRange (10, 1000);
- _reference->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&SubtitlePanel::reference_clicked, this));
- _use->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&SubtitlePanel::use_toggled, this));
- _burn->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&SubtitlePanel::burn_toggled, this));
- _x_offset->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&SubtitlePanel::x_offset_changed, this));
- _y_offset->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&SubtitlePanel::y_offset_changed, this));
- _x_scale->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&SubtitlePanel::x_scale_changed, this));
- _y_scale->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&SubtitlePanel::y_scale_changed, this));
- _language->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&SubtitlePanel::language_changed, this));
- _stream->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&SubtitlePanel::stream_changed, this));
- _subtitle_view_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&SubtitlePanel::subtitle_view_clicked, this));
- _fonts_dialog_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&SubtitlePanel::fonts_dialog_clicked, this));
+ _reference->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&SubtitlePanel::reference_clicked, this));
+ _use->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&SubtitlePanel::use_toggled, this));
+ _burn->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&SubtitlePanel::burn_toggled, this));
+ _x_offset->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&SubtitlePanel::x_offset_changed, this));
+ _y_offset->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&SubtitlePanel::y_offset_changed, this));
+ _x_scale->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&SubtitlePanel::x_scale_changed, this));
+ _y_scale->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&SubtitlePanel::y_scale_changed, this));
+ _language->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&SubtitlePanel::language_changed, this));
+ _stream->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&SubtitlePanel::stream_changed, this));
+ _subtitle_view_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&SubtitlePanel::subtitle_view_clicked, this));
+ _fonts_dialog_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&SubtitlePanel::fonts_dialog_clicked, this));
+ _appearance_dialog_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&SubtitlePanel::appearance_dialog_clicked, this));
}
void
{
int any_subs = 0;
int ffmpeg_subs = 0;
- int subrip_or_dcp_subs = 0;
+ int subrip_subs = 0;
+ int dcp_subs = 0;
int image_subs = 0;
SubtitleContentList sel = _parent->selected_subtitle ();
BOOST_FOREACH (shared_ptr<SubtitleContent> i, sel) {
++ffmpeg_subs;
++any_subs;
}
- } else if (sc || dsc) {
- ++subrip_or_dcp_subs;
+ } else if (sc) {
+ ++subrip_subs;
+ ++any_subs;
+ } else if (dsc) {
+ ++dcp_subs;
++any_subs;
} else {
++any_subs;
_y_scale->Enable (!reference && any_subs > 0 && use);
_language->Enable (!reference && any_subs > 0 && use);
_stream->Enable (!reference && ffmpeg_subs == 1);
- _subtitle_view_button->Enable (!reference && subrip_or_dcp_subs == 1);
- _fonts_dialog_button->Enable (!reference && subrip_or_dcp_subs == 1);
+ _subtitle_view_button->Enable (!reference && (subrip_subs == 1 || dcp_subs == 1));
+ _fonts_dialog_button->Enable (!reference && (subrip_subs == 1 || dcp_subs == 1));
+ _appearance_dialog_button->Enable (!reference && subrip_subs == 1);
}
void
d->set_reference_subtitle (_reference->GetValue ());
}
+
+void
+SubtitlePanel::appearance_dialog_clicked ()
+{
+ SubtitleContentList c = _parent->selected_subtitle ();
+ DCPOMATIC_ASSERT (c.size() == 1);
+
+ shared_ptr<SubRipContent> sr = dynamic_pointer_cast<SubRipContent> (c.front ());
+ DCPOMATIC_ASSERT (sr);
+
+ SubtitleAppearanceDialog* d = new SubtitleAppearanceDialog (this, sr);
+ if (d->ShowModal () == wxID_OK) {
+ d->apply ();
+ }
+ d->Destroy ();
+}
class wxSpinCtrl;
class SubtitleView;
class FontsDialog;
+class SubtitleAppearanceDialog;
class SubtitlePanel : public ContentSubPanel
{
void subtitle_view_clicked ();
void fonts_dialog_clicked ();
void reference_clicked ();
+ void appearance_dialog_clicked ();
void setup_sensitivity ();
SubtitleView* _subtitle_view;
wxButton* _fonts_dialog_button;
FontsDialog* _fonts_dialog;
+ wxButton* _appearance_dialog_button;
};
screens_panel.cc
server_dialog.cc
servers_list_dialog.cc
+ subtitle_appearance_dialog.cc
subtitle_panel.cc
subtitle_view.cc
system_font_dialog.cc