SourcePP
Several modern C++20 libraries for sanely parsing Valve's formats.
Loading...
Searching...
No Matches
ImageConversion.h
Go to the documentation of this file.
1#pragma once
2
3#include <array>
4#include <concepts>
5#include <cstddef>
6#include <span>
7#include <vector>
8
9#include <BufferStream.h>
10#include <sourcepp/Templates.h>
11
12#include "ImageFormats.h"
13
14namespace vtfpp {
15
16namespace ImagePixel {
17
18#define VTFPP_CHECK_SIZE(format) \
19 static_assert(sizeof(format) == ImageFormatDetails::bpp(ImageFormat::format) / 8)
20
21#define VTFPP_FORMAT_INHERITED(format, parent) \
22 struct format : parent { \
23 static constexpr auto FORMAT = ImageFormat::format; \
24 }; \
25 VTFPP_CHECK_SIZE(format)
26
27struct RGBA8888 {
28 static constexpr auto FORMAT = ImageFormat::RGBA8888;
29 uint8_t r;
30 uint8_t g;
31 uint8_t b;
32 uint8_t a;
33}; VTFPP_CHECK_SIZE(RGBA8888);
34
35struct ABGR8888 {
36 static constexpr auto FORMAT = ImageFormat::ABGR8888;
37 uint8_t a;
38 uint8_t b;
39 uint8_t g;
40 uint8_t r;
41}; VTFPP_CHECK_SIZE(ABGR8888);
42
43struct RGB888 {
44 static constexpr auto FORMAT = ImageFormat::RGB888;
45 uint8_t r;
46 uint8_t g;
47 uint8_t b;
49
51
52struct BGR888 {
53 static constexpr auto FORMAT = ImageFormat::BGR888;
54 uint8_t b;
55 uint8_t g;
56 uint8_t r;
58
60
61struct RGB565 {
62 static constexpr auto FORMAT = ImageFormat::RGB565;
63 uint16_t r : 5;
64 uint16_t g : 6;
65 uint16_t b : 5;
67
68struct I8 {
69 static constexpr auto FORMAT = ImageFormat::I8;
70 uint8_t i;
72
73struct IA88 {
74 static constexpr auto FORMAT = ImageFormat::IA88;
75 uint8_t i;
76 uint8_t a;
78
79struct P8 {
80 static constexpr auto FORMAT = ImageFormat::P8;
81 uint8_t p;
83
84struct A8 {
85 static constexpr auto FORMAT = ImageFormat::A8;
86 uint8_t a;
88
89struct ARGB8888 {
90 static constexpr auto FORMAT = ImageFormat::ARGB8888;
91 uint8_t a;
92 uint8_t r;
93 uint8_t g;
94 uint8_t b;
95}; VTFPP_CHECK_SIZE(ARGB8888);
96
97struct BGRA8888 {
98 static constexpr auto FORMAT = ImageFormat::BGRA8888;
99 uint8_t b;
100 uint8_t g;
101 uint8_t r;
102 uint8_t a;
103}; VTFPP_CHECK_SIZE(BGRA8888);
104
105struct BGRX8888 {
106 static constexpr auto FORMAT = ImageFormat::BGRX8888;
107 uint8_t b;
108 uint8_t g;
109 uint8_t r;
110 uint8_t x;
111}; VTFPP_CHECK_SIZE(BGRX8888);
112
113struct BGR565 {
114 static constexpr auto FORMAT = ImageFormat::BGR565;
115 uint16_t b : 5;
116 uint16_t g : 6;
117 uint16_t r : 5;
119
120struct BGRX5551 {
121 static constexpr auto FORMAT = ImageFormat::BGRX5551;
122 uint16_t b : 5;
123 uint16_t g : 5;
124 uint16_t r : 5;
125 uint16_t x : 1;
126}; VTFPP_CHECK_SIZE(BGRX5551);
127
128struct BGRA4444 {
129 static constexpr auto FORMAT = ImageFormat::BGRA4444;
130 uint16_t b : 4;
131 uint16_t g : 4;
132 uint16_t r : 4;
133 uint16_t a : 4;
134}; VTFPP_CHECK_SIZE(BGRA4444);
135
136struct BGRA5551 {
137 static constexpr auto FORMAT = ImageFormat::BGRA5551;
138 uint16_t b : 5;
139 uint16_t g : 5;
140 uint16_t r : 5;
141 uint16_t a : 1;
142}; VTFPP_CHECK_SIZE(BGRA5551);
143
144struct UV88 {
145 static constexpr auto FORMAT = ImageFormat::UV88;
146 uint8_t u;
147 uint8_t v;
149
150struct UVWQ8888 {
151 static constexpr auto FORMAT = ImageFormat::UVWQ8888;
152 uint8_t u;
153 uint8_t v;
154 uint8_t w;
155 uint8_t q;
156}; VTFPP_CHECK_SIZE(UVWQ8888);
157
159 static constexpr auto FORMAT = ImageFormat::RGBA16161616F;
160 half r;
161 half g;
162 half b;
163 half a;
164}; VTFPP_CHECK_SIZE(RGBA16161616F);
165
167 static constexpr auto FORMAT = ImageFormat::RGBA16161616;
168 uint16_t r;
169 uint16_t g;
170 uint16_t b;
171 uint16_t a;
172}; VTFPP_CHECK_SIZE(RGBA16161616);
173
174struct UVLX8888 {
175 static constexpr auto FORMAT = ImageFormat::UVLX8888;
176 uint8_t u;
177 uint8_t v;
178 uint8_t l;
179 uint8_t x;
180}; VTFPP_CHECK_SIZE(UVLX8888);
181
182struct R32F {
183 static constexpr auto FORMAT = ImageFormat::R32F;
184 float r;
186
188 static constexpr auto FORMAT = ImageFormat::R32F;
189 float r;
190 float g;
191 float b;
192}; VTFPP_CHECK_SIZE(RGB323232F);
193
195 static constexpr auto FORMAT = ImageFormat::RGBA32323232F;
196 float r;
197 float g;
198 float b;
199 float a;
200}; VTFPP_CHECK_SIZE(RGBA32323232F);
201
202struct RG1616F {
203 static constexpr auto FORMAT = ImageFormat::RG1616F;
204 half r;
205 half g;
207
208struct RG3232F {
209 static constexpr auto FORMAT = ImageFormat::RG3232F;
210 float r;
211 float g;
213
214struct RGBX8888 {
215 static constexpr auto FORMAT = ImageFormat::RGBX8888;
216 uint8_t r;
217 uint8_t g;
218 uint8_t b;
219 uint8_t x;
220}; VTFPP_CHECK_SIZE(RGBX8888);
221
223 static constexpr auto FORMAT = ImageFormat::RGBA1010102;
224 uint32_t r : 10;
225 uint32_t g : 10;
226 uint32_t b : 10;
227 uint32_t a : 2;
228}; VTFPP_CHECK_SIZE(RGBA1010102);
229
231 static constexpr auto FORMAT = ImageFormat::BGRA1010102;
232 uint32_t b : 10;
233 uint32_t g : 10;
234 uint32_t r : 10;
235 uint32_t a : 2;
236}; VTFPP_CHECK_SIZE(BGRA1010102);
237
238struct R16F {
239 static constexpr auto FORMAT = ImageFormat::R16F;
240 half r;
242
243struct R8 {
244 static constexpr auto FORMAT = ImageFormat::R8;
245 uint8_t r;
247
249
251
253
255
257
259
261
263
265
267
269
271
272#undef VTFPP_FORMAT_INHERITED
273#undef VTFPP_CHECK_SIZE
274
275template<typename T>
276concept PixelType =
277 std::same_as<T, RGBA8888> ||
278 std::same_as<T, ABGR8888> ||
279 std::same_as<T, RGB888> ||
280 std::same_as<T, BGR888> ||
281 std::same_as<T, RGB565> ||
282 std::same_as<T, I8> ||
283 std::same_as<T, IA88> ||
284 std::same_as<T, P8> ||
285 std::same_as<T, A8> ||
286 std::same_as<T, RGB888_BLUESCREEN> ||
287 std::same_as<T, BGR888_BLUESCREEN> ||
288 std::same_as<T, ARGB8888> ||
289 std::same_as<T, BGRA8888> ||
290 std::same_as<T, BGRX8888> ||
291 std::same_as<T, BGR565> ||
292 std::same_as<T, BGRX5551> ||
293 std::same_as<T, BGRA4444> ||
294 std::same_as<T, BGRA5551> ||
295 std::same_as<T, UV88> ||
296 std::same_as<T, UVWQ8888> ||
297 std::same_as<T, RGBA16161616F> ||
298 std::same_as<T, RGBA16161616> ||
299 std::same_as<T, UVLX8888> ||
300 std::same_as<T, R32F> ||
301 std::same_as<T, RGB323232F> ||
302 std::same_as<T, RGBA32323232F> ||
303 std::same_as<T, RG1616F> ||
304 std::same_as<T, RG3232F> ||
305 std::same_as<T, RGBX8888> ||
306 std::same_as<T, RGBA1010102> ||
307 std::same_as<T, BGRA1010102> ||
308 std::same_as<T, R16F> ||
309 std::same_as<T, CONSOLE_BGRX8888_LINEAR> ||
310 std::same_as<T, CONSOLE_RGBA8888_LINEAR> ||
311 std::same_as<T, CONSOLE_ABGR8888_LINEAR> ||
312 std::same_as<T, CONSOLE_ARGB8888_LINEAR> ||
313 std::same_as<T, CONSOLE_BGRA8888_LINEAR> ||
314 std::same_as<T, CONSOLE_RGB888_LINEAR> ||
315 std::same_as<T, CONSOLE_BGR888_LINEAR> ||
316 std::same_as<T, CONSOLE_BGRX5551_LINEAR> ||
317 std::same_as<T, CONSOLE_I8_LINEAR> ||
318 std::same_as<T, CONSOLE_RGBA16161616_LINEAR> ||
319 std::same_as<T, CONSOLE_BGRX8888_LE> ||
320 std::same_as<T, CONSOLE_BGRA8888_LE> ||
321 std::same_as<T, R8>;
322
323} // namespace ImagePixel
324
325namespace ImageConversion {
326
328[[nodiscard]] std::vector<std::byte> convertImageDataToFormat(std::span<const std::byte> imageData, ImageFormat oldFormat, ImageFormat newFormat, uint16_t width, uint16_t height);
329
331[[nodiscard]] std::vector<std::byte> convertSeveralImageDataToFormat(std::span<const std::byte> imageData, ImageFormat oldFormat, ImageFormat newFormat, uint8_t mipCount, uint16_t frameCount, uint8_t faceCount, uint16_t width, uint16_t height, uint16_t sliceCount);
332
337[[nodiscard]] std::array<std::vector<std::byte>, 6> convertHDRIToCubeMap(std::span<const std::byte> imageData, ImageFormat format, uint16_t width, uint16_t height, uint16_t resolution = 0, bool bilinear = true);
338
339enum class FileFormat {
340 DEFAULT,
341 PNG,
342 JPEG,
343 BMP,
344 TGA,
345 HDR,
346 EXR,
347};
348
351
353[[nodiscard]] std::vector<std::byte> convertImageDataToFile(std::span<const std::byte> imageData, ImageFormat format, uint16_t width, uint16_t height, FileFormat fileFormat = FileFormat::DEFAULT);
354
355[[nodiscard]] std::vector<std::byte> convertFileToImageData(std::span<const std::byte> fileData, ImageFormat& format, int& width, int& height, int& frameCount);
356
357enum class ResizeEdge {
358 // Matches stbir_edge
359 CLAMP = 0,
360 REFLECT,
361 WRAP,
362 ZERO,
363};
364
365enum class ResizeFilter {
366 // Matches stbir_filter
367 DEFAULT = 0,
368 BOX,
369 BILINEAR,
372 MITCHELL,
374
375 // User-defined
376 KAISER = 100,
377};
378
379enum class ResizeMethod {
380 NONE,
384};
385
387[[nodiscard]] uint16_t getResizedDim(uint16_t n, ResizeMethod method);
388
390void setResizedDims(uint16_t& width, ResizeMethod widthResize, uint16_t& height, ResizeMethod heightResize);
391
393[[nodiscard]] std::vector<std::byte> resizeImageData(std::span<const std::byte> imageData, ImageFormat format, uint16_t width, uint16_t newWidth, uint16_t height, uint16_t newHeight, bool srgb, ResizeFilter filter, ResizeEdge edge = ResizeEdge::CLAMP);
394
396[[nodiscard]] std::vector<std::byte> resizeImageDataStrict(std::span<const std::byte> imageData, ImageFormat format, uint16_t width, uint16_t newWidth, uint16_t& widthOut, ResizeMethod widthResize, uint16_t height, uint16_t newHeight, uint16_t& heightOut, ResizeMethod heightResize, bool srgb, ResizeFilter filter, ResizeEdge edge = ResizeEdge::CLAMP);
397
399[[nodiscard]] std::vector<std::byte> cropImageData(std::span<const std::byte> imageData, ImageFormat format, uint16_t width, uint16_t newWidth, uint16_t xOffset, uint16_t height, uint16_t newHeight, uint16_t yOffset);
400
405template<ImagePixel::PixelType P>
406[[nodiscard]] std::vector<std::byte> extractChannelFromImageData(std::span<const std::byte> imageData, auto P::*channel) {
407 using C = sourcepp::member_type_t<decltype(channel)>;
408 if (imageData.empty() || imageData.size() % sizeof(P) != 0) {
409 return {};
410 }
411
412 std::span pixels{reinterpret_cast<const P*>(imageData.data()), imageData.size() / sizeof(P)};
413
414 std::vector<std::byte> out(imageData.size() / sizeof(P) * sizeof(C));
415 BufferStream stream{out, false};
416 for (const auto& pixel : pixels) {
417 stream << pixel.*channel;
418 }
419 return out;
420}
421
426template<ImagePixel::PixelType P>
427bool applyChannelToImageData(std::span<std::byte> imageData, std::span<const std::byte> channelData, auto P::*channel) {
428 using C = sourcepp::member_type_t<decltype(channel)>;
429 if (imageData.empty() || imageData.size() % sizeof(P) != 0 || channelData.empty() || channelData.size() % sizeof(C) != 0 || imageData.size() / sizeof(P) != channelData.size() / sizeof(C)) {
430 return false;
431 }
432
433 std::span pixels{reinterpret_cast<P*>(imageData.data()), imageData.size() / sizeof(P)};
434 std::span values{reinterpret_cast<C*>(channelData.data()), channelData.size() / sizeof(C)};
435
436 for (int i = 0; i < pixels.size(); i++) {
437 pixels[i].*channel = values[i];
438 }
439 return true;
440}
441
442} // namespace ImageConversion
443
444} // namespace vtfpp
#define VTFPP_CHECK_SIZE(format)
#define VTFPP_FORMAT_INHERITED(format, parent)
typename member_type< T >::type member_type_t
Definition: Templates.h:21
std::vector< std::byte > convertFileToImageData(std::span< const std::byte > fileData, ImageFormat &format, int &width, int &height, int &frameCount)
std::vector< std::byte > convertImageDataToFile(std::span< const std::byte > imageData, ImageFormat format, uint16_t width, uint16_t height, FileFormat fileFormat=FileFormat::DEFAULT)
Converts image data to the given file format (PNG or EXR by default).
void setResizedDims(uint16_t &width, ResizeMethod widthResize, uint16_t &height, ResizeMethod heightResize)
Set the new image dimensions given a resize method.
std::array< std::vector< std::byte >, 6 > convertHDRIToCubeMap(std::span< const std::byte > imageData, ImageFormat format, uint16_t width, uint16_t height, uint16_t resolution=0, bool bilinear=true)
Converts an HDRI into a cubemap.
uint16_t getResizedDim(uint16_t n, ResizeMethod method)
Get the new image size given a resize method.
FileFormat getDefaultFileFormatForImageFormat(ImageFormat format)
PNG for integer formats, EXR for floating point formats.
std::vector< std::byte > extractChannelFromImageData(std::span< const std::byte > imageData, auto P::*channel)
Extracts a single channel from the given image data.
std::vector< std::byte > cropImageData(std::span< const std::byte > imageData, ImageFormat format, uint16_t width, uint16_t newWidth, uint16_t xOffset, uint16_t height, uint16_t newHeight, uint16_t yOffset)
Crops the given image to the new dimensions. If the image format is compressed it will be converted t...
std::vector< std::byte > convertSeveralImageDataToFormat(std::span< const std::byte > imageData, ImageFormat oldFormat, ImageFormat newFormat, uint8_t mipCount, uint16_t frameCount, uint8_t faceCount, uint16_t width, uint16_t height, uint16_t sliceCount)
Converts several images from one format to another.
std::vector< std::byte > resizeImageDataStrict(std::span< const std::byte > imageData, ImageFormat format, uint16_t width, uint16_t newWidth, uint16_t &widthOut, ResizeMethod widthResize, uint16_t height, uint16_t newHeight, uint16_t &heightOut, ResizeMethod heightResize, bool srgb, ResizeFilter filter, ResizeEdge edge=ResizeEdge::CLAMP)
Resize given image data to the new dimensions, where the new width and height are governed by the res...
std::vector< std::byte > convertImageDataToFormat(std::span< const std::byte > imageData, ImageFormat oldFormat, ImageFormat newFormat, uint16_t width, uint16_t height)
Converts an image from one format to another.
bool applyChannelToImageData(std::span< std::byte > imageData, std::span< const std::byte > channelData, auto P::*channel)
Applies a single channel to the given image data.
std::vector< std::byte > resizeImageData(std::span< const std::byte > imageData, ImageFormat format, uint16_t width, uint16_t newWidth, uint16_t height, uint16_t newHeight, bool srgb, ResizeFilter filter, ResizeEdge edge=ResizeEdge::CLAMP)
Resize given image data to the new dimensions.
ImageFormat
Definition: ImageFormats.h:7
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT
static constexpr auto FORMAT