+/*\r
+* Copyright (c) 2011 Sveriges Television AB <info@casparcg.com>\r
+*\r
+* This file is part of CasparCG (www.casparcg.com).\r
+*\r
+* CasparCG is free software: you can redistribute it and/or modify\r
+* it under the terms of the GNU General Public License as published by\r
+* the Free Software Foundation, either version 3 of the License, or\r
+* (at your option) any later version.\r
+*\r
+* CasparCG is distributed in the hope that it will be useful,\r
+* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+* GNU General Public License for more details.\r
+*\r
+* You should have received a copy of the GNU General Public License\r
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.\r
+*\r
+* Author: Helge Norberg, helge.norberg@svt.se\r
+*/\r
+\r
+#pragma once\r
+\r
+#include <boost/iterator/filter_iterator.hpp>\r
+\r
+namespace caspar { namespace image {\r
+\r
+/**\r
+ * A POD pixel with a compatible memory layout as a 8bit BGRA pixel (32bits in\r
+ * total).\r
+ * <p>\r
+ * Models the PackedPixel concept used by for example image_view. Also models\r
+ * the RGBAPixel concept which does not care about the order between RGBA but\r
+ * only requires that all 4 channel has accessors.\r
+ */\r
+class bgra_pixel\r
+{\r
+ uint8_t b_;\r
+ uint8_t g_;\r
+ uint8_t r_;\r
+ uint8_t a_;\r
+public:\r
+ 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) {}\r
+ inline const uint8_t& b() const { return b_; }\r
+ inline uint8_t& b() { return b_; }\r
+ inline const uint8_t& g() const { return g_; }\r
+ inline uint8_t& g() { return g_; }\r
+ inline const uint8_t& r() const { return r_; }\r
+ inline uint8_t& r() { return r_; }\r
+ inline const uint8_t& a() const { return a_; }\r
+ inline uint8_t& a() { return a_; }\r
+};\r
+\r
+template<class PackedPixel> class image_sub_view;\r
+\r
+/**\r
+ * An image view abstracting raw packed pixel data\r
+ * <p>\r
+ * This is only a view, it does not own the data.\r
+ * <p>\r
+ * Models the the ImageView concept.\r
+ */\r
+template<class PackedPixel>\r
+class image_view\r
+{\r
+public:\r
+ typedef PackedPixel pixel_type;\r
+\r
+ image_view(void* raw_start, int width, int height)\r
+ : begin_(static_cast<PackedPixel*>(raw_start))\r
+ , end_(begin_ + (width * height))\r
+ , width_(width)\r
+ , height_(height)\r
+ {\r
+ }\r
+\r
+ PackedPixel* begin()\r
+ {\r
+ return begin_;\r
+ }\r
+\r
+ const PackedPixel* begin() const\r
+ {\r
+ return begin_;\r
+ }\r
+\r
+ PackedPixel* end()\r
+ {\r
+ return end_;\r
+ }\r
+\r
+ const PackedPixel* end() const\r
+ {\r
+ return end_;\r
+ }\r
+\r
+ template<class PackedPixelIter>\r
+ inline PackedPixel* relative(PackedPixelIter to, int delta_x, int delta_y)\r
+ {\r
+ auto pixel_distance = delta_x + width_ * delta_y;\r
+ PackedPixel* to_address = &(*to);\r
+ auto result = to_address + pixel_distance;\r
+\r
+ if (result < begin_ || result >= end_)\r
+ return nullptr;\r
+ else\r
+ return result;\r
+ }\r
+\r
+ template<class PackedPixelIter>\r
+ inline const PackedPixel* relative(PackedPixelIter to, int delta_x, int delta_y) const\r
+ {\r
+ //auto x_distance\r
+ auto pixel_distance = delta_x + width_ * delta_y;\r
+ const PackedPixel* to_address = &(*to);\r
+ auto result = to_address + pixel_distance;\r
+\r
+ /*if (delta_x != 0)\r
+ {\r
+ auto actual_delta_y = result % width_\r
+ }*/\r
+\r
+ if (result < begin_ || result >= end_)\r
+ return nullptr;\r
+ else\r
+ return result;\r
+ }\r
+\r
+ int width() const\r
+ {\r
+ return width_;\r
+ }\r
+\r
+ int height() const\r
+ {\r
+ return height_;\r
+ }\r
+\r
+ image_sub_view<PackedPixel> subview(int x, int y, int width, int height)\r
+ {\r
+ return image_sub_view<PackedPixel>(*this, x, y, width, height);\r
+ }\r
+\r
+ const image_sub_view<PackedPixel> subview(int x, int y, int width, int height) const\r
+ {\r
+ return image_sub_view<PackedPixel>(*this, x, y, width, height);\r
+ }\r
+private:\r
+ PackedPixel* begin_;\r
+ PackedPixel* end_;\r
+ int width_;\r
+ int height_;\r
+};\r
+\r
+template<class PackedPixel>\r
+class is_within_view\r
+{\r
+public:\r
+ is_within_view(const PackedPixel* begin, int width, int stride)\r
+ : begin_(begin)\r
+ , width_(width)\r
+ , stride_(stride)\r
+ , no_check_(width == stride)\r
+ {\r
+ }\r
+\r
+ inline bool operator()(const PackedPixel& pixel) const\r
+ {\r
+ if (no_check_)\r
+ return true;\r
+\r
+ const PackedPixel* position = &pixel;\r
+ int distance_from_row_start = (position - begin_) % stride_;\r
+\r
+ return distance_from_row_start < width_;\r
+ }\r
+private:\r
+ const PackedPixel* begin_;\r
+ int width_;\r
+ int stride_;\r
+ bool no_check_;\r
+};\r
+\r
+template <class PackedPixel>\r
+struct image_stride_iterator : public boost::filter_iterator<is_within_view<PackedPixel>, PackedPixel*>\r
+{\r
+ image_stride_iterator(PackedPixel* begin, PackedPixel* end, int width, int stride)\r
+ : boost::filter_iterator<is_within_view<PackedPixel>, PackedPixel*>::filter_iterator(\r
+ is_within_view<PackedPixel>(begin, width, stride), begin, end)\r
+ {\r
+ }\r
+};\r
+\r
+/**\r
+ * A sub view created from an image_view.\r
+ * <p>\r
+ * This also models the ImageView concept.\r
+ */\r
+template<class PackedPixel>\r
+class image_sub_view\r
+{\r
+public:\r
+ typedef PackedPixel pixel_type;\r
+\r
+ image_sub_view(image_view<PackedPixel>& root_view, int x, int y, int width, int height)\r
+ : root_view_(root_view)\r
+ , relative_to_root_x_(x)\r
+ , relative_to_root_y_(y)\r
+ , width_(width)\r
+ , height_(height)\r
+ , raw_begin_(root_view.relative(root_view.begin(), x, y))\r
+ , raw_end_(root_view.relative(raw_begin_, width - 1, height_ - 1) + 1)\r
+ {\r
+ }\r
+\r
+ image_stride_iterator<PackedPixel> begin()\r
+ {\r
+ return image_stride_iterator<PackedPixel>(raw_begin_, raw_end_, width_, root_view_.width());\r
+ }\r
+\r
+ image_stride_iterator<const PackedPixel> begin() const\r
+ {\r
+ return image_stride_iterator<const PackedPixel>(raw_begin_, raw_end_, width_, root_view_.width());\r
+ }\r
+\r
+ image_stride_iterator<PackedPixel> end()\r
+ {\r
+ return image_stride_iterator<PackedPixel>(raw_end_, raw_end_, width_, root_view_.width());\r
+ }\r
+\r
+ image_stride_iterator<const PackedPixel> end() const\r
+ {\r
+ return image_stride_iterator<const PackedPixel>(raw_end_, raw_end_, width_, root_view_.width());\r
+ }\r
+\r
+ template<class PackedPixelIter>\r
+ PackedPixel* relative(PackedPixelIter to, int delta_x, int delta_y)\r
+ {\r
+ return root_view_.relative(to, delta_x, delta_y);\r
+ }\r
+\r
+ template<class PackedPixelIter>\r
+ const PackedPixel* relative(PackedPixelIter to, int delta_x, int delta_y) const\r
+ {\r
+ return root_view_.relative(to, delta_x, delta_y);\r
+ }\r
+\r
+ int width() const\r
+ {\r
+ return width_;\r
+ }\r
+\r
+ int height() const\r
+ {\r
+ return height_;\r
+ }\r
+\r
+ image_sub_view<PackedPixel> subview(int x, int y, int width, int height)\r
+ {\r
+ return root_view_.subview(relative_to_root_x_ + x, relative_to_root_y_ + y, width, height);\r
+ }\r
+\r
+ const image_sub_view<PackedPixel> subview(int x, int y, int width, int height) const\r
+ {\r
+ return root_view_.subview(relative_to_root_x_ + x, relative_to_root_y_ + y, width, height);\r
+ }\r
+private:\r
+ image_view<PackedPixel> root_view_;\r
+ int relative_to_root_x_;\r
+ int relative_to_root_y_;\r
+ int width_;\r
+ int height_;\r
+ PackedPixel* raw_begin_;\r
+ PackedPixel* raw_end_;\r
+};\r
+\r
+}}\r