diff options
| author | Carl Hetherington <cth@carlh.net> | 2014-01-15 16:21:41 +0000 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2014-01-15 16:21:41 +0000 |
| commit | 86214f4619476b1a4951e15f002a93743b5f7a1e (patch) | |
| tree | a827550b72a7409d280d21fc6e0a820c9f940fc2 /src/lib/render_subtitles.cc | |
| parent | a890bedf688f0066d70dd5e9b07cbd86736cc0b1 (diff) | |
Basics of subtitle rendering.
Diffstat (limited to 'src/lib/render_subtitles.cc')
| -rw-r--r-- | src/lib/render_subtitles.cc | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/src/lib/render_subtitles.cc b/src/lib/render_subtitles.cc new file mode 100644 index 000000000..630681761 --- /dev/null +++ b/src/lib/render_subtitles.cc @@ -0,0 +1,150 @@ +/* + Copyright (C) 2014 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 <cairomm/cairomm.h> +#include <pangomm.h> +#include "render_subtitles.h" +#include "types.h" +#include "image.h" + +using std::list; +using std::cout; +using std::string; +using std::min; +using std::max; +using boost::shared_ptr; +using boost::optional; + +static int +calculate_position (libdcp::VAlign v_align, double v_position, int target_height, int offset) +{ + switch (v_align) { + case libdcp::TOP: + return (v_position / 100) * target_height - offset; + case libdcp::CENTER: + return (0.5 + v_position / 100) * target_height - offset; + case libdcp::BOTTOM: + return (1.0 - v_position / 100) * target_height - offset; + } + + return 0; +} + +void +render_subtitles (list<libdcp::Subtitle> subtitles, libdcp::Size target, shared_ptr<Image>& image, Position<int>& position) +{ + if (subtitles.empty ()) { + image.reset (); + return; + } + + /* Estimate height that the subtitle image needs to be */ + optional<int> top; + optional<int> bottom; + for (list<libdcp::Subtitle>::const_iterator i = subtitles.begin(); i != subtitles.end(); ++i) { + int const b = calculate_position (i->v_align(), i->v_position(), target.height, 0); + int const t = b - i->size() * target.height / (11 * 72); + + top = min (top.get_value_or (t), t); + bottom = max (bottom.get_value_or (b), b); + } + + top = top.get() - 32; + bottom = bottom.get() + 32; + + image.reset (new Image (PIX_FMT_RGBA, libdcp::Size (target.width, bottom.get() - top.get ()), false)); + image->make_black (); + + Cairo::RefPtr<Cairo::ImageSurface> surface = Cairo::ImageSurface::create ( + image->data()[0], + Cairo::FORMAT_ARGB32, + image->size().width, + image->size().height, + Cairo::ImageSurface::format_stride_for_width (Cairo::FORMAT_ARGB32, image->size().width) + ); + + Cairo::RefPtr<Cairo::Context> context = Cairo::Context::create (surface); + Glib::RefPtr<Pango::Layout> layout = Pango::Layout::create (context); + + layout->set_width (image->size().width * PANGO_SCALE); + layout->set_alignment (Pango::ALIGN_CENTER); + + context->set_line_width (1); + + for (list<libdcp::Subtitle>::const_iterator i = subtitles.begin(); i != subtitles.end(); ++i) { + string f = i->font (); + if (f.empty ()) { + f = "Arial"; + } + Pango::FontDescription font (f); + font.set_absolute_size (i->size_in_pixels (target.height) * PANGO_SCALE); + if (i->italic ()) { + font.set_style (Pango::STYLE_ITALIC); + } + layout->set_font_description (font); + layout->set_text (i->text ()); + + /* Compute fade factor */ + /* XXX */ + float fade_factor = 1; +#if 0 + libdcp::Time now (time * 1000 / (4 * TIME_HZ)); + libdcp::Time end_fade_up = i->in() + i->fade_up_time (); + libdcp::Time start_fade_down = i->out() - i->fade_down_time (); + if (now < end_fade_up) { + fade_factor = (now - i->in()) / i->fade_up_time(); + } else if (now > start_fade_down) { + fade_factor = 1.0 - ((now - start_fade_down) / i->fade_down_time ()); + } +#endif + + layout->update_from_cairo_context (context); + + /* Work out position */ + + int const x = 0; + int const y = calculate_position (i->v_align (), i->v_position (), target.height, (layout->get_baseline() / PANGO_SCALE) + top.get ()); + + if (i->effect() == libdcp::SHADOW) { + /* Drop-shadow effect */ + libdcp::Color const ec = i->effect_color (); + context->set_source_rgba (float(ec.r) / 255, float(ec.g) / 255, float(ec.b) / 255, fade_factor); + context->move_to (x + 4, y + 4); + layout->add_to_cairo_context (context); + context->fill (); + } + + /* The actual subtitle */ + context->move_to (x, y); + libdcp::Color const c = i->color (); + context->set_source_rgba (float(c.r) / 255, float(c.g) / 255, float(c.b) / 255, fade_factor); + layout->add_to_cairo_context (context); + context->fill (); + + if (i->effect() == libdcp::BORDER) { + /* Border effect */ + context->move_to (x, y); + libdcp::Color ec = i->effect_color (); + context->set_source_rgba (float(ec.r) / 255, float(ec.g) / 255, float(ec.b) / 255, fade_factor); + layout->add_to_cairo_context (context); + context->stroke (); + } + } +} + |
