]> git.sesse.net Git - casparcg/blob - core/producer/frame/image_transform.cpp
3aaee6d08d4d5e93a5355c831ec3adc940c8f440
[casparcg] / core / producer / frame / image_transform.cpp
1 /*\r
2 * copyright (c) 2010 Sveriges Television AB <info@casparcg.com>\r
3 *\r
4 *  This file is part of CasparCG.\r
5 *\r
6 *    CasparCG is free software: you can redistribute it and/or modify\r
7 *    it under the terms of the GNU General Public License as published by\r
8 *    the Free Software Foundation, either version 3 of the License, or\r
9 *    (at your option) any later version.\r
10 *\r
11 *    CasparCG is distributed in the hope that it will be useful,\r
12 *    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14 *    GNU General Public License for more details.\r
15 \r
16 *    You should have received a copy of the GNU General Public License\r
17 *    along with CasparCG.  If not, see <http://www.gnu.org/licenses/>.\r
18 *\r
19 */\r
20 #include "../../stdafx.h"\r
21 \r
22 #include "image_transform.h"\r
23 \r
24 #include <common/utility/assert.h>\r
25 \r
26 #include <boost/algorithm/string.hpp>\r
27 \r
28 namespace caspar { namespace core {\r
29                 \r
30 image_transform::image_transform() \r
31         : opacity_(1.0)\r
32         , gain_(1.0)\r
33         , brightness_(1.0)\r
34         , contrast_(1.0)\r
35         , saturation_(1.0)\r
36         , is_key_(false)\r
37         , deinterlace_(false)\r
38         , blend_mode_(image_transform::blend_mode::normal)\r
39         , alpha_mode_(image_transform::alpha_mode::normal)\r
40 {\r
41         std::fill(fill_translation_.begin(), fill_translation_.end(), 0.0);\r
42         std::fill(fill_scale_.begin(), fill_scale_.end(), 1.0);\r
43         std::fill(clip_translation_.begin(), clip_translation_.end(), 0.0);\r
44         std::fill(clip_scale_.begin(), clip_scale_.end(), 1.0);\r
45 }\r
46 \r
47 void image_transform::set_opacity(double value)\r
48 {\r
49         opacity_ = std::max(value, 0.0);\r
50 }\r
51 \r
52 double image_transform::get_opacity() const\r
53 {\r
54         return opacity_;\r
55 }\r
56 \r
57 void image_transform::set_gain(double value)\r
58 {\r
59         gain_ = std::max(0.0, value);\r
60 }\r
61 \r
62 double image_transform::get_gain() const\r
63 {\r
64         return gain_;\r
65 }\r
66 \r
67 void image_transform::set_brightness(double value)\r
68 {\r
69         brightness_ = std::max(0.0, value);\r
70 }\r
71 \r
72 double image_transform::get_brightness() const\r
73 {\r
74         return brightness_;\r
75 }\r
76 \r
77 void image_transform::set_contrast(double value)\r
78 {\r
79         contrast_ = std::max(0.0, value);\r
80 }\r
81 \r
82 double image_transform::get_contrast() const\r
83 {\r
84         return contrast_;\r
85 }\r
86 \r
87 void image_transform::set_saturation(double value)\r
88 {\r
89         saturation_ = std::max(0.0, value);\r
90 }\r
91 \r
92 double image_transform::get_saturation() const\r
93 {\r
94         return saturation_;\r
95 }\r
96 \r
97 void image_transform::set_levels(const image_transform::levels& value)\r
98 {\r
99         levels_ = value;\r
100 }\r
101 \r
102 image_transform::levels image_transform::get_levels() const\r
103 {\r
104         return levels_;\r
105 }\r
106 \r
107 \r
108 void image_transform::set_fill_translation(double x, double y)\r
109 {\r
110         fill_translation_[0] = x;\r
111         fill_translation_[1] = y;\r
112 }\r
113 \r
114 void image_transform::set_fill_scale(double x, double y)\r
115 {\r
116         fill_scale_[0] = x;\r
117         fill_scale_[1] = y;     \r
118 }\r
119 \r
120 std::array<double, 2> image_transform::get_fill_translation() const\r
121 {\r
122         return fill_translation_;\r
123 }\r
124 \r
125 std::array<double, 2> image_transform::get_fill_scale() const\r
126 {\r
127         return fill_scale_;\r
128 }\r
129 \r
130 void image_transform::set_clip_translation(double x, double y)\r
131 {\r
132         clip_translation_[0] = x;\r
133         clip_translation_[1] = y;\r
134 }\r
135 \r
136 void image_transform::set_clip_scale(double x, double y)\r
137 {\r
138         clip_scale_[0] = x;\r
139         clip_scale_[1] = y;     \r
140 }\r
141 \r
142 std::array<double, 2> image_transform::get_clip_translation() const\r
143 {\r
144         return clip_translation_;\r
145 }\r
146 \r
147 std::array<double, 2> image_transform::get_clip_scale() const\r
148 {\r
149         return clip_scale_;\r
150 }\r
151 \r
152 void image_transform::set_deinterlace(bool value)\r
153 {\r
154         deinterlace_ = value;\r
155 }\r
156 \r
157 bool image_transform::get_deinterlace() const\r
158 {\r
159         return deinterlace_;\r
160 }\r
161 \r
162 void image_transform::set_blend_mode(image_transform::blend_mode::type value)\r
163 {\r
164         blend_mode_ = value;\r
165 }\r
166 \r
167 image_transform::blend_mode::type image_transform::get_blend_mode() const\r
168 {\r
169         return blend_mode_;\r
170 }\r
171 \r
172 void image_transform::set_alpha_mode(image_transform::alpha_mode::type value)\r
173 {\r
174         alpha_mode_ = value;\r
175 }\r
176 \r
177 image_transform::alpha_mode::type image_transform::get_alpha_mode() const\r
178 {\r
179         return alpha_mode_;\r
180 }\r
181 \r
182 image_transform& image_transform::operator*=(const image_transform &other)\r
183 {\r
184         opacity_                                *= other.opacity_;      \r
185         blend_mode_                              = std::max(blend_mode_, other.blend_mode_);\r
186         alpha_mode_                              = std::max(alpha_mode_, other.alpha_mode_);\r
187         gain_                                   *= other.gain_;\r
188         brightness_                             *= other.brightness_;\r
189         contrast_                               *= other.contrast_;\r
190         saturation_                             *= other.saturation_;\r
191 \r
192         levels_.min_input               = std::max(levels_.min_input, other.levels_.min_input);\r
193         levels_.max_input               = std::min(levels_.max_input, other.levels_.max_input);\r
194         \r
195         levels_.min_output              = std::max(levels_.min_output, other.levels_.min_output);\r
196         levels_.max_output              = std::min(levels_.max_output, other.levels_.max_output);\r
197 \r
198         levels_.gamma                   *= other.levels_.gamma;\r
199 \r
200         deinterlace_                    |= other.deinterlace_;\r
201         is_key_                                 |= other.is_key_;\r
202         fill_translation_[0]    += other.fill_translation_[0]*fill_scale_[0];\r
203         fill_translation_[1]    += other.fill_translation_[1]*fill_scale_[1];\r
204         fill_scale_[0]                  *= other.fill_scale_[0];\r
205         fill_scale_[1]                  *= other.fill_scale_[1];\r
206         clip_translation_[0]    += other.clip_translation_[0]*clip_scale_[0];\r
207         clip_translation_[1]    += other.clip_translation_[1]*clip_scale_[1];\r
208         clip_scale_[0]                  *= other.clip_scale_[0];\r
209         clip_scale_[1]                  *= other.clip_scale_[1];\r
210         return *this;\r
211 }\r
212 \r
213 const image_transform image_transform::operator*(const image_transform &other) const\r
214 {\r
215         return image_transform(*this) *= other;\r
216 }\r
217 \r
218 void image_transform::set_is_key(bool value){is_key_ = value;}\r
219 bool image_transform::get_is_key() const{return is_key_;}\r
220 \r
221 image_transform tween(double time, const image_transform& source, const image_transform& dest, double duration, const tweener_t& tweener)\r
222 {       \r
223         auto do_tween = [](double time, double source, double dest, double duration, const tweener_t& tweener)\r
224         {\r
225                 return tweener(time, source, dest-source, duration);\r
226         };\r
227         \r
228         image_transform result; \r
229         result.set_blend_mode           (std::max(source.get_blend_mode(), dest.get_blend_mode()));\r
230         result.set_alpha_mode           (std::max(source.get_alpha_mode(), dest.get_alpha_mode()));\r
231         result.set_is_key                       (source.get_is_key() | dest.get_is_key());\r
232         result.set_deinterlace          (source.get_deinterlace() | dest.get_deinterlace());\r
233         result.set_gain                         (do_tween(time, source.get_gain(), dest.get_gain(), duration, tweener));\r
234         result.set_brightness           (do_tween(time, source.get_brightness(), dest.get_brightness(), duration, tweener));\r
235         result.set_contrast                     (do_tween(time, source.get_contrast(), dest.get_contrast(), duration, tweener));\r
236         result.set_saturation           (do_tween(time, source.get_saturation(), dest.get_saturation(), duration, tweener));\r
237         result.set_opacity                      (do_tween(time, source.get_opacity(), dest.get_opacity(), duration, tweener));\r
238         result.set_fill_translation     (do_tween(time, source.get_fill_translation()[0], dest.get_fill_translation()[0], duration, tweener), do_tween(time, source.get_fill_translation()[1], dest.get_fill_translation()[1], duration, tweener));\r
239         result.set_fill_scale           (do_tween(time, source.get_fill_scale()[0], dest.get_fill_scale()[0], duration, tweener), do_tween(time, source.get_fill_scale()[1], dest.get_fill_scale()[1], duration, tweener));\r
240         result.set_clip_translation     (do_tween(time, source.get_clip_translation()[0], dest.get_clip_translation()[0], duration, tweener), do_tween(time, source.get_clip_translation()[1], dest.get_clip_translation()[1], duration, tweener));\r
241         result.set_clip_scale           (do_tween(time, source.get_clip_scale()[0], dest.get_clip_scale()[0], duration, tweener), do_tween(time, source.get_clip_scale()[1], dest.get_clip_scale()[1], duration, tweener));\r
242         \r
243         auto s_levels = source.get_levels();\r
244         auto d_levels = dest.get_levels();\r
245 \r
246         d_levels.max_input = do_tween(time, s_levels.max_input, d_levels.max_input, duration, tweener);\r
247         d_levels.min_input = do_tween(time, s_levels.min_input, d_levels.min_input, duration, tweener);\r
248         \r
249         d_levels.max_output = do_tween(time, s_levels.max_output, d_levels.max_output, duration, tweener);\r
250         d_levels.min_output = do_tween(time, s_levels.min_output, d_levels.min_output, duration, tweener);\r
251 \r
252         d_levels.gamma = do_tween(time, s_levels.gamma, d_levels.gamma, duration, tweener);\r
253 \r
254         result.set_levels(d_levels);\r
255 \r
256         return result;\r
257 }\r
258 \r
259 image_transform::blend_mode::type get_blend_mode(const std::wstring& str)\r
260 {\r
261         if(boost::iequals(str, L"normal"))\r
262                 return image_transform::blend_mode::normal;\r
263         else if(boost::iequals(str, L"lighten"))\r
264                 return image_transform::blend_mode::lighten;\r
265         else if(boost::iequals(str, L"darken"))\r
266                 return image_transform::blend_mode::darken;\r
267         else if(boost::iequals(str, L"multiply"))\r
268                 return image_transform::blend_mode::multiply;\r
269         else if(boost::iequals(str, L"average"))\r
270                 return image_transform::blend_mode::average;\r
271         else if(boost::iequals(str, L"add"))\r
272                 return image_transform::blend_mode::add;\r
273         else if(boost::iequals(str, L"subtract"))\r
274                 return image_transform::blend_mode::subtract;\r
275         else if(boost::iequals(str, L"difference"))\r
276                 return image_transform::blend_mode::difference;\r
277         else if(boost::iequals(str, L"negation"))\r
278                 return image_transform::blend_mode::negation;\r
279         else if(boost::iequals(str, L"exclusion"))\r
280                 return image_transform::blend_mode::exclusion;\r
281         else if(boost::iequals(str, L"screen"))\r
282                 return image_transform::blend_mode::screen;\r
283         else if(boost::iequals(str, L"overlay"))\r
284                 return image_transform::blend_mode::overlay;\r
285         else if(boost::iequals(str, L"soft_light"))\r
286                 return image_transform::blend_mode::soft_light;\r
287         else if(boost::iequals(str, L"hard_light"))\r
288                 return image_transform::blend_mode::hard_light;\r
289         else if(boost::iequals(str, L"color_dodge"))\r
290                 return image_transform::blend_mode::color_dodge;\r
291         else if(boost::iequals(str, L"color_burn"))\r
292                 return image_transform::blend_mode::color_burn;\r
293         else if(boost::iequals(str, L"linear_dodge"))\r
294                 return image_transform::blend_mode::linear_dodge;\r
295         else if(boost::iequals(str, L"linear_burn"))\r
296                 return image_transform::blend_mode::linear_burn;\r
297         else if(boost::iequals(str, L"linear_light"))\r
298                 return image_transform::blend_mode::linear_light;\r
299         else if(boost::iequals(str, L"vivid_light"))\r
300                 return image_transform::blend_mode::vivid_light;\r
301         else if(boost::iequals(str, L"pin_light"))\r
302                 return image_transform::blend_mode::pin_light;\r
303         else if(boost::iequals(str, L"hard_mix"))\r
304                 return image_transform::blend_mode::hard_mix;\r
305         else if(boost::iequals(str, L"reflect"))\r
306                 return image_transform::blend_mode::reflect;\r
307         else if(boost::iequals(str, L"glow"))\r
308                 return image_transform::blend_mode::glow;\r
309         else if(boost::iequals(str, L"phoenix"))\r
310                 return image_transform::blend_mode::phoenix;\r
311         else if(boost::iequals(str, L"contrast"))\r
312                 return image_transform::blend_mode::contrast;\r
313         else if(boost::iequals(str, L"saturation"))\r
314                 return image_transform::blend_mode::saturation;\r
315         else if(boost::iequals(str, L"color"))\r
316                 return image_transform::blend_mode::color;\r
317         else if(boost::iequals(str, L"luminosity"))\r
318                 return image_transform::blend_mode::luminosity;\r
319                 \r
320         return image_transform::blend_mode::normal;\r
321 }\r
322 \r
323 image_transform::alpha_mode::type get_alpha_mode(const std::wstring& str)\r
324 {\r
325         if(boost::iequals(str, L"normal"))\r
326                 return image_transform::alpha_mode::normal;\r
327 \r
328         return image_transform::alpha_mode::normal;\r
329 }\r
330 \r
331 bool operator<(const image_transform& lhs, const image_transform& rhs)\r
332 {\r
333         return memcmp(&lhs, &rhs, sizeof(image_transform)) < 0;\r
334 }\r
335 \r
336 bool operator==(const image_transform& lhs, const image_transform& rhs)\r
337 {\r
338         return memcmp(&lhs, &rhs, sizeof(image_transform)) == 0;\r
339 }\r
340 \r
341 bool operator!=(const image_transform& lhs, const image_transform& rhs)\r
342 {\r
343         return !(lhs == rhs);\r
344 }\r
345 \r
346 }}