]> git.sesse.net Git - casparcg/blob - core/producer/frame/image_transform.cpp
git-svn-id: https://casparcg.svn.sourceforge.net/svnroot/casparcg/server/branches...
[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         , blend_mode_(image_transform::blend_mode::normal)\r
38 {\r
39         std::fill(fill_translation_.begin(), fill_translation_.end(), 0.0);\r
40         std::fill(fill_scale_.begin(), fill_scale_.end(), 1.0);\r
41         std::fill(clip_translation_.begin(), clip_translation_.end(), 0.0);\r
42         std::fill(clip_scale_.begin(), clip_scale_.end(), 1.0);\r
43 }\r
44 \r
45 void image_transform::set_opacity(double value)\r
46 {\r
47         opacity_ = std::max(value, 0.0);\r
48 }\r
49 \r
50 double image_transform::get_opacity() const\r
51 {\r
52         return opacity_;\r
53 }\r
54 \r
55 void image_transform::set_gain(double value)\r
56 {\r
57         gain_ = std::max(0.0, value);\r
58 }\r
59 \r
60 double image_transform::get_gain() const\r
61 {\r
62         return gain_;\r
63 }\r
64 \r
65 void image_transform::set_brightness(double value)\r
66 {\r
67         brightness_ = std::max(0.0, value);\r
68 }\r
69 \r
70 double image_transform::get_brightness() const\r
71 {\r
72         return brightness_;\r
73 }\r
74 \r
75 void image_transform::set_contrast(double value)\r
76 {\r
77         contrast_ = std::max(0.0, value);\r
78 }\r
79 \r
80 double image_transform::get_contrast() const\r
81 {\r
82         return contrast_;\r
83 }\r
84 \r
85 void image_transform::set_saturation(double value)\r
86 {\r
87         saturation_ = std::max(0.0, value);\r
88 }\r
89 \r
90 double image_transform::get_saturation() const\r
91 {\r
92         return saturation_;\r
93 }\r
94 \r
95 void image_transform::set_levels(const image_transform::levels& value)\r
96 {\r
97         levels_ = value;\r
98 }\r
99 \r
100 image_transform::levels image_transform::get_levels() const\r
101 {\r
102         return levels_;\r
103 }\r
104 \r
105 \r
106 void image_transform::set_fill_translation(double x, double y)\r
107 {\r
108         fill_translation_[0] = x;\r
109         fill_translation_[1] = y;\r
110 }\r
111 \r
112 void image_transform::set_fill_scale(double x, double y)\r
113 {\r
114         fill_scale_[0] = x;\r
115         fill_scale_[1] = y;     \r
116 }\r
117 \r
118 std::array<double, 2> image_transform::get_fill_translation() const\r
119 {\r
120         return fill_translation_;\r
121 }\r
122 \r
123 std::array<double, 2> image_transform::get_fill_scale() const\r
124 {\r
125         return fill_scale_;\r
126 }\r
127 \r
128 void image_transform::set_clip_translation(double x, double y)\r
129 {\r
130         clip_translation_[0] = x;\r
131         clip_translation_[1] = y;\r
132 }\r
133 \r
134 void image_transform::set_clip_scale(double x, double y)\r
135 {\r
136         clip_scale_[0] = x;\r
137         clip_scale_[1] = y;     \r
138 }\r
139 \r
140 std::array<double, 2> image_transform::get_clip_translation() const\r
141 {\r
142         return clip_translation_;\r
143 }\r
144 \r
145 std::array<double, 2> image_transform::get_clip_scale() const\r
146 {\r
147         return clip_scale_;\r
148 }\r
149 \r
150 void image_transform::set_blend_mode(image_transform::blend_mode::type value)\r
151 {\r
152         blend_mode_ = value;\r
153 }\r
154 \r
155 image_transform::blend_mode::type image_transform::get_blend_mode() const\r
156 {\r
157         return blend_mode_;\r
158 }\r
159 \r
160 image_transform& image_transform::operator*=(const image_transform &other)\r
161 {\r
162         opacity_                                *= other.opacity_;      \r
163         blend_mode_                              = std::max(blend_mode_, other.blend_mode_);\r
164         gain_                                   *= other.gain_;\r
165         brightness_                             *= other.brightness_;\r
166         contrast_                               *= other.contrast_;\r
167         saturation_                             *= other.saturation_;\r
168 \r
169         levels_.min_input               = std::max(levels_.min_input, other.levels_.min_input);\r
170         levels_.max_input               = std::min(levels_.max_input, other.levels_.max_input);\r
171         \r
172         levels_.min_output              = std::max(levels_.min_output, other.levels_.min_output);\r
173         levels_.max_output              = std::min(levels_.max_output, other.levels_.max_output);\r
174 \r
175         levels_.gamma                   *= other.levels_.gamma;\r
176 \r
177         is_key_                                 |= other.is_key_;\r
178         fill_translation_[0]    += other.fill_translation_[0]*fill_scale_[0];\r
179         fill_translation_[1]    += other.fill_translation_[1]*fill_scale_[1];\r
180         fill_scale_[0]                  *= other.fill_scale_[0];\r
181         fill_scale_[1]                  *= other.fill_scale_[1];\r
182         clip_translation_[0]    += other.clip_translation_[0]*clip_scale_[0];\r
183         clip_translation_[1]    += other.clip_translation_[1]*clip_scale_[1];\r
184         clip_scale_[0]                  *= other.clip_scale_[0];\r
185         clip_scale_[1]                  *= other.clip_scale_[1];\r
186         return *this;\r
187 }\r
188 \r
189 const image_transform image_transform::operator*(const image_transform &other) const\r
190 {\r
191         return image_transform(*this) *= other;\r
192 }\r
193 \r
194 void image_transform::set_is_key(bool value){is_key_ = value;}\r
195 bool image_transform::get_is_key() const{return is_key_;}\r
196 \r
197 image_transform tween(double time, const image_transform& source, const image_transform& dest, double duration, const tweener_t& tweener)\r
198 {       \r
199         auto do_tween = [](double time, double source, double dest, double duration, const tweener_t& tweener)\r
200         {\r
201                 return tweener(time, source, dest-source, duration);\r
202         };\r
203         \r
204         image_transform result; \r
205         result.set_blend_mode           (std::max(source.get_blend_mode(), dest.get_blend_mode()));\r
206         result.set_is_key                       (source.get_is_key() | dest.get_is_key());\r
207         result.set_gain                         (do_tween(time, source.get_gain(), dest.get_gain(), duration, tweener));\r
208         result.set_brightness           (do_tween(time, source.get_brightness(), dest.get_brightness(), duration, tweener));\r
209         result.set_contrast                     (do_tween(time, source.get_contrast(), dest.get_contrast(), duration, tweener));\r
210         result.set_saturation           (do_tween(time, source.get_saturation(), dest.get_saturation(), duration, tweener));\r
211         result.set_opacity                      (do_tween(time, source.get_opacity(), dest.get_opacity(), duration, tweener));\r
212         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
213         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
214         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
215         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
216         \r
217         auto s_levels = source.get_levels();\r
218         auto d_levels = dest.get_levels();\r
219 \r
220         d_levels.max_input = do_tween(time, s_levels.max_input, d_levels.max_input, duration, tweener);\r
221         d_levels.min_input = do_tween(time, s_levels.min_input, d_levels.min_input, duration, tweener);\r
222         \r
223         d_levels.max_output = do_tween(time, s_levels.max_output, d_levels.max_output, duration, tweener);\r
224         d_levels.min_output = do_tween(time, s_levels.min_output, d_levels.min_output, duration, tweener);\r
225 \r
226         d_levels.gamma = do_tween(time, s_levels.gamma, d_levels.gamma, duration, tweener);\r
227 \r
228         result.set_levels(d_levels);\r
229 \r
230         return result;\r
231 }\r
232 \r
233 image_transform::blend_mode::type get_blend_mode(const std::wstring& str)\r
234 {\r
235         if(boost::iequals(str, L"normal"))\r
236                 return image_transform::blend_mode::normal;\r
237         else if(boost::iequals(str, L"lighten"))\r
238                 return image_transform::blend_mode::lighten;\r
239         else if(boost::iequals(str, L"darken"))\r
240                 return image_transform::blend_mode::darken;\r
241         else if(boost::iequals(str, L"multiply"))\r
242                 return image_transform::blend_mode::multiply;\r
243         else if(boost::iequals(str, L"average"))\r
244                 return image_transform::blend_mode::average;\r
245         else if(boost::iequals(str, L"add"))\r
246                 return image_transform::blend_mode::add;\r
247         else if(boost::iequals(str, L"subtract"))\r
248                 return image_transform::blend_mode::subtract;\r
249         else if(boost::iequals(str, L"difference"))\r
250                 return image_transform::blend_mode::difference;\r
251         else if(boost::iequals(str, L"negation"))\r
252                 return image_transform::blend_mode::negation;\r
253         else if(boost::iequals(str, L"exclusion"))\r
254                 return image_transform::blend_mode::exclusion;\r
255         else if(boost::iequals(str, L"screen"))\r
256                 return image_transform::blend_mode::screen;\r
257         else if(boost::iequals(str, L"overlay"))\r
258                 return image_transform::blend_mode::overlay;\r
259         else if(boost::iequals(str, L"soft_light"))\r
260                 return image_transform::blend_mode::soft_light;\r
261         else if(boost::iequals(str, L"hard_light"))\r
262                 return image_transform::blend_mode::hard_light;\r
263         else if(boost::iequals(str, L"color_dodge"))\r
264                 return image_transform::blend_mode::color_dodge;\r
265         else if(boost::iequals(str, L"color_burn"))\r
266                 return image_transform::blend_mode::color_burn;\r
267         else if(boost::iequals(str, L"linear_dodge"))\r
268                 return image_transform::blend_mode::linear_dodge;\r
269         else if(boost::iequals(str, L"linear_burn"))\r
270                 return image_transform::blend_mode::linear_burn;\r
271         else if(boost::iequals(str, L"linear_light"))\r
272                 return image_transform::blend_mode::linear_light;\r
273         else if(boost::iequals(str, L"vivid_light"))\r
274                 return image_transform::blend_mode::vivid_light;\r
275         else if(boost::iequals(str, L"pin_light"))\r
276                 return image_transform::blend_mode::pin_light;\r
277         else if(boost::iequals(str, L"hard_mix"))\r
278                 return image_transform::blend_mode::hard_mix;\r
279         else if(boost::iequals(str, L"reflect"))\r
280                 return image_transform::blend_mode::reflect;\r
281         else if(boost::iequals(str, L"glow"))\r
282                 return image_transform::blend_mode::glow;\r
283         else if(boost::iequals(str, L"phoenix"))\r
284                 return image_transform::blend_mode::phoenix;\r
285         else if(boost::iequals(str, L"contrast"))\r
286                 return image_transform::blend_mode::contrast;\r
287         else if(boost::iequals(str, L"saturation"))\r
288                 return image_transform::blend_mode::saturation;\r
289         else if(boost::iequals(str, L"color"))\r
290                 return image_transform::blend_mode::color;\r
291         else if(boost::iequals(str, L"luminosity"))\r
292                 return image_transform::blend_mode::luminosity;\r
293                 \r
294         return image_transform::blend_mode::normal;\r
295 }\r
296 \r
297 bool operator<(const image_transform& lhs, const image_transform& rhs)\r
298 {\r
299         return memcmp(&lhs, &rhs, sizeof(image_transform)) < 0;\r
300 }\r
301 \r
302 bool operator==(const image_transform& lhs, const image_transform& rhs)\r
303 {\r
304         return memcmp(&lhs, &rhs, sizeof(image_transform)) == 0;\r
305 }\r
306 \r
307 bool operator!=(const image_transform& lhs, const image_transform& rhs)\r
308 {\r
309         return !(lhs == rhs);\r
310 }\r
311 \r
312 }}