HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
pixel_map.hpp
1// Copyright Take Vos 2021.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6#include "required.hpp"
7#include "geometry/axis_aligned_rectangle.hpp"
8#include "geometry/extent.hpp"
9#include <algorithm>
10#include <cassert>
11#include <span>
12#include <string>
13#include <vector>
14
15namespace hi::inline v1 {
16
19template<typename T>
20class pixel_row {
21public:
22 using value_type = T;
23
24 pixel_row(T *pixels, std::size_t width) noexcept : _pixels(pixels), _width(width) {}
25
26 [[nodiscard]] std::size_t width() const noexcept
27 {
28 return _width;
29 }
30
33 [[nodiscard]] T const *data() const noexcept
34 {
35 return _pixels;
36 }
37
40 [[nodiscard]] T *data() noexcept
41 {
42 return _pixels;
43 }
44
49 [[nodiscard]] T const &operator[](std::size_t columnNr) const noexcept
50 {
51 return _pixels[columnNr];
52 }
53
58 [[nodiscard]] T &operator[](std::size_t columnNr) noexcept
59 {
60 return _pixels[columnNr];
61 }
62
69 [[nodiscard]] T const &at(std::size_t columnNr) const noexcept
70 {
71 hi_assert(columnNr >= 0 && columnNr < _width);
72 return _pixels[columnNr];
73 }
74
81 [[nodiscard]] T &at(std::size_t columnNr) noexcept
82 {
83 hi_assert(columnNr >= 0 && columnNr < _width);
84 return _pixels[columnNr];
85 }
86
87private:
90 T *_pixels;
91
94 std::size_t _width;
95};
96
101template<typename T>
103public:
104 using value_type = T;
105
108 pixel_map() noexcept : _pixels(nullptr), _width(0), _height(0), _stride(0), _self_allocated(true) {}
109
116 pixel_map(T *pixels, std::size_t width, std::size_t height, std::size_t stride) noexcept :
117 _pixels(pixels), _width(width), _height(height), _stride(stride), _self_allocated(false)
118 {
119 hi_assert(_stride >= _width);
120 hi_assert(_width >= 0);
121 hi_assert(_height >= 0);
122
123 if (pixels == nullptr) {
124 _self_allocated = true;
125 _pixels = new T[_height * _stride];
126 }
127 }
128
135 pixel_map(T *pixels, std::size_t width, std::size_t height) noexcept : pixel_map(pixels, width, height, width) {}
136
142 pixel_map(std::size_t width, std::size_t height, std::size_t stride) noexcept : pixel_map(nullptr, width, height, stride) {}
143
149 pixel_map(std::size_t width, std::size_t height) noexcept : pixel_map(nullptr, width, height, width) {}
150
151 ~pixel_map()
152 {
153 if (_self_allocated) {
154 delete[] _pixels;
155 }
156 }
157
163 pixel_map(pixel_map const &other) noexcept :
164 _pixels(other._pixels),
165 _width(other._width),
166 _height(other._height),
167 _stride(other._stride),
168 _self_allocated(other._self_allocated)
169 {
170 if (_self_allocated) {
171 _pixels = new T[_height * _stride];
172
173 for (std::size_t y = 0; y != _height; ++y) {
174 hilet src_row = other[y];
175 auto dst_row = (*this)[y];
176 for (std::size_t x = 0; x != _width; ++x) {
177 dst_row[x] = src_row[x];
178 }
179 }
180 }
181 }
182
183 pixel_map(pixel_map &&other) noexcept :
184 _pixels(other._pixels),
185 _width(other._width),
186 _height(other._height),
187 _stride(other._stride),
188 _self_allocated(other._self_allocated)
189 {
190 hi_axiom(this != &other);
191 other._self_allocated = false;
192 }
193
194 [[nodiscard]] operator bool() const noexcept
195 {
196 return _pixels != nullptr;
197 }
198
199 [[nodiscard]] std::size_t width() const noexcept
200 {
201 return _width;
202 }
203
204 [[nodiscard]] std::size_t height() const noexcept
205 {
206 return _height;
207 }
208
209 [[nodiscard]] std::size_t stride() const noexcept
210 {
211 return _stride;
212 }
213
217 {
218 hi_return_on_self_assignment(other);
219
220 _pixels = other._pixels;
221 _width = other._width;
222 _height = other._height;
223 _stride = other._stride;
224 _self_allocated = other._self_allocated;
225
226 if (_self_allocated) {
227 _pixels = new T[_height * _stride];
228
229 for (std::size_t y = 0; y != _height; ++y) {
230 hilet src_row = other[y];
231 auto dst_row = (*this)[y];
232 for (std::size_t x = 0; x != _width; ++x) {
233 dst_row[x] = src_row[x];
234 }
235 }
236 }
237 return *this;
238 }
239
240 pixel_map &operator=(pixel_map &&other) noexcept
241 {
242 // Self assignment is allowed.
243 if (_self_allocated) {
244 delete[] _pixels;
245 }
246 _pixels = other._pixels;
247 _width = other._width;
248 _height = other._height;
249 _stride = other._stride;
250 _self_allocated = other._self_allocated;
251 other._self_allocated = false;
252 return *this;
253 }
254
255 extent2 extent() const noexcept
256 {
257 return {narrow_cast<float>(_width), narrow_cast<float>(_height)};
258 }
259
267 pixel_map submap(std::size_t x, std::size_t y, std::size_t width, std::size_t height) const noexcept
268 {
269 hi_axiom((x >= 0) && (y >= 0));
270 hi_assert((x + width <= _width) && (y + height <= _height));
271
272 hilet offset = y * _stride + x;
273
274 return pixel_map{_pixels + offset, width, height, _stride};
275 }
276
277 pixel_map submap(aarectangle rectangle) const noexcept
278 {
279 hi_axiom(round(rectangle) == rectangle);
280 return submap(
281 narrow_cast<std::size_t>(rectangle.left()),
282 narrow_cast<std::size_t>(rectangle.bottom()),
283 narrow_cast<std::size_t>(rectangle.width()),
284 narrow_cast<std::size_t>(rectangle.height()));
285 }
286
287 pixel_row<T> const operator[](std::size_t rowNr) const noexcept
288 {
289 return {_pixels + (rowNr * _stride), _width};
290 }
291
292 pixel_row<T> operator[](std::size_t rowNr) noexcept
293 {
294 return {_pixels + (rowNr * _stride), _width};
295 }
296
297 pixel_row<T> const at(std::size_t rowNr) const noexcept
298 {
299 hi_assert(rowNr < _height);
300 return (*this)[rowNr];
301 }
302
303 pixel_row<T> at(std::size_t rowNr) noexcept
304 {
305 hi_assert(rowNr < _height);
306 return (*this)[rowNr];
307 }
308
309private:
312 T *_pixels;
313
316 std::size_t _width;
317
320 std::size_t _height;
321
325 std::size_t _stride;
326
329 bool _self_allocated;
330};
331
332template<typename T>
333void copy(pixel_map<T> const &src, pixel_map<T> &dst) noexcept
334{
335 std::size_t width = std::min(src.width(), dst.width());
336 std::size_t height = std::min(src.height(), dst.height());
337
338 for (std::size_t y = 0; y != height; ++y) {
339 hilet src_row = src[y];
340 auto dst_row = dst[y];
341 for (std::size_t x = 0; x != width; ++x) {
342 dst_row[x] = src_row[x];
343 }
344 }
345}
346
347template<int KERNEL_SIZE, typename KERNEL>
348void horizontalFilterRow(pixel_row<uint8_t> row, KERNEL kernel) noexcept;
349
350template<int KERNEL_SIZE, typename T, typename KERNEL>
351void horizontalFilter(pixel_map<T> &pixels, KERNEL kernel) noexcept;
352
355template<typename T>
356void fill(pixel_map<T> &dst) noexcept;
357
360template<typename T>
361void fill(pixel_map<T> &dst, T color) noexcept;
362
365template<typename T>
366void rotate90(pixel_map<T> &dst, pixel_map<T> const &src) noexcept;
367
370template<typename T>
371void rotate270(pixel_map<T> &dst, pixel_map<T> const &src) noexcept;
372
375void mergeMaximum(pixel_map<uint8_t> &dst, pixel_map<uint8_t> const &src) noexcept;
376
382template<typename T>
383inline void makeTransparentBorder(pixel_map<T> &pixel_map) noexcept;
384
385} // namespace hi::inline v1
This file includes required definitions.
#define hilet
Invariant should be the default for variables.
Definition required.hpp:23
Class which represents an axis-aligned rectangle.
Definition axis_aligned_rectangle.hpp:20
A rectangle / parallelogram in 3D space.
Definition rectangle.hpp:20
constexpr float height() const noexcept
The height, or length of the up vector.
Definition rectangle.hpp:147
constexpr float width() const noexcept
The width, or length of the right vector.
Definition rectangle.hpp:140
A 2D canvas of pixels.
Definition pixel_map.hpp:102
pixel_map() noexcept
Construct an empty pixel-map.
Definition pixel_map.hpp:108
pixel_map(std::size_t width, std::size_t height, std::size_t stride) noexcept
Construct an pixel-map from memory received from an API.
Definition pixel_map.hpp:142
pixel_map(T *pixels, std::size_t width, std::size_t height, std::size_t stride) noexcept
Construct an pixel-map from memory received from an API.
Definition pixel_map.hpp:116
pixel_map(pixel_map const &other) noexcept
Copy constructor of other.
Definition pixel_map.hpp:163
pixel_map(std::size_t width, std::size_t height) noexcept
Construct an pixel-map from memory received from an API.
Definition pixel_map.hpp:149
pixel_map & operator=(pixel_map const &other)
Disallowing copying so that life-time of selfAllocated pixels is easy to understand.
Definition pixel_map.hpp:216
pixel_map submap(std::size_t x, std::size_t y, std::size_t width, std::size_t height) const noexcept
Get a (smaller) view of the map.
Definition pixel_map.hpp:267
pixel_map(T *pixels, std::size_t width, std::size_t height) noexcept
Construct an pixel-map from memory received from an API.
Definition pixel_map.hpp:135
A row of pixels.
Definition pixel_map.hpp:20
T * data() noexcept
Get a pointer to the pixel data.
Definition pixel_map.hpp:40
T & operator[](std::size_t columnNr) noexcept
Get a access to a pixel in the row.
Definition pixel_map.hpp:58
T const & at(std::size_t columnNr) const noexcept
Get a access to a pixel in the row.
Definition pixel_map.hpp:69
T const & operator[](std::size_t columnNr) const noexcept
Get a access to a pixel in the row.
Definition pixel_map.hpp:49
T const * data() const noexcept
Get a pointer to the pixel data.
Definition pixel_map.hpp:33
T & at(std::size_t columnNr) noexcept
Get a access to a pixel in the row.
Definition pixel_map.hpp:81
T copy(T... args)
T fill(T... args)
T min(T... args)