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 */
16struct Target { uint32_t pixelFormat; size_t stride; };
17
18constexpr Target targetFor(Haio::Color colour) {
19 return colour == Haio::Color::RGB888
20 ? Target{WUFFS_BASE__PIXEL_FORMAT__RGB, 3}
21 : Target{WUFFS_BASE__PIXEL_FORMAT__RGBA_NONPREMUL, 4};
22}
23
24}
25
26namespace Haio::Codecs {
27
28namespace {
29
30template <Color P>
31Result<Image<P>> decodeGif(const Blob& blob) {
32 wuffs_gif__decoder dec;
33
34 wuffs_base__status st =
35 wuffs_gif__decoder__initialize(
36 &dec,
37 sizeof dec,
38 WUFFS_VERSION,
39 WUFFS_INITIALIZE__DEFAULT_OPTIONS
40 );
41
42 if (!wuffs_base__status__is_ok(&st)) {
43 HAIO_FAIL(InvalidInput, "wuffs is not ok");
44 }
45
46 wuffs_base__io_buffer src =
47 wuffs_base__ptr_u8__reader(
48 (uint8_t*)blob.data.data(),
49 blob.data.size(),
50 true
51 );
52
53 wuffs_base__image_config cfg;
54 memset(&cfg, 0, sizeof cfg);
55
56 st = wuffs_base__image_decoder__decode_image_config(
57 wuffs_gif__decoder__upcast_as__wuffs_base__image_decoder(&dec),
58 &cfg,
59 &src
60 );
61
62 if (!wuffs_base__status__is_ok(&st)) {
63 HAIO_FAIL(InvalidInput, "invalid gif config");
64 }
65
66 uint32_t w = wuffs_base__pixel_config__width(&cfg.pixcfg);
67 uint32_t h = wuffs_base__pixel_config__height(&cfg.pixcfg);
68
69 if (!w || !h) {
70 HAIO_FAIL(InvalidInput, "invalid gif dimensions");
71 }
72
73 constexpr auto target = targetFor(P);
74
75 wuffs_base__pixel_config__set(
76 &cfg.pixcfg,
77 target.pixelFormat,
78 WUFFS_BASE__PIXEL_SUBSAMPLING__NONE,
79 w,
80 h
81 );
82
83 std::vector<uint8_t> buffer(
84 static_cast<size_t>(w) *
85 static_cast<size_t>(h) *
86 target.stride
87 );
88
89 wuffs_base__pixel_buffer pb;
90
91 st = wuffs_base__pixel_buffer__set_from_slice(
92 &pb,
93 &cfg.pixcfg,
94 wuffs_base__make_slice_u8(
95 buffer.data(),
96 buffer.size()
97 )
98 );
99
100 if (!wuffs_base__status__is_ok(&st)) {
101 HAIO_FAIL(InvalidInput, "failed to create gif pixel buffer");
102 }
103
104 wuffs_base__range_ii_u64 wb =
105 wuffs_base__image_decoder__workbuf_len(
106 wuffs_gif__decoder__upcast_as__wuffs_base__image_decoder(&dec)
107 );
108
109 std::vector<uint8_t> work(
110 wb.max_incl ? static_cast<size_t>(wb.max_incl) : 0
111 );
112
113 // One decode_frame call gives us the first GIF frame.
114 st = wuffs_base__image_decoder__decode_frame(
115 wuffs_gif__decoder__upcast_as__wuffs_base__image_decoder(&dec),
116 &pb,
117 &src,
118 WUFFS_BASE__PIXEL_BLEND__SRC,
119 wuffs_base__make_slice_u8(
120 work.data(),
121 work.size()
122 ),
123 nullptr
124 );
125
126 if (!wuffs_base__status__is_ok(&st)) {
127 HAIO_FAIL(InvalidInput, "failed to decode gif frame");
128 }
129
130 return Image<P>{
131 static_cast<int>(w),
132 static_cast<int>(h),
133 std::move(buffer)
134 };
135}
136
137}
138
139/**
140 * @addtogroup decode
141 * @{
142 */
143template <>
145 return decodeGif<Color::RGBA8888>(blob);
146}
147/** @} */
148
149/**
150 * @addtogroup decode
151 * @{
152 */
153template <>
155 return decodeGif<Color::RGB888>(blob);
156}
157/** @} */
158
159}
Result< Image< Color::RGB888 > > Decode< Format::GIF, Color::RGB888 >(const Blob &blob)
Definition decode.cpp:154
Result< Image< Color::RGBA8888 > > Decode< Format::GIF, Color::RGBA8888 >(const Blob &blob)
Definition decode.cpp:144
#define HAIO_FAIL(why, message)
std::expected< T, Error > Result