Haio 0.2.X
Homebrew Asset IO/CDN
Loading...
Searching...
No Matches
decode.cpp
Go to the documentation of this file.
1#include <haio_codec.hpp>
2
3// the modules are compiled once, in backend/codecs/wuffs.cpp. NONMONOLITHIC keeps
4// the declarations without them, and IMPLEMENTATION is what completes the types:
5// wuffs leaves them opaque otherwise, and a decoder on the stack needs the size
6#define WUFFS_NONMONOLITHIC
7#define WUFFS_IMPLEMENTATION
8#define WUFFS_CONFIG__MODULES
9#include <wuffs-v0.4.c>
10
11namespace {
12
13/**
14 * the pixel format wuffs is asked for, and how many bytes that costs per pixel.
15 *
16 * wuffs offers both channel orders and its names say which is which, so the only way
17 * to get this wrong is to pick the wrong one: asking for BGR where Color::RGB888 is
18 * meant hands back a picture with red and blue swapped, and every stage after it
19 * copies three bytes faithfully without ever noticing.
20 */
21struct Target { uint32_t pixelFormat; size_t stride; };
22
23constexpr Target targetFor(Haio::Color colour) {
24 return colour == Haio::Color::RGB888
25 ? Target{WUFFS_BASE__PIXEL_FORMAT__RGB, 3}
26 : Target{WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL, 4};
27}
28
29}
30
31namespace Haio::Codecs {
32
33namespace {
34
35/** one decode for every colour png can hand back; the caller says which it wants */
36template <Color P>
37Result<Image<P>> decodePng(const Blob& blob) {
38 wuffs_png__decoder dec;
39 wuffs_base__status st = wuffs_png__decoder__initialize(&dec, sizeof dec, WUFFS_VERSION, WUFFS_INITIALIZE__DEFAULT_OPTIONS);
40
41 if (!wuffs_base__status__is_ok(&st)) {
42 HAIO_FAIL(InvalidInput, "wuffs is not ok");
43 }
44
45 wuffs_base__io_buffer src = wuffs_base__ptr_u8__reader((uint8_t*)blob.data.data(), blob.data.size(), true);
46
47 wuffs_base__image_config cfg;
48 memset(&cfg, 0, sizeof cfg);
49 st = wuffs_base__image_decoder__decode_image_config(wuffs_png__decoder__upcast_as__wuffs_base__image_decoder(&dec), &cfg, &src);
50 if (!wuffs_base__status__is_ok(&st)) {
51 HAIO_FAIL(InvalidInput, "invalid png config");
52 }
53
54 uint32_t w = wuffs_base__pixel_config__width(&cfg.pixcfg);
55 uint32_t h = wuffs_base__pixel_config__height(&cfg.pixcfg);
56 if (!w || !h) {
57 HAIO_FAIL(InvalidInput, "invalid png dimensions");
58 }
59
60 constexpr auto target = targetFor(P);
61 wuffs_base__pixel_config__set(&cfg.pixcfg, target.pixelFormat, WUFFS_BASE__PIXEL_SUBSAMPLING__NONE, w, h);
62
63 std::vector<uint8_t> buffer(static_cast<size_t>(w) * static_cast<size_t>(h) * target.stride);
64
65 wuffs_base__pixel_buffer pb;
66 st = wuffs_base__pixel_buffer__set_from_slice(&pb, &cfg.pixcfg, wuffs_base__make_slice_u8(buffer.data(), buffer.size()));
67 if (!wuffs_base__status__is_ok(&st)) {
68 HAIO_FAIL(InvalidInput, "failed to create png pixel buffer");
69 }
70
71 wuffs_base__range_ii_u64 wb = wuffs_base__image_decoder__workbuf_len(wuffs_png__decoder__upcast_as__wuffs_base__image_decoder(&dec));
72 std::vector<uint8_t> work(wb.max_incl ? static_cast<size_t>(wb.max_incl) : 0);
73
74 st = wuffs_base__image_decoder__decode_frame(
75 wuffs_png__decoder__upcast_as__wuffs_base__image_decoder(&dec),
76 &pb,
77 &src,
78 WUFFS_BASE__PIXEL_BLEND__SRC,
79 wuffs_base__make_slice_u8(work.data(), work.size()),
80 nullptr
81 );
82 if (!wuffs_base__status__is_ok(&st)) {
83 HAIO_FAIL(InvalidInput, "failed to decode png frame");
84 }
85
86
87 return Image<P>{static_cast<int>(w), static_cast<int>(h), std::move(buffer)};
88}
89
90}
91
92/**
93 * @addtogroup decode
94 * @{
95 */
96template <>
98 return decodePng<Color::RGBA8888>(blob);
99}
100/** @} */
101
102/**
103 * @addtogroup decode
104 * @{
105 */
106/** a truecolour png without alpha: kept at three bytes instead of inflated to four */
107template <>
109 return decodePng<Color::RGB888>(blob);
110}
111/** @} */
112
113}
Result< Image< Color::RGB888 > > Decode< Format::PNG, Color::RGB888 >(const Blob &blob)
Definition decode.cpp:108
Result< Image< Color::RGBA8888 > > Decode< Format::PNG, Color::RGBA8888 >(const Blob &blob)
Definition decode.cpp:97
#define HAIO_FAIL(why, message)
std::expected< T, Error > Result