Haio
0.2.X
Homebrew Asset IO/CDN
Toggle main menu visibility
Loading...
Searching...
No Matches
encode.cpp
Go to the documentation of this file.
1
#include <
haio_codec.hpp
>
2
#include <haio_codecs.hpp>
3
#include <
haio_convert.hpp
>
4
5
#include <string>
6
7
namespace
{
8
9
/** U+2580, which fills the top half of the cell and leaves the bottom to the background */
10
constexpr
std::string_view halfBlock =
"▀"
;
11
12
void
appendNumber(std::string& out,
int
value) {
13
out += std::to_string(value);
14
}
15
16
}
17
18
namespace
Haio::Codecs
{
19
20
/**
21
* two pixel rows per terminal row, using the upper half block.
22
*
23
* the foreground paints the top pixel and the background the bottom one, which buys
24
* twice the vertical resolution of the ansi rendering for the same number of lines
25
* and makes the aspect ratio come out roughly square.
26
*
27
* an odd number of rows leaves the last cell with nothing below it, and its
28
* background is left black rather than repeating the row above: a doubled last line
29
* reads as part of the picture, a dark one reads as the edge.
30
*/
31
template
<>
32
Result<Blob>
Encode<Format::UTF8, Color::RGB888>
(Image<Color::RGB888> img) {
33
const
Size size{img.width, img.height};
34
HAIO_TRY
(expected,
sizeOf
(
Color::RGB888
, size));
35
if
(img.data.size() != expected)
HAIO_FAIL
(InvalidInput,
"invalid rgb888 image for utf8 encode"
);
36
37
const
auto
width =
static_cast<
size_t
>
(img.width);
38
const
auto
height =
static_cast<
size_t
>
(img.height);
39
40
std::string out;
41
out.reserve(width * ((height + 1) / 2) * 40);
42
43
const
auto
colourAt = [&](
size_t
row,
size_t
x,
bool
present) -> uint32_t {
44
if
(!present)
return
0;
45
const
auto
at = (row * width + x) * 3;
46
return
(
static_cast<
uint32_t
>
(img.data[at + 0]) << 16)
47
| (
static_cast<
uint32_t
>
(img.data[at + 1]) << 8)
48
| img.data[at + 2];
49
};
50
51
const
auto
appendColour = [&](std::string_view lead, uint32_t colour) {
52
out += lead;
53
appendNumber(out,
static_cast<
int
>
((colour >> 16) & 0xFF));
54
out +=
';'
;
55
appendNumber(out,
static_cast<
int
>
((colour >> 8) & 0xFF));
56
out +=
';'
;
57
appendNumber(out,
static_cast<
int
>
(colour & 0xFF));
58
};
59
60
for
(
size_t
y = 0; y < height; y += 2) {
61
/**
62
* a terminal keeps the colour it was last told, so saying it again is bytes
63
* nobody reads. a picture in few colours repeats itself constantly, and this
64
* is exactly the picture somebody renders in a terminal.
65
*
66
* the pair is tracked rather than each half, because a cell sets both at once.
67
*/
68
uint32_t lastTop = 0;
69
uint32_t lastBottom = 0;
70
bool
anySoFar =
false
;
71
72
for
(
size_t
x = 0; x < width; x++) {
73
const
auto
top = colourAt(y, x,
true
);
74
const
auto
bottom = colourAt(y + 1, x, y + 1 < height);
75
76
if
(!anySoFar || top != lastTop || bottom != lastBottom) {
77
appendColour(
"\x1b[38;2;"
, top);
78
appendColour(
";48;2;"
, bottom);
79
out +=
'm'
;
80
lastTop = top;
81
lastBottom = bottom;
82
anySoFar =
true
;
83
}
84
out += halfBlock;
85
}
86
// the reset ends the row, so the next one starts with nothing assumed
87
out +=
"\x1b[0m\n"
;
88
}
89
90
return
Blob{
Format::UTF8
,
Color::RGB888
,
"text/x-ansi-halfblock"
, {},
91
std::vector<uint8_t>(out.begin(), out.end())};
92
}
93
94
}
haio_codec.hpp
HAIO_TRY
#define HAIO_TRY(name, expr)
Definition
haio_codec.hpp:246
HAIO_FAIL
#define HAIO_FAIL(why, message)
Definition
haio_codec.hpp:258
haio_convert.hpp
Haio::Codecs
Definition
haio_codec.hpp:136
Haio::Codecs::Encode< Format::UTF8, Color::RGB888 >
Result< Blob > Encode< Format::UTF8, Color::RGB888 >(Image< Color::RGB888 > img)
Definition
encode.cpp:32
Haio::Color::RGB888
@ RGB888
Definition
haio_formats.hpp:108
Haio::Result
std::expected< T, Error > Result
Definition
haio_codec.hpp:32
Haio::sizeOf
Result< size_t > sizeOf(Color color, Size size)
Definition
sizes.cpp:6
Haio::Format::UTF8
@ UTF8
Definition
haio_formats.hpp:73
library
backend
codecs
container
utf8
encode.cpp
Generated by
1.18.0