|
Haio 0.2.X
Homebrew Asset IO/CDN
|
Namespaces | |
| namespace | Cdn |
| namespace | Cli |
| namespace | Codecs |
| namespace | Detail |
| namespace | Pipe |
| namespace | String |
| namespace | Tokens |
| namespace | Util |
Classes | |
| struct | Blob |
| struct | ColorAlias |
| struct | Error |
| struct | Found |
| struct | Image |
| struct | Image< Color::PALETTE > |
| class | IWindow |
| class | Pipeline |
| struct | Rect |
| struct | Size |
| struct | Token |
| class | WindowsWindow |
Concepts | |
| concept | Addressable |
| concept | Maskable |
Typedefs | |
| using | Bytes = std::span<const uint8_t> |
| template<typename T> | |
| using | Result = std::expected<T, Error> |
Enumerations | |
| enum class | ErrorCode { Internal , InvalidInput , UnsupportedFormat , NotFound , Io , Upstream , Timeout } |
| enum class | Format { RAW , PNG , PPM , JPEG , KTX , KTX2 , DDS , PVR , ZCIS , ANSI , UTF8 , ROM , TGA , GIF } |
| enum class | Color { RGBA8888 , RGB888 , RGB565 , RGB555 , RGBA5551 , BGR888 , BGRA8888 , GRAY8 , ETC1 , YUV420 , PALETTE , CHR_NES } |
| enum class | Dither { Nearest , Bayer , Floyd , Strict } |
| enum class | Limit { Sort , Spread } |
| enum class | TokenKind { Source , DecodeAuto , Decode , Crop , Resize , Radius , Palette , Encode } |
Functions | |
| std::unique_ptr< IWindow > | CreateWindow (const char *title, int width, int height) |
| constexpr size_t | strideOf (Color color) |
| constexpr int | alphaOffsetOf (Color color) |
| consteval std::string_view | lowerOf (std::meta::info enumerator) |
| Result< size_t > | sizeOf (Color color, Size size) |
| Result< std::vector< uint32_t > > | paletteNamed (std::string_view spec, size_t wanted) |
| std::span< const std::string_view > | paletteNames () |
| std::optional< Dither > | ditherNamed (std::string_view name) |
| Result< Image< Color::PALETTE > > | toPalette (const Image< Color::RGBA8888 > &image, std::vector< uint32_t > entries, Dither how) |
| std::optional< Limit > | limitNamed (std::string_view name) |
| Result< std::vector< uint32_t > > | limitPalette (const Image< Color::RGBA8888 > &image, std::vector< uint32_t > entries, size_t most, Limit how) |
| Result< void > | operator>> (const Result< Blob > &result, std::ostream &out) |
| Format | formatFromExtension (std::string_view path) |
| Format | formatFromContentType (std::string_view contentType) |
| std::string_view | extensionFor (Format format) |
| std::string_view | contentTypeFor (Format format) |
| Result< Blob > | runPipeline (Blob input, const Pipeline &pipeline, std::optional< std::chrono::steady_clock::time_point > deadline=std::nullopt) |
| std::vector< Token > | parseQueryTokens (std::string_view query) |
| std::unordered_map< std::string, std::string > | parseQueryMap (std::string_view query) |
| constexpr std::string_view | formatName (Format wanted) |
| constexpr std::string_view | colorName (Color wanted) |
| constexpr Format | formatFromName (std::string_view name) |
| constexpr std::optional< Color > | colorNamed (std::string_view name) |
| constexpr Color | colorFromName (std::string_view name) |
| Found | Detect (Bytes data) |
| constexpr bool | detectable (Format format, Color color) |
| constexpr bool | encodable (Format format, Color color) |
| constexpr std::optional< Color > | encodeColorFor (Format to) |
| Result< Image< Color::RGBA8888 > > | Decode (const Blob &blob) |
| Result< std::vector< uint8_t > > | Convert (const Image< Color::RGBA8888 > &image, Color to) |
| Result< Blob > | Encode (Image< Color::RGBA8888 > image, Format to, std::optional< Color > as=std::nullopt) |
| Result< Blob > | Encode (Image< Color::PALETTE > image, Format to) |
| template<Color P> | |
| Image< P > | withPixels (const Image< P > &from, int width, int height, std::vector< uint8_t > pixels) |
| template<Color P> requires Addressable<P> | |
| Image< P > | cropImage (const Image< P > &image, Rect rect) |
| template<Color P> requires Addressable<P> | |
| Image< P > | resizeImage (const Image< P > &image, Size size) |
| template<Color P> requires Maskable<P> | |
| Image< P > | roundImageCorners (const Image< P > &image, int radius) |
Variables | |
| constexpr ColorAlias | colorAliases [] |
geometry on addressable pixels. the colour no longer has to be rgba8888: the only thing these ever needed from it was how wide a pixel is, which PixelStride answers, so a crop on rgb565 stops going through a conversion it never used.
| struct Haio::Blob |
bytes of a file. it has a container and the colour it was found to hold
Definition at line 122 of file haio_codec.hpp.
| Class Members | ||
|---|---|---|
| Color | color = Color::RGBA8888 | |
| string | contentType = "application/octet-stream" | |
| vector< uint8_t > | data | |
| Format | format = Format::RAW | |
| string | path | |
| struct Haio::ColorAlias |
the other names these layouts go by.
ffmpeg's -pix_fmt is where most people learned to name a pixel layout on a command line, so what they already type for it is accepted beside the enumerator's own name. the list sits next to the enum rather than inside the lookup that reads it, because the command line grammar prints it too, and a list written in two places is a list that drifts.
Definition at line 167 of file haio_formats.hpp.
| Class Members | ||
|---|---|---|
| Color | color | |
| string_view | spelling | |
| struct Haio::Error |
Definition at line 26 of file haio_codec.hpp.
| Class Members | ||
|---|---|---|
| ErrorCode | code = ErrorCode::Internal | |
| string | message | |
| struct Haio::Rect |
Definition at line 5 of file haio_object.hpp.
| Class Members | ||
|---|---|---|
| int | height = 0 | |
| int | width = 0 | |
| int | x = 0 | |
| int | y = 0 | |
| struct Haio::Size |
Definition at line 12 of file haio_object.hpp.
| Class Members | ||
|---|---|---|
| int | height = 0 | |
| int | width = 0 | |
| struct Haio::Token |
Definition at line 28 of file haio_pipeline.hpp.

| Class Members | ||
|---|---|---|
| string | bucket | |
| optional< Color > | color |
Encode only: which colour to store inside the container, when somebody named one. nothing named is not the same as rgba8888: it means the container picks, which for most of them is the only colour they write anyway. |
| Dither | dither = Dither::Nearest | |
| Format | format = Format::RAW | |
| TokenKind | kind = TokenKind::DecodeAuto | |
| size_t | limit = 0 | |
| Limit | limitHow = Limit::Spread | |
| string | palette |
Palette only: which colours, how to fit into them, and how many to keep |
| string | path | |
| int | percent = 0 |
Resize only: a share of the incoming picture, when the size was written as one |
| int | radius = 0 | |
| Rect | rect | |
| Size | size | |
| using Haio::Bytes = std::span<const uint8_t> |
Definition at line 14 of file haio_codec.hpp.
| using Haio::Result = std::expected<T, Error> |
Definition at line 32 of file haio_codec.hpp.
|
strong |
how the pixels are laid out. these never appear as a file on their own: ETC1 and RGB565 are what a gpu container carries, the rest are what codecs hand around.
| Enumerator | |
|---|---|
| RGBA8888 | |
| RGB888 | |
| RGB565 | |
| RGB555 | five bits a channel packed into two bytes, little endian, with the top bit spare: 0RRRRRGGGGGBBBBB. it is what a sixteen bit tga holds, and the spare bit is why the same two bytes are a different colour once somebody declares it to be alpha. |
| RGBA5551 | the same two bytes with the alpha at the other end: RRRRRGGGGGBBBBBA. the name reads from the top bit down, which is the order the bits sit in the sixteen bit word once it is read little endian. one bit of alpha is a yes or a no, so converting to it rounds: half opaque and up survives, the rest goes clear. |
| BGR888 | blue first, which is how every windows era container stores a pixel. a tga, a dds and a bmp all write their bytes this way round, so the swap belongs in one colour rather than inside each of their decoders. |
| BGRA8888 | |
| GRAY8 | |
| ETC1 | |
| YUV420 | |
| PALETTE | an index per pixel plus the colours it indexes, which is why this is the one colour whose Image carries something besides pixels. |
| CHR_NES | how a console keeps its indices, which is not one per byte. nes chr is two bits a pixel, in eight by eight tiles, with the two bits of a pixel living in separate planes eight bytes apart. that is a layout and not a container, the same way ETC1 is, so it is a colour: a .chr file is Format::RAW holding this, and converting to PALETTE is what unpacks it. |
Definition at line 106 of file haio_formats.hpp.
|
strong |
how a colour that is not in the palette becomes one that is.
there is no default on purpose. every one of these changes the picture in a way somebody has to want: nearest flattens a gradient into bands, the dithers trade that for a pattern that is wrong at every single pixel, and strict refuses a picture that was not already in the palette. choosing for the caller would mean choosing what their art looks like.
Definition at line 44 of file haio_palette.hpp.
|
strong |
| Enumerator | |
|---|---|
| Internal | |
| InvalidInput | |
| UnsupportedFormat | |
| NotFound | |
| Io | |
| Upstream | |
| Timeout | |
Definition at line 16 of file haio_codec.hpp.
|
strong |
what a file is: the container that holds pixels. RAW means no container at all, just the bytes of a colour format, which is why it needs its size supplied.
the @mime and @ext tags are read by scripts/gen_codecs.cpp, which builds the lookups both ways from them. the first one is what haio writes, the rest are only accepted. this is what a c++26 enum annotation will carry once the compiler parses them, and until then a tag keeps them on the enumerator instead of in a table somewhere else.
Definition at line 17 of file haio_formats.hpp.
|
strong |
which colours to keep when a palette has more than was asked for.
taking the first N is never right: a master palette is ordered by how the hardware addresses it, so the first sixteen of the nes are sixteen dark blues. counting which colours a picture would use is better, but counting alone has a bias of its own, and the two answers differ enough to be worth choosing between.
Definition at line 71 of file haio_palette.hpp.
|
strong |
| Enumerator | |
|---|---|
| Source | |
| DecodeAuto | |
| Decode | |
| Crop | |
| Resize | |
| Radius | |
| Palette | |
| Encode | |
Definition at line 17 of file haio_pipeline.hpp.
|
constexpr |
which byte of a pixel holds its alpha, or a negative when the colour has none. the two eight bit colours answer the same, because where the alpha sits is all a masking loop ever wanted to know and neither of them moved it. written as a rule so that the day another arrives, rgba4444 in a ktx or a palette that keeps a transparent entry, it is one line here rather than a second copy of the loop.
Definition at line 78 of file haio_codec.hpp.

|
constexpr |
the same question where an unknown name is not worth stopping for
Definition at line 70 of file haio_registry.hpp.

|
constexpr |
|
constexpr |
the colour somebody typed, or nothing when no colour answers to that name.
the enumerator names come first and then colorAliases, which is every other name the same layouts go by. borrowing ffmpeg's option without its vocabulary would be borrowing the half that does not help.
Definition at line 56 of file haio_registry.hpp.

| std::string_view Haio::contentTypeFor | ( | Format | format | ) |
the first mime type an enumerator names is the one haio sends
Definition at line 62 of file format.cpp.

|
inline |
the same picture in another colour, named at runtime.
it hands back bytes rather than an image because at runtime there is no Image
to hand back: the colour is a value here, and the type it would pick is a compile time thing. the callers that want one already know which they want and say so through Codecs::Convert.
Definition at line 197 of file haio_registry.hpp.

| std::unique_ptr< IWindow > Haio::CreateWindow | ( | const char * | title, |
| int | width, | ||
| int | height ) |
|
inline |
the runtime way in: reads the bytes, routes to the pair that matched, and brings the result to rgba8888 so the caller has one type to hold.
Definition at line 154 of file haio_registry.hpp.

asks every declared pair, so "which payload is inside" needs no separate reader
Definition at line 84 of file haio_registry.hpp.

| std::optional< Dither > Haio::ditherNamed | ( | std::string_view | name | ) |
the spelling used on the command line, or nothing when it is not one of them
Definition at line 56 of file quantise.cpp.

|
inline |
the indexed way out, for the containers that store a palette rather than expanding it. there is no conversion into it here on purpose: haio does not pick colours for anybody, so the picture arrives already fitted to a palette or not at all.
Definition at line 274 of file haio_registry.hpp.

|
inline |
the runtime way out. rgba8888 goes in because that is what the runtime decode hands back; the colour stored inside is the one asked for, or the one the container calls its own when nobody asked.
naming it is what -pix_fmt does, and it is the only way to say "a ktx2 holding etc1" or "a tga holding bgr888" from a command line: the pair was always there in Codecs::Encode, with nothing but this bridge between it and a string.
Definition at line 229 of file haio_registry.hpp.

the colour a container is written in when nobody names one: the one it declares as its own, and failing that the first it can write at all.
before this there was only the second half, so the colour a file came out in was whichever one happened to be declared earliest in the enum. that is fine while a container writes one colour and arbitrary the moment it writes six.
Definition at line 128 of file haio_registry.hpp.

| std::string_view Haio::extensionFor | ( | Format | format | ) |
the first extension an enumerator names is the one haio writes
Definition at line 54 of file format.cpp.

| Format Haio::formatFromContentType | ( | std::string_view | contentType | ) |
| Format Haio::formatFromExtension | ( | std::string_view | path | ) |
a file name only ever names a container, never the colour inside it. the extension is not the enumerator name: .jpg is the usual spelling of jpeg, and the netpbm family answers to four.
Definition at line 33 of file format.cpp.

|
constexpr |
|
constexpr |
| std::optional< Limit > Haio::limitNamed | ( | std::string_view | name | ) |
"sort" or "spread", or nothing when it is neither
Definition at line 64 of file quantise.cpp.

| Result< std::vector< uint32_t > > Haio::limitPalette | ( | const Image< Color::RGBA8888 > & | image, |
| std::vector< uint32_t > | entries, | ||
| size_t | most, | ||
| Limit | how ) |
|
consteval |
the enumerator is PNG, the name people type is png
Definition at line 269 of file haio_codec.hpp.

the sugar: input >> pipeline >> output, with the Result surviving the chain
Definition at line 103 of file haio_pipe.hpp.

| Result< std::vector< uint32_t > > Haio::paletteNamed | ( | std::string_view | spec, |
| size_t | wanted ) |
the palettes haio knows by name, and the way to ask for part of one.
a name on its own is the whole palette, and a colon takes a slice of one:
cga every colour it has cga:2 the second bank, where a bank is as wide as the picture needs cga:1..3 those colours, counted from one cga:1,4,7 the same, spelled out cga:1..3,7 and the two together
a colon rather than brackets so that a shell leaves it alone: "<" and ">" are redirections, and a palette nobody can type without quoting is a palette nobody types.
the bank form is why the picture has to be known before the palette is: a two bit image wants four colours, so its second bank is 5 to 8, while a three colour one has 4 to 6 there. saying it as a bank rather than a list is what lets the same spelling follow a picture that changes depth.
a colon rather than brackets, because a shell eats "<" and ">" as redirections and would need the whole thing quoted to reach here at all.
a bare number on its own is a bank; anything else spells out which colours.
the two cannot be told apart by looking at the number, so they are told apart by shape: "tic80:2" is the second bank of whatever the picture needs, while "tic80:2..4" and "tic80:2,5" are colours, counted from one. a range is there because asking for the first three of a palette should not mean writing them all out.
Definition at line 91 of file known.cpp.

| std::span< const std::string_view > Haio::paletteNames | ( | ) |
| std::unordered_map< std::string, std::string > Haio::parseQueryMap | ( | std::string_view | query | ) |
| std::vector< Token > Haio::parseQueryTokens | ( | std::string_view | query | ) |
a url cannot carry a percent sign: "%" opens an escape, so "?resize=30%" is a broken request rather than a small picture. "30pct" says the same thing and survives, and both spellings are read here so a query and a command line can be written the same way.
the colour inside the container, spelled the way ffmpeg spells it.
it can arrive without a format, and that is a request rather than a mistake: "?pix_fmt=rgb565" with nothing to wrap it is raw pixels in that colour, which is what a caller loading a texture straight into a gpu is asking for.
Definition at line 100 of file pipeline.cpp.

| Image< P > Haio::resizeImage | ( | const Image< P > & | image, |
| Size | size ) |
nearest neighbour: one side may be left at zero and follows the other
Definition at line 54 of file haio_transform.hpp.

| Image< P > Haio::roundImageCorners | ( | const Image< P > & | image, |
| int | radius ) |
clears the alpha outside a rounded corner, so this one asks for more than the other two: a colour with no alpha has no way to say "not here", and asking for square corners back would be a worse answer than refusing to compile.
Definition at line 84 of file haio_transform.hpp.

| Result< Blob > Haio::runPipeline | ( | Blob | input, |
| const Pipeline & | pipeline, | ||
| std::optional< std::chrono::steady_clock::time_point > | deadline = std::nullopt ) |
a deadline of none lets it run as long as it takes.
it is checked between stages rather than inside them, so the bound is really "one more stage after the clock runs out". that is enough for what it defends against: a query naming a thousand operations is stopped after the first one or two, and a single stage is already bounded by max_size.
a conversion described at runtime, which is what a url query builds. it decodes once, applies whatever transforms were asked for, and encodes at the end.
the picture as indices, kept beside the full colour one from the moment a palette is applied.
quantising and then expanding back loses nothing about the picture and everything about how it is stored, and a container that keeps a palette wants the second thing. the two travel together rather than the pipeline switching over, because every transform downstream is written against full colour and only some of them mean anything to a page of indices.
quantise, keep the indices, and expand back to full colour.
the picture afterwards holds only the palette's colours, which is the point, and it stays rgba8888 so that everything downstream keeps working. the indices are kept as well rather than thrown away, because a container that stores a palette is the one place where they are not simply a longer way of saying the same picture.
no container asked for, so the answer is the pixels themselves.
a colour without a container is still worth doing: "-pix_fmt rgb565 raw:out.bin" is a texture in the layout it will be uploaded in, and it is the same thing ffmpeg writes when it is given a pixel format and no muxer.
a picture that was fitted to a palette goes out as indices wherever the container keeps them, which is the whole reason the indices were kept. asking for any other colour is honoured: somebody who says "-palete cga -pix_fmt bgr888" wants sixteen colours stored the long way, and that is a real thing to want when the reader on the other end has no palette support.
Definition at line 15 of file convert.cpp.

how many bytes one image of this colour and size takes. block formats round up to whole blocks, so this is not always width times height times something.
sixteen bytes for every eight by eight tile, which works out to two bits a pixel. the sides have to be whole tiles: a chr file has no way to say that the last row is short, so an odd size would be read past the end.
three planes: a full size luma and two half size chroma. the halves are why the dimensions have to be even, and refusing an odd one here is better than rounding it and handing back a picture a line short.
Definition at line 6 of file sizes.cpp.

|
constexpr |
how wide one pixel is, or zero when the colour has no such number: etc1 packs four by four blocks and yuv420 splits into planes, so neither can be measured a pixel at a time. sizeOf reads this too, so the widths are written down once.
Definition at line 48 of file haio_codec.hpp.

| Result< Image< Color::PALETTE > > Haio::toPalette | ( | const Image< Color::RGBA8888 > & | image, |
| std::vector< uint32_t > | entries, | ||
| Dither | how ) |
fits a true colour picture into a palette.
the palette is given rather than derived: haio does not pick colours for anybody, it puts a picture into the colours it was handed.
Definition at line 146 of file quantise.cpp.

| Image< P > Haio::withPixels | ( | const Image< P > & | from, |
| int | width, | ||
| int | height, | ||
| std::vector< uint8_t > | pixels ) |
a transformed picture keeps everything about the original except its pixels.
building a fresh Image would drop whatever else the colour carries, which for a palette is the palette: a cropped picture would come back as indices into nothing.
Definition at line 22 of file haio_transform.hpp.

|
inlineconstexpr |
Definition at line 172 of file haio_formats.hpp.