]> git.sesse.net Git - casparcg/blob - modules/image/util/image_view.h
Refactored to use non-static data member initializers where it makes sense. Mixes...
[casparcg] / modules / image / util / image_view.h
1 /*
2 * Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>
3 *
4 * This file is part of CasparCG (www.casparcg.com).
5 *
6 * CasparCG is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * CasparCG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * Author: Helge Norberg, helge.norberg@svt.se
20 */
21
22 #pragma once
23
24 #include <boost/iterator/filter_iterator.hpp>
25
26 namespace caspar { namespace image {
27
28 /**
29  * A POD pixel with a compatible memory layout as a 8bit BGRA pixel (32bits in
30  * total).
31  * <p>
32  * Models the PackedPixel concept used by for example image_view. Also models
33  * the RGBAPixel concept which does not care about the order between RGBA but
34  * only requires that all 4 channel has accessors.
35  */
36 class bgra_pixel
37 {
38         uint8_t b_;
39         uint8_t g_;
40         uint8_t r_;
41         uint8_t a_;
42 public:
43         bgra_pixel(uint8_t b = 0, uint8_t g = 0, uint8_t r = 0, uint8_t a = 0) : b_(b), g_(g), r_(r), a_(a) {}
44         inline const uint8_t& b() const { return b_; }
45         inline uint8_t& b() { return b_; }
46         inline const uint8_t& g() const { return g_; }
47         inline uint8_t& g() { return g_; }
48         inline const uint8_t& r() const { return r_; }
49         inline uint8_t& r() { return r_; }
50         inline const uint8_t& a() const { return a_; }
51         inline uint8_t& a() { return a_; }
52 };
53
54 template<class PackedPixel> class image_sub_view;
55
56 /**
57  * An image view abstracting raw packed pixel data
58  * <p>
59  * This is only a view, it does not own the data.
60  * <p>
61  * Models the the ImageView concept.
62  */
63 template<class PackedPixel>
64 class image_view
65 {
66 public:
67         typedef PackedPixel pixel_type;
68
69         image_view(void* raw_start, int width, int height)
70                 : begin_(static_cast<PackedPixel*>(raw_start))
71                 , end_(begin_ + (width * height))
72                 , width_(width)
73                 , height_(height)
74         {
75         }
76
77         PackedPixel* begin()
78         {
79                 return begin_;
80         }
81
82         const PackedPixel* begin() const
83         {
84                 return begin_;
85         }
86
87         PackedPixel* end()
88         {
89                 return end_;
90         }
91
92         const PackedPixel* end() const
93         {
94                 return end_;
95         }
96
97         template<class PackedPixelIter>
98         inline PackedPixel* relative(PackedPixelIter to, int delta_x, int delta_y)
99         {
100                 auto pixel_distance = delta_x + width_ * delta_y;
101                 PackedPixel* to_address = &(*to);
102                 auto result = to_address + pixel_distance;
103
104                 if (result < begin_ || result >= end_)
105                         return nullptr;
106                 else
107                         return result;
108         }
109
110         template<class PackedPixelIter>
111         inline const PackedPixel* relative(PackedPixelIter to, int delta_x, int delta_y) const
112         {
113                 //auto x_distance
114                 auto pixel_distance = delta_x + width_ * delta_y;
115                 const PackedPixel* to_address = &(*to);
116                 auto result = to_address + pixel_distance;
117
118                 /*if (delta_x != 0)
119                 {
120                         auto actual_delta_y = result % width_
121                 }*/
122
123                 if (result < begin_ || result >= end_)
124                         return nullptr;
125                 else
126                         return result;
127         }
128
129         int width() const
130         {
131                 return width_;
132         }
133
134         int height() const
135         {
136                 return height_;
137         }
138
139         image_sub_view<PackedPixel> subview(int x, int y, int width, int height)
140         {
141                 return image_sub_view<PackedPixel>(*this, x, y, width, height);
142         }
143
144         const image_sub_view<PackedPixel> subview(int x, int y, int width, int height) const
145         {
146                 return image_sub_view<PackedPixel>(*this, x, y, width, height);
147         }
148 private:
149         PackedPixel* begin_;
150         PackedPixel* end_;
151         int width_;
152         int height_;
153 };
154
155 template<class PackedPixel>
156 class is_within_view
157 {
158 public:
159         is_within_view(const PackedPixel* begin, int width, int stride)
160                 : begin_(begin)
161                 , width_(width)
162                 , stride_(stride)
163                 , no_check_(width == stride)
164         {
165         }
166
167         inline bool operator()(const PackedPixel& pixel) const
168         {
169                 if (no_check_)
170                         return true;
171
172                 const PackedPixel* position = &pixel;
173                 int distance_from_row_start = (position - begin_) % stride_;
174
175                 return distance_from_row_start < width_;
176         }
177 private:
178         const PackedPixel* begin_;
179         int width_;
180         int stride_;
181         bool no_check_;
182 };
183
184 template <class PackedPixel>
185 struct image_stride_iterator : public boost::filter_iterator<is_within_view<PackedPixel>, PackedPixel*>
186 {
187         image_stride_iterator(PackedPixel* begin, PackedPixel* end, int width, int stride)
188                 : boost::filter_iterator<is_within_view<PackedPixel>, PackedPixel*>::filter_iterator(
189                         is_within_view<PackedPixel>(begin, width, stride), begin, end)
190         {
191         }
192 };
193
194 /**
195  * A sub view created from an image_view.
196  * <p>
197  * This also models the ImageView concept.
198  */
199 template<class PackedPixel>
200 class image_sub_view
201 {
202 private:
203         image_view<PackedPixel> root_view_;
204         int                                             relative_to_root_x_;
205         int                                             relative_to_root_y_;
206         int                                             width_;
207         int                                             height_;
208         PackedPixel*                    raw_begin_                              = root_view_.relative(root_view_.begin(), relative_to_root_x_, relative_to_root_y_);
209         PackedPixel*                    raw_end_                                = root_view_.relative(raw_begin_, width_ - 1, height_ - 1) + 1;
210 public:
211         typedef PackedPixel pixel_type;
212
213         image_sub_view(image_view<PackedPixel>& root_view, int x, int y, int width, int height)
214                 : root_view_(root_view)
215                 , relative_to_root_x_(x)
216                 , relative_to_root_y_(y)
217                 , width_(width)
218                 , height_(height)
219         {
220         }
221
222         image_stride_iterator<PackedPixel> begin()
223         {
224                 return image_stride_iterator<PackedPixel>(raw_begin_, raw_end_, width_, root_view_.width());
225         }
226
227         image_stride_iterator<const PackedPixel> begin() const
228         {
229                 return image_stride_iterator<const PackedPixel>(raw_begin_, raw_end_, width_, root_view_.width());
230         }
231
232         image_stride_iterator<PackedPixel> end()
233         {
234                 return image_stride_iterator<PackedPixel>(raw_end_, raw_end_, width_, root_view_.width());
235         }
236
237         image_stride_iterator<const PackedPixel> end() const
238         {
239                 return image_stride_iterator<const PackedPixel>(raw_end_, raw_end_, width_, root_view_.width());
240         }
241
242         template<class PackedPixelIter>
243         PackedPixel* relative(PackedPixelIter to, int delta_x, int delta_y)
244         {
245                 return root_view_.relative(to, delta_x, delta_y);
246         }
247
248         template<class PackedPixelIter>
249         const PackedPixel* relative(PackedPixelIter to, int delta_x, int delta_y) const
250         {
251                 return root_view_.relative(to, delta_x, delta_y);
252         }
253
254         int width() const
255         {
256                 return width_;
257         }
258
259         int height() const
260         {
261                 return height_;
262         }
263
264         image_sub_view<PackedPixel> subview(int x, int y, int width, int height)
265         {
266                 return root_view_.subview(relative_to_root_x_ + x, relative_to_root_y_ + y, width, height);
267         }
268
269         const image_sub_view<PackedPixel> subview(int x, int y, int width, int height) const
270         {
271                 return root_view_.subview(relative_to_root_x_ + x, relative_to_root_y_ + y, width, height);
272         }
273 };
274
275 }}