Merge remote-tracking branch 'origin/master' into 2.0
[dcpomatic.git] / src / lib / video_content_scale.cc
1 /*
2     Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <boost/optional.hpp>
21 #include <libxml++/libxml++.h>
22 #include <libcxml/cxml.h>
23 #include "video_content_scale.h"
24 #include "ratio.h"
25 #include "safe_stringstream.h"
26 #include "util.h"
27
28 #include "i18n.h"
29
30 using std::vector;
31 using std::string;
32 using boost::shared_ptr;
33 using boost::optional;
34
35 vector<VideoContentScale> VideoContentScale::_scales;
36
37 VideoContentScale::VideoContentScale (Ratio const * r)
38         : _ratio (r)
39         , _scale (true)
40 {
41
42 }
43
44 VideoContentScale::VideoContentScale ()
45         : _ratio (0)
46         , _scale (false)
47 {
48
49 }
50
51 VideoContentScale::VideoContentScale (bool scale)
52         : _ratio (0)
53         , _scale (scale)
54 {
55
56 }
57
58 VideoContentScale::VideoContentScale (shared_ptr<cxml::Node> node)
59         : _ratio (0)
60         , _scale (true)
61 {
62         optional<string> r = node->optional_string_child ("Ratio");
63         if (r) {
64                 _ratio = Ratio::from_id (r.get ());
65         } else {
66                 _scale = node->bool_child ("Scale");
67         }
68 }
69
70 void
71 VideoContentScale::as_xml (xmlpp::Node* node) const
72 {
73         if (_ratio) {
74                 node->add_child("Ratio")->add_child_text (_ratio->id ());
75         } else {
76                 node->add_child("Scale")->add_child_text (_scale ? "1" : "0");
77         }
78 }
79
80 string
81 VideoContentScale::id () const
82 {
83         SafeStringStream s;
84         
85         if (_ratio) {
86                 s << _ratio->id ();
87         } else {
88                 s << (_scale ? "S1" : "S0");
89         }
90         
91         return s.str ();
92 }
93
94 string
95 VideoContentScale::name () const
96 {
97         if (_ratio) {
98                 return _ratio->nickname ();
99         }
100
101         if (_scale) {
102                 return _("No stretch");
103         }
104
105         return _("No scale");
106 }
107
108 VideoContentScale
109 VideoContentScale::from_id (string id)
110 {
111         Ratio const * r = Ratio::from_id (id);
112         if (r) {
113                 return VideoContentScale (r);
114         }
115
116         if (id == "S0") {
117                 return VideoContentScale (false);
118         }
119
120         return VideoContentScale (true);
121 }
122                 
123 /** @param display_container Size of the container that we are displaying this content in.
124  *  @param film_container The size of the film's image.
125  */
126 dcp::Size
127 VideoContentScale::size (shared_ptr<const VideoContent> c, dcp::Size display_container, dcp::Size film_container, int round) const
128 {
129         if (_ratio) {
130                 return fit_ratio_within (_ratio->ratio (), display_container, round);
131         }
132
133         dcp::Size const ac = c->video_size_after_crop ();
134
135         /* Force scale if the film_container is smaller than the content's image */
136         if (_scale || film_container.width < ac.width || film_container.height < ac.height) {
137                 return fit_ratio_within (ac.ratio (), display_container, round);
138         }
139
140         /* Scale the image so that it will be in the right place in film_container, even if display_container is a
141            different size.
142         */
143         return dcp::Size (
144                 c->video_size().width  * float(display_container.width)  / film_container.width,
145                 c->video_size().height * float(display_container.height) / film_container.height
146                 );
147 }
148
149 void
150 VideoContentScale::setup_scales ()
151 {
152         vector<Ratio const *> ratios = Ratio::all ();
153         for (vector<Ratio const *>::const_iterator i = ratios.begin(); i != ratios.end(); ++i) {
154                 _scales.push_back (VideoContentScale (*i));
155         }
156
157         _scales.push_back (VideoContentScale (true));
158         _scales.push_back (VideoContentScale (false));
159 }
160
161 bool
162 operator== (VideoContentScale const & a, VideoContentScale const & b)
163 {
164         return (a.ratio() == b.ratio() && a.scale() == b.scale());
165 }
166
167 bool
168 operator!= (VideoContentScale const & a, VideoContentScale const & b)
169 {
170         return (a.ratio() != b.ratio() || a.scale() != b.scale());
171 }