Haio
0.2.X
Homebrew Asset IO/CDN
Toggle main menu visibility
Loading...
Searching...
No Matches
haio_registry.hpp
Go to the documentation of this file.
1
#pragma once
2
3
// the generated list comes first on purpose. everything below asks the codecs what
4
// they can do, and a concept evaluated before they are declared caches the answer
5
// "no" for the rest of the build, silently.
6
#include "haio_codecs.hpp"
7
8
#include "
haio_codec.hpp
"
9
#include "
haio_convert.hpp
"
10
11
namespace
Haio
{
12
13
constexpr
std::string_view
formatName
(
Format
wanted) {
14
HAIO_FOR_EACH_FORMAT
(e) {
15
if
(std::meta::extract<Format>(e) == wanted)
return
lowerOf
(e);
16
}
17
return
"raw"
;
18
}
19
20
constexpr
std::string_view
colorName
(
Color
wanted) {
21
HAIO_FOR_EACH_COLOR
(e) {
22
if
(std::meta::extract<Color>(e) == wanted)
return
lowerOf
(e);
23
}
24
return
"rgba8888"
;
25
}
26
27
namespace
Detail
{
28
29
constexpr
std::string_view
lowered
(std::string_view name,
char
(&buffer)[32]) {
30
if
(name.size() >=
sizeof
(buffer))
return
{};
31
for
(
size_t
i = 0; i < name.size(); i++) {
32
const
char
c = name[i];
33
buffer[i] = (c >=
'A'
&& c <= 'Z') ? static_cast<char>(c -
'A'
+
'a'
) : c;
34
}
35
return
{buffer, name.size()};
36
}
37
38
}
39
40
constexpr
Format
formatFromName
(std::string_view name) {
41
char
buffer[32]{};
42
const
auto
key =
Detail::lowered
(name, buffer);
43
HAIO_FOR_EACH_FORMAT
(e) {
44
if
(
lowerOf
(e) == key)
return
std::meta::extract<Format>(e);
45
}
46
return
Format::RAW
;
47
}
48
49
/**
50
* the colour somebody typed, or nothing when no colour answers to that name.
51
*
52
* the enumerator names come first and then colorAliases, which is every other name
53
* the same layouts go by. borrowing ffmpeg's option without its vocabulary would be
54
* borrowing the half that does not help.
55
*/
56
constexpr
std::optional<Color>
colorNamed
(std::string_view name) {
57
char
buffer[32]{};
58
const
auto
key =
Detail::lowered
(name, buffer);
59
HAIO_FOR_EACH_COLOR
(e) {
60
if
(
lowerOf
(e) == key)
return
std::meta::extract<Color>(e);
61
}
62
63
for
(
const
auto
& alias :
colorAliases
) {
64
if
(alias.spelling == key)
return
alias.color;
65
}
66
return
std::nullopt;
67
}
68
69
/** the same question where an unknown name is not worth stopping for */
70
constexpr
Color
colorFromName
(std::string_view name) {
71
const
auto
color =
colorNamed
(name);
72
return
color ? *color :
Color::RGBA8888
;
73
}
74
75
/** what a file turned out to be: the container and the colour it holds */
76
struct
Found
{
77
Format
format
=
Format::RAW
;
78
Color
color
=
Color::RGBA8888
;
79
80
explicit
operator
bool() const noexcept {
return
format
!=
Format::RAW
; }
81
};
82
83
/** asks every declared pair, so "which payload is inside" needs no separate reader */
84
inline
Found
Detect
(
Bytes
data) {
85
Found
found;
86
HAIO_FOR_EACH_FORMAT
(f) {
87
constexpr
Format
format = std::meta::extract<Format>(f);
88
HAIO_FOR_EACH_COLOR
(c) {
89
constexpr
Color
color = std::meta::extract<Color>(c);
90
if
constexpr
(
Codecs::Detectable<format, color>
) {
91
if
(!found &&
Codecs::Detect<format, color>
(data)) found =
Found
{format, color};
92
}
93
}
94
}
95
return
found;
96
}
97
98
constexpr
bool
detectable
(
Format
format,
Color
color) {
99
HAIO_FOR_EACH_FORMAT
(f) {
100
constexpr
Format
ff = std::meta::extract<Format>(f);
101
HAIO_FOR_EACH_COLOR
(c) {
102
constexpr
Color
cc = std::meta::extract<Color>(c);
103
if
(ff == format && cc == color)
return
Codecs::Detectable<ff, cc>
;
104
}
105
}
106
return
false
;
107
}
108
109
constexpr
bool
encodable
(
Format
format,
Color
color) {
110
HAIO_FOR_EACH_FORMAT
(f) {
111
constexpr
Format
ff = std::meta::extract<Format>(f);
112
HAIO_FOR_EACH_COLOR
(c) {
113
constexpr
Color
cc = std::meta::extract<Color>(c);
114
if
(ff == format && cc == color)
return
Codecs::Encodable<ff, cc>
;
115
}
116
}
117
return
false
;
118
}
119
120
/**
121
* the colour a container is written in when nobody names one: the one it declares as
122
* its own, and failing that the first it can write at all.
123
*
124
* before this there was only the second half, so the colour a file came out in was
125
* whichever one happened to be declared earliest in the enum. that is fine while a
126
* container writes one colour and arbitrary the moment it writes six.
127
*/
128
constexpr
std::optional<Color>
encodeColorFor
(
Format
to) {
129
std::optional<Color> first;
130
HAIO_FOR_EACH_FORMAT
(f) {
131
constexpr
Format
format = std::meta::extract<Format>(f);
132
if
(format != to)
continue
;
133
HAIO_FOR_EACH_COLOR
(c) {
134
constexpr
Color
color = std::meta::extract<Color>(c);
135
if
constexpr
(
Codecs::Encodable<format, color>
) {
136
if
constexpr
(
Codecs::HasDefaultColor<format>
) {
137
if
(
Codecs::DefaultColor<format>::value
== color)
return
color;
138
}
139
if
(!first) first = color;
140
}
141
}
142
}
143
return
first;
144
}
145
146
/**
147
* the runtime way in: reads the bytes, routes to the pair that matched, and brings
148
* the result to rgba8888 so the caller has one type to hold.
149
*
150
* @todo everything funnels through rgba8888, so ktx2(etc1) -> ktx2 decompresses and
151
* recompresses for nothing. keeping the payload needs a typed path, which is exactly
152
* what Codecs::Decode<Format, Color> already offers; only this runtime bridge flattens it.
153
*/
154
inline
Result<Image<Color::RGBA8888>
>
Decode
(
const
Blob
& blob) {
155
const
auto
found = blob.
format
!=
Format::RAW
?
Found
{blob.
format
, blob.
color
} :
Detect
(blob.
data
);
156
if
(!found) {
157
return
std::unexpected(
Error
{
ErrorCode::UnsupportedFormat
,
"unrecognised input"
});
158
}
159
160
Result<Image<Color::RGBA8888>
> out =
161
std::unexpected(
Error
{
ErrorCode::UnsupportedFormat
,
162
"cannot decode "
+ std::string(
formatName
(found.format))
163
+
" "
+ std::string(
colorName
(found.color))});
164
165
HAIO_FOR_EACH_FORMAT
(f) {
166
constexpr
Format
format = std::meta::extract<Format>(f);
167
HAIO_FOR_EACH_COLOR
(c) {
168
constexpr
Color
color = std::meta::extract<Color>(c);
169
if
constexpr
(
Codecs::Decodable<format, color>
) {
170
if
(format != found.format || color != found.color)
continue
;
171
172
auto
decoded =
Codecs::Decode<format, color>
(blob);
173
if
(!decoded) {
174
out = std::unexpected(decoded.error());
175
}
else
if
constexpr
(color ==
Color::RGBA8888
) {
176
out = *std::move(decoded);
177
}
else
if
constexpr
(
Codecs::Convertible<color, Color::RGBA8888>
) {
178
out =
Codecs::Convert<color, Color::RGBA8888>
(*std::move(decoded));
179
}
else
{
180
out = std::unexpected(
Error
{
ErrorCode::UnsupportedFormat
,
181
"no route from "
+ std::string(
colorName
(color)) +
" to rgba8888"
});
182
}
183
}
184
}
185
}
186
return
out;
187
}
188
189
/**
190
* the same picture in another colour, named at runtime.
191
*
192
* it hands back bytes rather than an image because at runtime there is no Image<P> to
193
* hand back: the colour is a value here, and the type it would pick is a compile time
194
* thing. the callers that want one already know which they want and say so through
195
* Codecs::Convert.
196
*/
197
inline
Result<std::vector<uint8_t>
>
Convert
(
const
Image<Color::RGBA8888>
& image,
Color
to) {
198
if
(to ==
Color::RGBA8888
)
return
image.
data
;
199
200
Result<std::vector<uint8_t>
> out =
201
std::unexpected(
Error
{
ErrorCode::UnsupportedFormat
,
202
"no route from rgba8888 to "
+ std::string(
colorName
(to))});
203
204
HAIO_FOR_EACH_COLOR
(c) {
205
constexpr
Color
color = std::meta::extract<Color>(c);
206
if
constexpr
(
Codecs::Convertible<Color::RGBA8888, color>
) {
207
if
(color != to)
continue
;
208
209
auto
converted =
Codecs::Convert<Color::RGBA8888, color>
(image);
210
if
(!converted) {
211
out = std::unexpected(converted.error());
212
}
else
{
213
out = std::move(converted->data);
214
}
215
}
216
}
217
return
out;
218
}
219
220
/**
221
* the runtime way out. rgba8888 goes in because that is what the runtime decode
222
* hands back; the colour stored inside is the one asked for, or the one the container
223
* calls its own when nobody asked.
224
*
225
* naming it is what -pix_fmt does, and it is the only way to say "a ktx2 holding
226
* etc1" or "a tga holding bgr888" from a command line: the pair was always there in
227
* Codecs::Encode, with nothing but this bridge between it and a string.
228
*/
229
inline
Result<Blob>
Encode
(
Image<Color::RGBA8888>
image,
Format
to, std::optional<Color> as = std::nullopt) {
230
const
auto
wanted = as ? as :
encodeColorFor
(to);
231
if
(!wanted) {
232
return
std::unexpected(
Error
{
ErrorCode::UnsupportedFormat
,
233
"cannot encode "
+ std::string(
formatName
(to))});
234
}
235
236
Result<Blob>
out = std::unexpected(
Error
{
ErrorCode::UnsupportedFormat
,
237
"a "
+ std::string(
formatName
(to)) +
" cannot hold "
238
+ std::string(
colorName
(*wanted))});
239
bool
done =
false
;
240
241
HAIO_FOR_EACH_COLOR
(c) {
242
constexpr
Color
color = std::meta::extract<Color>(c);
243
HAIO_FOR_EACH_FORMAT
(f) {
244
constexpr
Format
format = std::meta::extract<Format>(f);
245
if
constexpr
(
Codecs::Encodable<format, color>
) {
246
if
(done || format != to || color != *wanted)
continue
;
247
248
if
constexpr
(color ==
Color::RGBA8888
) {
249
out =
Codecs::Encode<format, color>
(image);
250
done =
true
;
251
}
else
if
constexpr
(
Codecs::Convertible<Color::RGBA8888, color>
) {
252
auto
converted =
Codecs::Convert<Color::RGBA8888, color>
(image);
253
out = converted ?
Codecs::Encode<format, color>
(*std::move(converted))
254
:
Result<Blob>
{std::unexpected(converted.error())};
255
done =
true
;
256
}
else
{
257
// the pair exists and the road to it does not, which is a different
258
// sentence from the container not holding that colour at all
259
out = std::unexpected(
Error
{
ErrorCode::UnsupportedFormat
,
260
"no route from rgba8888 to "
+ std::string(
colorName
(color))});
261
done =
true
;
262
}
263
}
264
}
265
}
266
return
out;
267
}
268
269
/**
270
* the indexed way out, for the containers that store a palette rather than expanding
271
* it. there is no conversion into it here on purpose: haio does not pick colours for
272
* anybody, so the picture arrives already fitted to a palette or not at all.
273
*/
274
inline
Result<Blob>
Encode
(
Image<Color::PALETTE>
image,
Format
to) {
275
Result<Blob>
out = std::unexpected(
Error
{
ErrorCode::UnsupportedFormat
,
276
"a "
+ std::string(
formatName
(to)) +
" cannot hold a palette"
});
277
HAIO_FOR_EACH_FORMAT
(f) {
278
constexpr
Format
format = std::meta::extract<Format>(f);
279
if
constexpr
(
Codecs::Encodable<format, Color::PALETTE>
) {
280
if
(format != to)
continue
;
281
out =
Codecs::Encode<format, Color::PALETTE>
(std::move(image));
282
}
283
}
284
return
out;
285
}
286
287
}
Haio::Codecs::Convertible
Definition
haio_codec.hpp:237
Haio::Codecs::Decodable
Definition
haio_codec.hpp:222
Haio::Codecs::Detectable
Definition
haio_codec.hpp:217
Haio::Codecs::Encodable
Definition
haio_codec.hpp:227
Haio::Codecs::HasDefaultColor
Definition
haio_codec.hpp:211
haio_codec.hpp
HAIO_FOR_EACH_COLOR
#define HAIO_FOR_EACH_COLOR(e)
Definition
haio_codec.hpp:265
HAIO_FOR_EACH_FORMAT
#define HAIO_FOR_EACH_FORMAT(e)
Definition
haio_codec.hpp:262
haio_convert.hpp
Haio::Codecs::Convert
Result< Image< To > > Convert(Image< From >)=delete
Haio::Codecs::Decode
Result< Image< P > > Decode(const Blob &)=delete
Haio::Codecs::Detect
bool Detect(Bytes)=delete
Haio::Codecs::Encode
Result< Blob > Encode(Image< P >)=delete
Haio::Codecs::DefaultColor
Definition
haio_codec.hpp:143
Haio::Detail
Definition
haio_registry.hpp:27
Haio::Detail::lowered
constexpr std::string_view lowered(std::string_view name, char(&buffer)[32])
Definition
haio_registry.hpp:29
Haio
Definition
haio.hpp:11
Haio::Encode
Result< Blob > Encode(Image< Color::RGBA8888 > image, Format to, std::optional< Color > as=std::nullopt)
Definition
haio_registry.hpp:229
Haio::encodeColorFor
constexpr std::optional< Color > encodeColorFor(Format to)
Definition
haio_registry.hpp:128
Haio::Detect
Found Detect(Bytes data)
Definition
haio_registry.hpp:84
Haio::detectable
constexpr bool detectable(Format format, Color color)
Definition
haio_registry.hpp:98
Haio::colorAliases
constexpr ColorAlias colorAliases[]
Definition
haio_formats.hpp:172
Haio::encodable
constexpr bool encodable(Format format, Color color)
Definition
haio_registry.hpp:109
Haio::Color
Color
Definition
haio_formats.hpp:106
Haio::Color::RGBA8888
@ RGBA8888
Definition
haio_formats.hpp:107
Haio::formatFromName
constexpr Format formatFromName(std::string_view name)
Definition
haio_registry.hpp:40
Haio::colorNamed
constexpr std::optional< Color > colorNamed(std::string_view name)
Definition
haio_registry.hpp:56
Haio::Blob::data
std::vector< uint8_t > data
Definition
haio_codec.hpp:127
Haio::Result
std::expected< T, Error > Result
Definition
haio_codec.hpp:32
Haio::lowerOf
consteval std::string_view lowerOf(std::meta::info enumerator)
Definition
haio_codec.hpp:269
Haio::formatName
constexpr std::string_view formatName(Format wanted)
Definition
haio_registry.hpp:13
Haio::Decode
Result< Image< Color::RGBA8888 > > Decode(const Blob &blob)
Definition
haio_registry.hpp:154
Haio::colorName
constexpr std::string_view colorName(Color wanted)
Definition
haio_registry.hpp:20
Haio::colorFromName
constexpr Color colorFromName(std::string_view name)
Definition
haio_registry.hpp:70
Haio::Format
Format
Definition
haio_formats.hpp:17
Haio::Format::RAW
@ RAW
Definition
haio_formats.hpp:19
Haio::Blob::color
Color color
Definition
haio_codec.hpp:124
Haio::ErrorCode::UnsupportedFormat
@ UnsupportedFormat
Definition
haio_codec.hpp:19
Haio::Bytes
std::span< const uint8_t > Bytes
Definition
haio_codec.hpp:14
Haio::Convert
Result< std::vector< uint8_t > > Convert(const Image< Color::RGBA8888 > &image, Color to)
Definition
haio_registry.hpp:197
Haio::Blob::format
Format format
Definition
haio_codec.hpp:123
Haio::Blob
Definition
haio_codec.hpp:122
Haio::Error
Definition
haio_codec.hpp:26
Haio::Found
Definition
haio_registry.hpp:76
Haio::Found::color
Color color
Definition
haio_registry.hpp:78
Haio::Found::format
Format format
Definition
haio_registry.hpp:77
Haio::Image
Definition
haio_codec.hpp:36
Haio::Image::data
std::vector< uint8_t > data
Definition
haio_codec.hpp:40
include
haio_registry.hpp
Generated by
1.18.0