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