roo_display
API Documentation for roo_display
Loading...
Searching...
No Matches
color_io.h
Go to the documentation of this file.
1#pragma once
2
3#include <inttypes.h>
4#include <stddef.h>
5
6#include <cstring>
7
8#include "roo_backport.h"
9#include "roo_backport/byte.h"
13#include "roo_io/data/byte_order.h"
14
15namespace roo_display {
16template <typename ColorMode, roo_io::ByteOrder byte_order,
17 typename Enable = void>
18struct ColorIo {
19 void store(Color src, roo::byte* dest,
20 const ColorMode& mode = ColorMode()) const;
21 Color load(const roo::byte* src, const ColorMode& mode = ColorMode()) const;
22};
23
24// 1-byte pixels.
25template <typename ColorMode, roo_io::ByteOrder byte_order>
26struct ColorIo<ColorMode, byte_order,
27 std::enable_if_t<ColorTraits<ColorMode>::bytes_per_pixel == 1 &&
28 ColorTraits<ColorMode>::pixels_per_byte == 1>> {
29 void store(Color src, roo::byte* dest,
30 const ColorMode& mode = ColorMode()) const
31 __attribute__((always_inline)) {
32 dest[0] = static_cast<roo::byte>(mode.fromArgbColor(src));
33 }
34 Color load(const roo::byte* src, const ColorMode& mode = ColorMode()) const
35 __attribute__((always_inline)) {
36 return mode.toArgbColor(static_cast<uint8_t>(src[0]));
37 }
38};
39
40// 2-byte pixels.
41template <typename ColorMode, roo_io::ByteOrder byte_order>
42struct ColorIo<ColorMode, byte_order,
43 std::enable_if_t<ColorTraits<ColorMode>::bytes_per_pixel == 2>> {
44 void store(Color src, roo::byte* dest,
45 const ColorMode& mode = ColorMode()) const
46 __attribute__((always_inline)) {
47 *(uint16_t*)dest =
48 roo_io::hto<uint16_t, byte_order>(mode.fromArgbColor(src));
49 }
50 Color load(const roo::byte* src, const ColorMode& mode = ColorMode()) const
51 __attribute__((always_inline)) {
52 return mode.toArgbColor(
53 roo_io::toh<uint16_t, byte_order>(*(const uint16_t*)src));
54 }
55};
56
57// 3-byte pixels.
58template <typename ColorMode, roo_io::ByteOrder byte_order>
59struct ColorIo<ColorMode, byte_order,
60 std::enable_if_t<ColorTraits<ColorMode>::bytes_per_pixel == 3 &&
61 ColorTraits<ColorMode>::pixels_per_byte == 1>> {
62 void store(Color src, roo::byte* dest,
63 const ColorMode& mode = ColorMode()) const
64 __attribute__((always_inline)) {
65 uint32_t raw = mode.fromArgbColor(src);
66 if constexpr (byte_order == roo_io::kBigEndian) {
67 dest[0] = static_cast<roo::byte>(raw >> 16);
68 dest[1] = static_cast<roo::byte>(raw >> 8);
69 dest[2] = static_cast<roo::byte>(raw >> 0);
70 } else {
71 dest[0] = static_cast<roo::byte>(raw >> 0);
72 dest[1] = static_cast<roo::byte>(raw >> 8);
73 dest[2] = static_cast<roo::byte>(raw >> 16);
74 }
75 }
76 Color load(const roo::byte* src, const ColorMode& mode = ColorMode()) const
77 __attribute__((always_inline)) {
78 if constexpr (byte_order == roo_io::kBigEndian) {
79 return mode.toArgbColor((static_cast<uint32_t>(src[0]) << 16) |
80 (static_cast<uint32_t>(src[1]) << 8) |
81 (static_cast<uint32_t>(src[2]) << 0));
82 } else {
83 return mode.toArgbColor((static_cast<uint32_t>(src[0]) << 0) |
84 (static_cast<uint32_t>(src[1]) << 8) |
85 (static_cast<uint32_t>(src[2]) << 16));
86 }
87 }
88};
89
90// 4-byte pixels.
91template <typename ColorMode, roo_io::ByteOrder byte_order>
92struct ColorIo<ColorMode, byte_order,
93 std::enable_if_t<ColorTraits<ColorMode>::bytes_per_pixel == 4>> {
94 void store(Color src, roo::byte* dest,
95 const ColorMode& mode = ColorMode()) const
96 __attribute__((always_inline)) {
97 *(uint32_t*)dest =
98 roo_io::hto<uint32_t, byte_order>(mode.fromArgbColor(src));
99 }
100 Color load(const roo::byte* src, const ColorMode& mode = ColorMode()) const
101 __attribute__((always_inline)) {
102 return mode.toArgbColor(
103 roo_io::toh<uint32_t, byte_order>(*(const uint32_t*)src));
104 }
105};
106
107// Utility class for color modes whose pixels_per_byte > 1. Allows callers to
108// load and store raw colors at various pixel indexes. This functionality is
109// here, rather than directly in the ColorMode classes, because it is
110// repetitive: identical for any color mode with the same pixels_per_byte.
111//
112// The template contract (implemented by specializations and partial
113// specializations, below) is the following:
114//
115// struct SubByteColorIo {
116// // Stores the specified raw_color (which is expected to be stored
117// // in the low bits) to the specified target byte, at the specified
118// // index location (from left-to-right, counting from zero). The
119// // index is in the range [0, pixels_per_byte - 1].
120// void storeRaw(uint8_t raw_color, roo::byte *target, int index);
121//
122// // Loads a raw color from the specified byte, at the specified index
123// // (from left-to-right, counting from zero).
124// uint8_t loadRaw(const roo::byte source, int index);
125//
126// // Returns a byte resulting from filling pixels_per_byte pixels
127// // to the same specified raw color.
128// roo::byte expandRaw(uint8_t raw_color);
129//
130// // Takes a byte specifying a sequence of raw colors, and converts
131// // them all to ARGB8, storing the resulting pixels_per_byte colors
132// // in the specified result array.
133// inline void loadBulk(const ColorMode &mode, roo::byte in,
134// Color *result);
135// };
136
137template <typename ColorMode, ColorPixelOrder pixel_order,
138 int8_t pixels_per_byte = ColorTraits<ColorMode>::pixels_per_byte>
140
141// Specialization that works for for Monochrome LSB-first.
142template <typename ColorMode>
144 void storeRaw(uint8_t raw_color, roo::byte* target, int index) const {
145 if (raw_color) {
146 *target |= (roo::byte{0x01} << index);
147 } else {
148 *target &= ~(roo::byte{0x01} << index);
149 }
150 }
151 uint8_t loadRaw(const roo::byte source, int index) {
152 return (source & (roo::byte{0x01} << index)) != roo::byte{0};
153 }
155 return raw_color ? roo::byte{0xFF} : roo::byte{0x00};
156 }
157 inline void loadBulk(const ColorMode& mode, roo::byte in,
158 Color* result) const {
159 result[0] = mode.toArgbColor((in & roo::byte{0x01}) != roo::byte{0});
160 result[1] = mode.toArgbColor((in & roo::byte{0x02}) != roo::byte{0});
161 result[2] = mode.toArgbColor((in & roo::byte{0x04}) != roo::byte{0});
162 result[3] = mode.toArgbColor((in & roo::byte{0x08}) != roo::byte{0});
163 result[4] = mode.toArgbColor((in & roo::byte{0x10}) != roo::byte{0});
164 result[5] = mode.toArgbColor((in & roo::byte{0x20}) != roo::byte{0});
165 result[6] = mode.toArgbColor((in & roo::byte{0x40}) != roo::byte{0});
166 result[7] = mode.toArgbColor((in & roo::byte{0x80}) != roo::byte{0});
167 }
168};
169
170// Specialization that works for for Monochrome MSB-first.
171template <typename ColorMode>
173 void storeRaw(uint8_t raw_color, roo::byte* target, int index) {
174 if (raw_color) {
175 *target |= (roo::byte{0x80} >> index);
176 } else {
177 *target &= ~(roo::byte{0x80} >> index);
178 }
179 }
180 uint8_t loadRaw(const roo::byte source, int index) {
181 return (source & (roo::byte{0x80} >> index)) != roo::byte{0};
182 }
184 return raw_color ? roo::byte{0xFF} : roo::byte{0x00};
185 }
186 inline void loadBulk(const ColorMode& mode, roo::byte in,
187 Color* result) const {
188 result[0] = mode.toArgbColor((in & roo::byte{0x80}) != roo::byte{0});
189 result[1] = mode.toArgbColor((in & roo::byte{0x40}) != roo::byte{0});
190 result[2] = mode.toArgbColor((in & roo::byte{0x20}) != roo::byte{0});
191 result[3] = mode.toArgbColor((in & roo::byte{0x10}) != roo::byte{0});
192 result[4] = mode.toArgbColor((in & roo::byte{0x08}) != roo::byte{0});
193 result[5] = mode.toArgbColor((in & roo::byte{0x04}) != roo::byte{0});
194 result[6] = mode.toArgbColor((in & roo::byte{0x02}) != roo::byte{0});
195 result[7] = mode.toArgbColor((in & roo::byte{0x01}) != roo::byte{0});
196 }
197};
198
199// Specialization that works for for 4bpp color modes.
200template <typename ColorMode>
202 void storeRaw(uint8_t raw_color, roo::byte* target, int index) {
203 roo::byte mask = roo::byte{0xF0} >> (index << 2);
204 *target &= mask;
205 *target |= (roo::byte)(raw_color << (index << 2));
206 }
207 uint8_t loadRaw(const roo::byte source, int index) {
208 return (uint8_t)((source >> (index << 2)) & roo::byte{0x0F});
209 }
211 return (roo::byte)(raw_color * 0x11);
212 }
213 inline void loadBulk(const ColorMode& mode, roo::byte in,
214 Color* result) const {
215 result[0] = mode.toArgbColor((uint8_t)(in & roo::byte{0x0F}));
216 result[1] = mode.toArgbColor((uint8_t)(in >> 4));
217 }
218};
219
220template <typename ColorMode>
222 void storeRaw(uint8_t raw_color, roo::byte* target, int index) {
223 roo::byte mask = (roo::byte{0x0F} << (index << 2));
224 *target &= mask;
225 *target |= (roo::byte)(raw_color << ((1 - index) << 2));
226 }
227 uint8_t loadRaw(const roo::byte source, int index) {
228 return (uint8_t)((source >> ((1 - index) << 2)) & roo::byte{0x0F});
229 }
231 return (roo::byte)(raw_color * 0x11);
232 }
233 inline void loadBulk(const ColorMode& mode, roo::byte in,
234 Color* result) const {
235 result[0] = mode.toArgbColor((uint8_t)(in >> 4));
236 result[1] = mode.toArgbColor((uint8_t)(in & roo::byte{0x0F}));
237 }
238};
239
240// Specialization that works for for 2bpp color modes.
241template <typename ColorMode>
243 void storeRaw(uint8_t raw_color, roo::byte* target, int index) {
244 roo::byte mask = roo::byte{0x03} << (index << 1);
245 *target &= ~mask;
246 *target |= (roo::byte)(raw_color << (index << 1));
247 }
248 uint8_t loadRaw(const roo::byte source, int index) {
249 return (uint8_t)((source >> (index << 1)) & roo::byte{0x03});
250 }
252 return (roo::byte)(raw_color * 0x55);
253 }
254 inline void loadBulk(const ColorMode& mode, roo::byte in,
255 Color* result) const {
256 result[0] = mode.toArgbColor((uint8_t)((in >> 0) & roo::byte{0x03}));
257 result[1] = mode.toArgbColor((uint8_t)((in >> 2) & roo::byte{0x03}));
258 result[2] = mode.toArgbColor((uint8_t)((in >> 4) & roo::byte{0x03}));
259 result[3] = mode.toArgbColor((uint8_t)(in >> 6));
260 }
261};
262
263template <typename ColorMode, roo_io::ByteOrder byte_order,
265 typename Enable = void>
267
268// Default implementation for sub-byte modes.
269template <typename ColorMode, roo_io::ByteOrder byte_order,
270 ColorPixelOrder pixel_order>
272 ColorMode, byte_order, pixel_order,
273 std::enable_if_t<ColorTraits<ColorMode>::pixels_per_byte != 1>> {
274 void decode(const roo::byte* data, size_t row_width_bytes, int16_t x0,
275 int16_t y0, int16_t x1, int16_t y1, Color* output,
276 const ColorMode& mode = ColorMode()) const {
277 constexpr int8_t pixels_per_byte = ColorTraits<ColorMode>::pixels_per_byte;
278 const uint16_t width = x1 - x0 + 1;
279 const uint16_t height = y1 - y0 + 1;
281 if (x0 == 0 && static_cast<size_t>(width * ColorMode::bits_per_pixel) ==
282 row_width_bytes * 8) {
283 const roo::byte* ptr = data + y0 * row_width_bytes;
284 const uint32_t total_pixels = width * height;
285 const uint32_t total_bytes = total_pixels / pixels_per_byte;
286 for (uint32_t i = 0; i < total_bytes; ++i) {
287 io.loadBulk(mode, *ptr++, output);
288 output += pixels_per_byte;
289 }
290 return;
291 }
292 const int16_t byte_index = x0 / pixels_per_byte;
293 const int16_t init_pixel_index = x0 % pixels_per_byte;
294 const int16_t full_limit = ((x1 + 1) / pixels_per_byte) * pixels_per_byte;
295 const int16_t trailing_count = (x1 + 1) % pixels_per_byte;
296
297 const roo::byte* row = data + y0 * row_width_bytes;
298 for (int16_t y = y0; y <= y1; ++y) {
299 const roo::byte* pos = row + byte_index;
300 row += row_width_bytes; // For next row.
301 int16_t x = x0;
302 for (int16_t pidx = init_pixel_index; pidx < pixels_per_byte && x <= x1;
303 ++pidx, ++x) {
304 uint8_t raw = io.loadRaw(*pos, pidx);
305 *output++ = mode.toArgbColor(raw);
306 }
307 if (x > x1) continue;
308 ++pos;
309 for (; x < full_limit; x += pixels_per_byte) {
310 io.loadBulk(mode, *pos++, output);
311 output += pixels_per_byte;
312 }
313 if (x > x1) continue;
314 for (int16_t pidx = 0; pidx < trailing_count; ++pidx) {
315 uint8_t raw = io.loadRaw(*pos, pidx);
316 *output++ = mode.toArgbColor(raw);
317 }
318 }
319 }
320
321 bool decodeIfUniform(const roo::byte* data, size_t row_width_bytes,
322 int16_t x0, int16_t y0, int16_t x1, int16_t y1,
323 Color* output,
324 const ColorMode& mode = ColorMode()) const {
325 constexpr int8_t pixels_per_byte = ColorTraits<ColorMode>::pixels_per_byte;
327
328 const roo::byte* first_row = data + y0 * row_width_bytes;
329 const int16_t first_byte_index = x0 / pixels_per_byte;
330 const int16_t first_pixel_index = x0 % pixels_per_byte;
331 const uint8_t raw =
333 const roo::byte raw_expanded = io.expandRaw(raw);
334
335 const int16_t width = x1 - x0 + 1;
336 const int16_t height = y1 - y0 + 1;
337 if (x0 == 0 && static_cast<size_t>(width * ColorMode::bits_per_pixel) ==
338 row_width_bytes * 8) {
339 const roo::byte* row = data + y0 * row_width_bytes;
340 for (int16_t y = 0; y < height; ++y) {
341 const roo::byte* ptr = row;
342 for (size_t i = 0; i < row_width_bytes; ++i) {
343 if (*ptr++ != raw_expanded) return false;
344 }
346 }
347 *output = mode.toArgbColor(raw);
348 return true;
349 }
350
351 const int16_t full_limit = ((x1 + 1) / pixels_per_byte) * pixels_per_byte;
352 const int16_t trailing_count = (x1 + 1) % pixels_per_byte;
353 const int16_t init_pixel_index = x0 % pixels_per_byte;
354 const int16_t byte_index = x0 / pixels_per_byte;
355
356 const roo::byte* row = data + y0 * row_width_bytes;
357 for (int16_t y = y0; y <= y1; ++y) {
358 const roo::byte* pos = row + byte_index;
360 int16_t x = x0;
361
362 for (int16_t pidx = init_pixel_index; pidx < pixels_per_byte && x <= x1;
363 ++pidx, ++x) {
364 if (io.loadRaw(*pos, pidx) != raw) return false;
365 }
366 if (x > x1) continue;
367
368 ++pos;
369 for (; x < full_limit; x += pixels_per_byte) {
370 if (*pos++ != raw_expanded) return false;
371 }
372 if (x > x1) continue;
373
374 for (int16_t pidx = 0; pidx < trailing_count; ++pidx) {
375 if (io.loadRaw(*pos, pidx) != raw) return false;
376 }
377 }
378
379 *output = mode.toArgbColor(raw);
380 return true;
381 }
382};
383
384// Specialization for full-byte modes.
385template <typename ColorMode, roo_io::ByteOrder byte_order,
386 ColorPixelOrder pixel_order>
388 ColorMode, byte_order, pixel_order,
389 std::enable_if_t<ColorTraits<ColorMode>::pixels_per_byte == 1>> {
390 void decode(const roo::byte* data, size_t row_width_bytes, int16_t x0,
391 int16_t y0, int16_t x1, int16_t y1, Color* output,
392 const ColorMode& mode = ColorMode()) const {
393 constexpr size_t bytes_per_pixel = ColorTraits<ColorMode>::bytes_per_pixel;
394 const int16_t width = x1 - x0 + 1;
395 const int16_t height = y1 - y0 + 1;
397 if (x0 == 0 && width * bytes_per_pixel == row_width_bytes) {
398 const roo::byte* ptr = data + y0 * row_width_bytes;
399 uint32_t count = static_cast<uint32_t>(width) * height;
400 while (count-- > 0) {
401 *output++ = io.load(ptr, mode);
402 ptr += bytes_per_pixel;
403 }
404 return;
405 }
406 const roo::byte* row = data + y0 * row_width_bytes + x0 * bytes_per_pixel;
407 for (int16_t y = y0; y <= y1; ++y) {
408 const roo::byte* pixel = row;
409 for (int16_t x = x0; x <= x1; ++x) {
410 *output++ = io.load(pixel, mode);
411 pixel += bytes_per_pixel;
412 }
414 }
415 }
416
417 bool decodeIfUniform(const roo::byte* data, size_t row_width_bytes,
418 int16_t x0, int16_t y0, int16_t x1, int16_t y1,
419 Color* output,
420 const ColorMode& mode = ColorMode()) const {
421 constexpr size_t bytes_per_pixel = ColorTraits<ColorMode>::bytes_per_pixel;
422 const int16_t width = x1 - x0 + 1;
423
424 const roo::byte* first = data + y0 * row_width_bytes + x0 * bytes_per_pixel;
425 const roo::byte* row = first;
426 for (int16_t y = y0; y <= y1; ++y) {
427 const roo::byte* pixel = row;
428 for (int16_t x = 0; x < width; ++x) {
429 if (std::memcmp(pixel, first, bytes_per_pixel) != 0) return false;
430 pixel += bytes_per_pixel;
431 }
433 }
434
436 *output = io.load(first, mode);
437 return true;
438 }
439};
440
441template <typename ColorMode>
443 void storeRaw(uint8_t raw_color, roo::byte* target, int index) {
444 roo::byte mask = (roo::byte{0x03} << ((3 - index) << 1));
445 *target &= ~mask;
446 *target |= (roo::byte)(raw_color << ((3 - index) << 1));
447 }
448 uint8_t loadRaw(const roo::byte source, int index) {
449 return (uint8_t)((source >> ((3 - index) << 1)) & roo::byte{0x03});
450 }
452 return (roo::byte)(raw_color * 0x55);
453 }
454 inline void loadBulk(const ColorMode& mode, roo::byte in,
455 Color* result) const {
456 result[0] = mode.toArgbColor((uint8_t)(in >> 6));
457 result[1] = mode.toArgbColor((uint8_t)((in >> 4) & roo::byte{0x03}));
458 result[2] = mode.toArgbColor((uint8_t)((in >> 2) & roo::byte{0x03}));
459 result[3] = mode.toArgbColor((uint8_t)((in >> 0) & roo::byte{0x03}));
460 }
461};
462
463} // namespace roo_display
ARGB8888 color stored as a 32-bit unsigned integer.
Definition color.h:16
Defines 140 opaque HTML named colors.
Color load(const roo::byte *src, const ColorMode &mode=ColorMode()) const __attribute__((always_inline))
Definition color_io.h:50
void store(Color src, roo::byte *dest, const ColorMode &mode=ColorMode()) const __attribute__((always_inline))
Definition color_io.h:44
void store(Color src, roo::byte *dest, const ColorMode &mode=ColorMode()) const __attribute__((always_inline))
Definition color_io.h:62
void store(Color src, roo::byte *dest, const ColorMode &mode=ColorMode()) const __attribute__((always_inline))
Definition color_io.h:29
Color load(const roo::byte *src, const ColorMode &mode=ColorMode()) const __attribute__((always_inline))
Definition color_io.h:100
void store(Color src, roo::byte *dest, const ColorMode &mode=ColorMode()) const __attribute__((always_inline))
Definition color_io.h:94
Color load(const roo::byte *src, const ColorMode &mode=ColorMode()) const
void store(Color src, roo::byte *dest, const ColorMode &mode=ColorMode()) const
bool decodeIfUniform(const roo::byte *data, size_t row_width_bytes, int16_t x0, int16_t y0, int16_t x1, int16_t y1, Color *output, const ColorMode &mode=ColorMode()) const
Definition color_io.h:417
void decode(const roo::byte *data, size_t row_width_bytes, int16_t x0, int16_t y0, int16_t x1, int16_t y1, Color *output, const ColorMode &mode=ColorMode()) const
Definition color_io.h:390
void decode(const roo::byte *data, size_t row_width_bytes, int16_t x0, int16_t y0, int16_t x1, int16_t y1, Color *output, const ColorMode &mode=ColorMode()) const
Definition color_io.h:274
bool decodeIfUniform(const roo::byte *data, size_t row_width_bytes, int16_t x0, int16_t y0, int16_t x1, int16_t y1, Color *output, const ColorMode &mode=ColorMode()) const
Definition color_io.h:321
Traits for a color mode's storage characteristics.
Definition traits.h:9
void loadBulk(const ColorMode &mode, roo::byte in, Color *result) const
Definition color_io.h:213
void storeRaw(uint8_t raw_color, roo::byte *target, int index)
Definition color_io.h:202
void storeRaw(uint8_t raw_color, roo::byte *target, int index)
Definition color_io.h:243
void loadBulk(const ColorMode &mode, roo::byte in, Color *result) const
Definition color_io.h:254
void loadBulk(const ColorMode &mode, roo::byte in, Color *result) const
Definition color_io.h:157
void storeRaw(uint8_t raw_color, roo::byte *target, int index) const
Definition color_io.h:144
void storeRaw(uint8_t raw_color, roo::byte *target, int index)
Definition color_io.h:222
void loadBulk(const ColorMode &mode, roo::byte in, Color *result) const
Definition color_io.h:233
void storeRaw(uint8_t raw_color, roo::byte *target, int index)
Definition color_io.h:443
void loadBulk(const ColorMode &mode, roo::byte in, Color *result) const
Definition color_io.h:454
void loadBulk(const ColorMode &mode, roo::byte in, Color *result) const
Definition color_io.h:186
void storeRaw(uint8_t raw_color, roo::byte *target, int index)
Definition color_io.h:173
#define const
Definition zconf.h:230