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
15hi_warning_push();
16// C26401: Do not delete a raw pointer that is not an owner<T> (i.11).
17// pixel map may be a container for pixel data.
18hi_warning_ignore_msvc(26401);
19// C26409: Avoid calling new and delete explicitly, use std::make_unique<T> instead (r.11).
20// pixel map may be a container for pixel data.
21hi_warning_ignore_msvc(26409);
22
23namespace hi::inline v1 {
24
27template<typename T>
28class pixel_row {
29public:
30 using value_type = T;
31
32 pixel_row(T *pixels, std::size_t width) noexcept : _pixels(pixels), _width(width) {}
33
34 [[nodiscard]] std::size_t width() const noexcept
35 {
36 return _width;
37 }
38
41 [[nodiscard]] T const *data() const noexcept
42 {
43 return _pixels;
44 }
45
48 [[nodiscard]] T *data() noexcept
49 {
50 return _pixels;
51 }
52
57 [[nodiscard]] T const &operator[](std::size_t columnNr) const noexcept
58 {
59 return _pixels[columnNr];
60 }
61
66 [[nodiscard]] T &operator[](std::size_t columnNr) noexcept
67 {
68 return _pixels[columnNr];
69 }
70
77 [[nodiscard]] T const &at(std::size_t columnNr) const noexcept
78 {
79 hi_assert(columnNr >= 0 && columnNr < _width);
80 return _pixels[columnNr];
81 }
82
89 [[nodiscard]] T &at(std::size_t columnNr) noexcept
90 {
91 hi_assert(columnNr >= 0 && columnNr < _width);
92 return _pixels[columnNr];
93 }
94
95private:
98 T *_pixels;
99
102 std::size_t _width;
103};
104
109template<typename T>
111public:
112 using value_type = T;
113
116 pixel_map() noexcept : _pixels(nullptr), _width(0), _height(0), _stride(0), _self_allocated(true) {}
117
124 pixel_map(T *pixels, std::size_t width, std::size_t height, std::size_t stride) noexcept :
125 _pixels(pixels), _width(width), _height(height), _stride(stride), _self_allocated(false)
126 {
127 hi_assert(_stride >= _width);
128 hi_assert(_width >= 0);
129 hi_assert(_height >= 0);
130
131 if (pixels == nullptr) {
132 _self_allocated = true;
133 _pixels = new T[_height * _stride];
134 }
135 }
136
143 pixel_map(T *pixels, std::size_t width, std::size_t height) noexcept : pixel_map(pixels, width, height, width) {}
144
150 pixel_map(std::size_t width, std::size_t height, std::size_t stride) noexcept : pixel_map(nullptr, width, height, stride) {}
151
157 pixel_map(std::size_t width, std::size_t height) noexcept : pixel_map(nullptr, width, height, width) {}
158
159 ~pixel_map()
160 {
161 if (_self_allocated) {
162 delete[] _pixels;
163 }
164 }
165
171 pixel_map(pixel_map const &other) noexcept :
172 _pixels(other._pixels),
173 _width(other._width),
174 _height(other._height),
175 _stride(other._stride),
176 _self_allocated(other._self_allocated)
177 {
178 if (_self_allocated) {
179 _pixels = new T[_height * _stride];
180
181 for (std::size_t y = 0; y != _height; ++y) {
182 hilet src_row = other[y];
183 auto dst_row = (*this)[y];
184 for (std::size_t x = 0; x != _width; ++x) {
185 dst_row[x] = src_row[x];
186 }
187 }
188 }
189 }
190
191 pixel_map(pixel_map &&other) noexcept :
192 _pixels(other._pixels),
193 _width(other._width),
194 _height(other._height),
195 _stride(other._stride),
196 _self_allocated(other._self_allocated)
197 {
198 hi_axiom(this != &other);
199 other._self_allocated = false;
200 }
201
202 [[nodiscard]] operator bool() const noexcept
203 {
204 return _pixels != nullptr;
205 }
206
207 [[nodiscard]] std::size_t width() const noexcept
208 {
209 return _width;
210 }
211
212 [[nodiscard]] std::size_t height() const noexcept
213 {
214 return _height;
215 }
216
217 [[nodiscard]] std::size_t stride() const noexcept
218 {
219 return _stride;
220 }
221
225 {
226 hi_return_on_self_assignment(other);
227
228 _pixels = other._pixels;
229 _width = other._width;
230 _height = other._height;
231 _stride = other._stride;
232 _self_allocated = other._self_allocated;
233
234 if (_self_allocated) {
235 _pixels = new T[_height * _stride];
236
237 for (std::size_t y = 0; y != _height; ++y) {
238 hilet src_row = other[y];
239 auto dst_row = (*this)[y];
240 for (std::size_t x = 0; x != _width; ++x) {
241 dst_row[x] = src_row[x];
242 }
243 }
244 }
245 return *this;
246 }
247
248 pixel_map &operator=(pixel_map &&other) noexcept
249 {
250 // Self assignment is allowed.
251 if (_self_allocated) {
252 delete[] _pixels;
253 }
254 _pixels = other._pixels;
255 _width = other._width;
256 _height = other._height;
257 _stride = other._stride;
258 _self_allocated = other._self_allocated;
259 other._self_allocated = false;
260 return *this;
261 }
262
263 extent2 extent() const noexcept
264 {
265 return {narrow_cast<float>(_width), narrow_cast<float>(_height)};
266 }
267
275 pixel_map submap(std::size_t x, std::size_t y, std::size_t width, std::size_t height) const noexcept
276 {
277 hi_axiom((x >= 0) && (y >= 0));
278 hi_assert((x + width <= _width) && (y + height <= _height));
279
280 hilet offset = y * _stride + x;
281
282 return pixel_map{_pixels + offset, width, height, _stride};
283 }
284
285 pixel_map submap(aarectangle rectangle) const noexcept
286 {
287 hi_axiom(round(rectangle) == rectangle);
288 return submap(
289 narrow_cast<std::size_t>(rectangle.left()),
290 narrow_cast<std::size_t>(rectangle.bottom()),
291 narrow_cast<std::size_t>(rectangle.width()),
292 narrow_cast<std::size_t>(rectangle.height()));
293 }
294
295 pixel_row<T> const operator[](std::size_t rowNr) const noexcept
296 {
297 return {_pixels + (rowNr * _stride), _width};
298 }
299
300 pixel_row<T> operator[](std::size_t rowNr) noexcept
301 {
302 return {_pixels + (rowNr * _stride), _width};
303 }
304
305 pixel_row<T> const at(std::size_t rowNr) const noexcept
306 {
307 hi_assert(rowNr < _height);
308 return (*this)[rowNr];
309 }
310
311 pixel_row<T> at(std::size_t rowNr) noexcept
312 {
313 hi_assert(rowNr < _height);
314 return (*this)[rowNr];
315 }
316
317private:
320 T *_pixels;
321
324 std::size_t _width;
325
328 std::size_t _height;
329
333 std::size_t _stride;
334
337 bool _self_allocated;
338};
339
340template<typename T>
341void copy(pixel_map<T> const &src, pixel_map<T> &dst) noexcept
342{
343 std::size_t width = std::min(src.width(), dst.width());
344 std::size_t height = std::min(src.height(), dst.height());
345
346 for (std::size_t y = 0; y != height; ++y) {
347 hilet src_row = src[y];
348 auto dst_row = dst[y];
349 for (std::size_t x = 0; x != width; ++x) {
350 dst_row[x] = src_row[x];
351 }
352 }
353}
354
355template<int KERNEL_SIZE, typename KERNEL>
356void horizontalFilterRow(pixel_row<uint8_t> row, KERNEL kernel) noexcept;
357
358template<int KERNEL_SIZE, typename T, typename KERNEL>
359void horizontalFilter(pixel_map<T> &pixels, KERNEL kernel) noexcept;
360
363template<typename T>
364void fill(pixel_map<T> &dst) noexcept;
365
368template<typename T>
369void fill(pixel_map<T> &dst, T color) noexcept;
370
373template<typename T>
374void rotate90(pixel_map<T> &dst, pixel_map<T> const &src) noexcept;
375
378template<typename T>
379void rotate270(pixel_map<T> &dst, pixel_map<T> const &src) noexcept;
380
383void mergeMaximum(pixel_map<uint8_t> &dst, pixel_map<uint8_t> const &src) noexcept;
384
390template<typename T>
391inline void makeTransparentBorder(pixel_map<T> &pixel_map) noexcept;
392
393} // namespace hi::inline v1
394
395hi_warning_pop();
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:110
pixel_map() noexcept
Construct an empty pixel-map.
Definition pixel_map.hpp:116
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:150
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:124
pixel_map(pixel_map const &other) noexcept
Copy constructor of other.
Definition pixel_map.hpp:171
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:157
pixel_map & operator=(pixel_map const &other)
Disallowing copying so that life-time of selfAllocated pixels is easy to understand.
Definition pixel_map.hpp:224
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:275
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:143
A row of pixels.
Definition pixel_map.hpp:28
T * data() noexcept
Get a pointer to the pixel data.
Definition pixel_map.hpp:48
T & operator[](std::size_t columnNr) noexcept
Get a access to a pixel in the row.
Definition pixel_map.hpp:66
T const & at(std::size_t columnNr) const noexcept
Get a access to a pixel in the row.
Definition pixel_map.hpp:77
T const & operator[](std::size_t columnNr) const noexcept
Get a access to a pixel in the row.
Definition pixel_map.hpp:57
T const * data() const noexcept
Get a pointer to the pixel data.
Definition pixel_map.hpp:41
T & at(std::size_t columnNr) noexcept
Get a access to a pixel in the row.
Definition pixel_map.hpp:89
T copy(T... args)
T fill(T... args)
T min(T... args)