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
327constexpr float DEFAULT_COMPRESSED_QUALITY = 0.105f;
328
330[[nodiscard]] std::vector<std::byte> convertImageDataToFormat(std::span<const std::byte> imageData, ImageFormat oldFormat, ImageFormat newFormat, uint16_t width, uint16_t height, float quality = DEFAULT_COMPRESSED_QUALITY);
331
333[[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 depth, float quality = DEFAULT_COMPRESSED_QUALITY);
334
339[[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);
340
341enum class FileFormat {
342 DEFAULT = 0,
343 PNG = 1,
344 JPG = 2,
345 BMP = 3,
346 TGA = 4,
347#ifdef VTFPP_SUPPORT_WEBP
348 WEBP = 5,
349#endif
350#ifdef VTFPP_SUPPORT_QOI
351 QOI = 6,
352#endif
353 HDR = 7,
354#ifdef VTFPP_SUPPORT_EXR
355 EXR = 8,
356#endif
357};
358
361
363[[nodiscard]] std::vector<std::byte> convertImageDataToFile(std::span<const std::byte> imageData, ImageFormat format, uint16_t width, uint16_t height, FileFormat fileFormat = FileFormat::DEFAULT);
364
365[[nodiscard]] std::vector<std::byte> convertFileToImageData(std::span<const std::byte> fileData, ImageFormat& format, int& width, int& height, int& frameCount);
366
367enum class ResizeEdge {
368 // Matches stbir_edge
369 CLAMP = 0,
370 REFLECT,
371 WRAP,
372 ZERO,
373};
374
375enum class ResizeFilter {
376 // Matches stbir_filter
377 DEFAULT = 0,
378 BOX,
379 BILINEAR,
382 MITCHELL,
384
385 // User-defined
386 KAISER = 100,
388 NICE = 101,
389};
390
391enum class ResizeMethod {
392 NONE,
396};
397
399[[nodiscard]] uint16_t getResizedDim(uint16_t n, ResizeMethod method);
400
402void setResizedDims(uint16_t& width, ResizeMethod widthResize, uint16_t& height, ResizeMethod heightResize);
403
405[[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);
406
408[[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);
409
411[[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);
412
414[[nodiscard]] std::vector<std::byte> gammaCorrectImageData(std::span<const std::byte> imageData, ImageFormat format, uint16_t width, uint16_t height, float gamma);
415
417[[nodiscard]] std::vector<std::byte> invertGreenChannelForImageData(std::span<const std::byte> imageData, ImageFormat format, uint16_t width, uint16_t height);
418
423template<ImagePixel::PixelType P>
424[[nodiscard]] std::vector<std::byte> extractChannelFromImageData(std::span<const std::byte> imageData, auto P::*channel) {
425 using C = sourcepp::member_type_t<decltype(channel)>;
426 if (imageData.empty() || imageData.size() % sizeof(P) != 0) {
427 return {};
428 }
429
430 std::span pixels{reinterpret_cast<const P*>(imageData.data()), imageData.size() / sizeof(P)};
431
432 std::vector<std::byte> out(imageData.size() / sizeof(P) * sizeof(C));
433 BufferStream stream{out, false};
434 for (const auto& pixel : pixels) {
435 stream << pixel.*channel;
436 }
437 return out;
438}
439
440} // namespace ImageConversion
441
442} // 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.
std::vector< std::byte > convertImageDataToFormat(std::span< const std::byte > imageData, ImageFormat oldFormat, ImageFormat newFormat, uint16_t width, uint16_t height, float quality=DEFAULT_COMPRESSED_QUALITY)
Converts an image from one format to another.
uint16_t getResizedDim(uint16_t n, ResizeMethod method)
Get the new image size given a resize method.
constexpr float DEFAULT_COMPRESSED_QUALITY
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 depth, float quality=DEFAULT_COMPRESSED_QUALITY)
Converts several images from one format to another.
std::vector< std::byte > gammaCorrectImageData(std::span< const std::byte > imageData, ImageFormat format, uint16_t width, uint16_t height, float gamma)
Perform gamma correction on the given image data. Will not perform gamma correction if the input imag...
@ NICE
Valve NICE filtering, equivalent to Lanczos-3.
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 > 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 > invertGreenChannelForImageData(std::span< const std::byte > imageData, ImageFormat format, uint16_t width, uint16_t height)
Invert the green channel. Meant for converting normal maps between OpenGL and DirectX formats.
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.
Definition: HOT.h:11
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