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
#include <
haio_util.hpp
>
5
6
#include <algorithm>
7
#include <array>
8
#include <cstdio>
9
#include <optional>
10
#include <string>
11
#include <string_view>
12
13
namespace
{
14
15
constexpr
std::string_view base62 =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
;
16
constexpr
int
base62PairMax = 62 * 62 - 1;
17
18
/**
19
* zcis splits the canvas into two layers of alternating rows, so that each layer
20
* stays a decodable image on its own and both together rebuild the original
21
* without losing a pixel.
22
*
23
* @note ZCIS.md marks "B" with the vertical bar glyph, which reads as alternating
24
* columns; the row split described here is the "C" glyph. Flip these two constants
25
* (and rowLayers) if the table is meant literally.
26
*/
27
constexpr
char
baseCommand =
'A'
;
28
constexpr
char
refineCommand =
'B'
;
29
30
constexpr
std::string_view indexMemberName =
"000000000000.txt"
;
31
32
std::string base62Pair(
int
value) {
33
return
{base62[
static_cast<
size_t
>
(value) / 62], base62[
static_cast<
size_t
>
(value) % 62]};
34
}
35
36
/** ar members sit on even offsets, padded with a newline. */
37
std::optional<Haio::Error> appendMember(std::vector<uint8_t>& out,
const
std::string& name,
const
std::vector<uint8_t>& body) {
38
std::array<char, 61> header{};
39
const
int
written = std::snprintf(
40
header.data(),
41
header.size(),
42
"%-16s%-12u%-6u%-6u%-8o%-10zu`\n"
,
43
name.c_str(),
44
0u,
45
0u,
46
0u,
47
0644u,
48
body.size()
49
);
50
if
(written != 60)
return
Haio::Error
{
Haio::ErrorCode::InvalidInput
,
"zcis member header overflow: "
+ name};
51
52
out.insert(out.end(), header.begin(), header.begin() + 60);
53
out.insert(out.end(), body.begin(), body.end());
54
if
(body.size() % 2 != 0) out.push_back(
'\n'
);
55
return
std::nullopt;
56
}
57
58
void
appendBytes(std::vector<uint8_t>& out, std::string_view text) {
59
out.insert(out.end(), text.begin(), text.end());
60
}
61
62
Haio::Image<Haio::Color::RGBA8888>
selectRows(
const
Haio::Image<Haio::Color::RGBA8888>
& image,
int
parity) {
63
const
int
height = (image.
height
- parity + 1) / 2;
64
const
auto
stride =
static_cast<
size_t
>
(image.
width
) * 4;
65
66
std::vector<uint8_t> data(stride *
static_cast<
size_t
>
(height));
67
for
(
int
y = 0; y < height; y++) {
68
const
auto
src =
static_cast<
size_t
>
(2 * y + parity) * stride;
69
std::copy_n(image.
data
.data() + src, stride, data.data() +
static_cast<
size_t
>
(y) * stride);
70
}
71
return
Haio::Image<Haio::Color::RGBA8888>
{image.
width
, height, std::move(data)};
72
}
73
74
}
75
76
namespace
Haio::Codecs
{
77
78
/**
79
* @addtogroup encode
80
* @{
81
*/
82
template
<>
83
Result<Blob>
Encode<Format::ZCIS, Color::RGBA8888>
(Image<Color::RGBA8888> img) {
84
const
auto
expected =
static_cast<
size_t
>
(img.width) *
static_cast<
size_t
>
(img.height) * 4;
85
if
(img.width <= 0 || img.height <= 0 || img.data.size() != expected) {
86
HAIO_FAIL
(InvalidInput,
"invalid rgba8888 image for zcis encode"
);
87
}
88
if
(img.width > base62PairMax || img.height > base62PairMax) {
89
HAIO_FAIL
(InvalidInput,
"zcis dimensions exceed base62 limit"
);
90
}
91
92
std::vector<uint8_t> out;
93
appendBytes(out,
"!<arch>\n"
);
94
95
const
auto
index =
"0 0 "
+ std::to_string(img.width) +
" "
+ std::to_string(img.height) +
"\r\n"
;
96
HAIO_CHECK
(appendMember(out, std::string(indexMemberName), {index.begin(), index.end()}));
97
98
const
auto
target = base62Pair(0) + base62Pair(0) + base62Pair(img.width) + base62Pair(img.height);
99
100
int
order = 1;
101
const
auto
appendLayer = [&](
char
command,
const
Image<Color::RGBA8888>& layer) -> std::optional<Error> {
102
if
(layer.height <= 0)
return
std::nullopt;
103
104
auto
payload =
Encode<Format::PPM, Color::RGBA8888>
(Image<Color::RGBA8888>{layer});
105
if
(!payload)
return
payload.error();
106
107
const
auto
name = std::string(1, base62[
static_cast<
size_t
>
(order++)]) + command + target +
".ppm/"
;
108
return
appendMember(out, name, payload->data);
109
};
110
111
HAIO_CHECK
(appendLayer(baseCommand, selectRows(img, 0)));
112
HAIO_CHECK
(appendLayer(refineCommand, selectRows(img, 1)));
113
114
return
Blob{
Format::ZCIS
,
Color::RGBA8888
,
"image/x-zcis"
, {}, std::move(out)};
115
}
116
/** @} */
117
118
}
Haio::Codecs::Encode< Format::PPM, Color::RGBA8888 >
Result< Blob > Encode< Format::PPM, Color::RGBA8888 >(Image< Color::RGBA8888 > img)
Definition
encode.cpp:19
Haio::Codecs::Encode< Format::ZCIS, Color::RGBA8888 >
Result< Blob > Encode< Format::ZCIS, Color::RGBA8888 >(Image< Color::RGBA8888 > img)
Definition
encode.cpp:83
haio_codec.hpp
HAIO_FAIL
#define HAIO_FAIL(why, message)
Definition
haio_codec.hpp:258
HAIO_CHECK
#define HAIO_CHECK(expr)
Definition
haio_codec.hpp:252
haio_convert.hpp
haio_util.hpp
Haio::Codecs
Definition
haio_codec.hpp:136
Haio::Color::RGBA8888
@ RGBA8888
Definition
haio_formats.hpp:107
Haio::Result
std::expected< T, Error > Result
Definition
haio_codec.hpp:32
Haio::Format::ZCIS
@ ZCIS
Definition
haio_formats.hpp:59
Haio::ErrorCode::InvalidInput
@ InvalidInput
Definition
haio_codec.hpp:18
Haio::Error
Definition
haio_codec.hpp:26
Haio::Image
Definition
haio_codec.hpp:36
Haio::Image::height
int height
Definition
haio_codec.hpp:39
Haio::Image::width
int width
Definition
haio_codec.hpp:38
Haio::Image::data
std::vector< uint8_t > data
Definition
haio_codec.hpp:40
library
backend
codecs
container
zcis
encode.cpp
Generated by
1.18.0