UFO 1.0.0
An Efficient Probabilistic 3D Mapping Framework That Embraces the Unknown
Loading...
Searching...
No Matches
png.cpp
1
42// UFO
43#include <ufo/io/png.hpp>
44
45// STL
46#include <format>
47#include <memory>
48#include <print>
49#include <stdexcept>
50
51// PNG
52#include <spng.h>
53
54namespace ufo
55{
56namespace detail
57{
58bool readPNG(std::FILE* fp, void* image, std::size_t length, int fmt)
59{
60 std::unique_ptr<spng_ctx, decltype(&spng_ctx_free)> ctx{spng_ctx_new(0), spng_ctx_free};
61 if (!ctx) {
62 std::println(stderr, "[UFO | Read PNG] Failed to create PNG context");
63 return false;
64 }
65
66 /* Ignore and do not calculate chunk CRC's */
67 spng_set_crc_action(ctx.get(), SPNG_CRC_USE, SPNG_CRC_USE);
68
69 /* Set memory usage limits for storing standard and unknown chunks,
70 this is important when reading untrusted files! */
71 constexpr std::size_t limit = 64uz * 1024 * 1024;
72 spng_set_chunk_limits(ctx.get(), limit, limit);
73
74 /* Set source PNG */
75 spng_set_png_file(ctx.get(), fp);
76
77 spng_ihdr ihdr;
78 if (int const ret = spng_get_ihdr(ctx.get(), &ihdr); ret) {
79 std::println(stderr, "[UFO | Read PNG] Get PNG IHDR error: {}", spng_strerror(ret));
80 return false;
81 }
82
83 /* Calculate output image size */
84 std::size_t image_size{};
85 if (int const ret = spng_decoded_image_size(ctx.get(), fmt, &image_size); ret) {
86 std::println(stderr, "[UFO | Read PNG] Get PNG image size error: {}",
87 spng_strerror(ret));
88 return false;
89 }
90
91 if (image_size != length) {
92 std::println(stderr, "[UFO | Read PNG] Incorrect image size, expected {} was {}",
93 length, image_size);
94 return false;
95 }
96
97 int flags = 0;
98 if (SPNG_FMT_GA8 == fmt || SPNG_FMT_GA16 == fmt || SPNG_FMT_RGBA8 == fmt ||
99 SPNG_FMT_RGBA16 == fmt) {
100 flags |= SPNG_DECODE_TRNS;
101 }
102
103 /* Decode the image in one go */
104 if (int const ret = spng_decode_image(ctx.get(), image, image_size, fmt, flags); ret) {
105 std::println(stderr, "[UFO | Read PNG] Decode PNG image error: {}",
106 spng_strerror(ret));
107 return false;
108 }
109
110 return true;
111}
112
113bool writePNG(std::FILE* fp, void const* image, std::size_t length, std::uint32_t width,
114 std::uint32_t height, int color_type, int bit_depth)
115{
116 std::unique_ptr<spng_ctx, decltype(&spng_ctx_free)> ctx{spng_ctx_new(SPNG_CTX_ENCODER),
117 spng_ctx_free};
118 if (!ctx) {
119 std::println(stderr, "[UFO | Write PNG] Failed to create PNG context");
120 return false;
121 }
122
123 spng_set_png_file(ctx.get(), fp);
124
125 spng_ihdr ihdr{};
126 ihdr.width = width;
127 ihdr.height = height;
128 ihdr.bit_depth = bit_depth;
129 ihdr.color_type = color_type;
130
131 spng_set_ihdr(ctx.get(), &ihdr);
132
133 /* SPNG_FMT_PNG matches the format in ihdr; SPNG_ENCODE_FINALIZE writes the EOF marker
134 */
135 if (int const ret =
136 spng_encode_image(ctx.get(), image, length, SPNG_FMT_PNG, SPNG_ENCODE_FINALIZE);
137 ret) {
138 std::println(stderr, "[UFO | Write PNG] Encode PNG image error: {}",
139 spng_strerror(ret));
140 return false;
141 }
142
143 return true;
144}
145} // namespace detail
146
147ImageProperties imagePropertiesPNG(std::filesystem::path const& file)
148{
149 FileHandler fp(file, "rb");
150
151 if (!fp) {
152 throw std::runtime_error(std::format(
153 "[UFO | Image Properties PNG] Failed to open file: {}", file.string()));
154 }
155
156 std::unique_ptr<spng_ctx, decltype(&spng_ctx_free)> ctx{spng_ctx_new(0), spng_ctx_free};
157 if (!ctx) {
158 throw std::runtime_error("[UFO | Image Properties PNG] Failed to create PNG context");
159 }
160
161 /* Ignore and do not calculate chunk CRC's */
162 spng_set_crc_action(ctx.get(), SPNG_CRC_USE, SPNG_CRC_USE);
163
164 /* Set memory usage limits for storing standard and unknown chunks,
165 this is important when reading untrusted files! */
166 constexpr std::size_t limit = 64uz * 1024 * 1024;
167 spng_set_chunk_limits(ctx.get(), limit, limit);
168
169 /* Set source PNG */
170 spng_set_png_file(ctx.get(), fp.get());
171
172 spng_ihdr ihdr;
173 if (int const ret = spng_get_ihdr(ctx.get(), &ihdr); ret) {
174 throw std::runtime_error(std::format(
175 "[UFO | Image Properties PNG] Get PNG IHDR error: {}", spng_strerror(ret)));
176 }
177
178 return {
179 .width = ihdr.width,
180 .height = ihdr.height,
181 .bit_depth = ihdr.bit_depth,
182 .alpha = SPNG_COLOR_TYPE_TRUECOLOR_ALPHA == ihdr.color_type ||
183 SPNG_COLOR_TYPE_GRAYSCALE_ALPHA == ihdr.color_type,
184 .grayscale = SPNG_COLOR_TYPE_GRAYSCALE == ihdr.color_type ||
185 SPNG_COLOR_TYPE_GRAYSCALE_ALPHA == ihdr.color_type,
186 };
187}
188} // namespace ufo
RAII wrapper around a C std::FILE* handle.
std::FILE * get() const noexcept
Returns the underlying FILE*.
All vision-related classes and functions.
Definition cloud.hpp:49
constexpr T length(Vec< Dim, T > const &v) noexcept
Computes the Euclidean length (magnitude) of a vector.
Definition vec.hpp:1101
ImageProperties imagePropertiesPNG(std::filesystem::path const &file)
Reads the metadata of a PNG file without decoding pixel data.
Definition png.cpp:147
Metadata describing the pixel layout of an image file.