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 sliceCount, 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,
343 PNG,
344 JPG,
345 BMP,
346 TGA,
347 WEBP,
348 QOI,
349 HDR,
350 EXR,
351};
352
355
357[[nodiscard]] std::vector<std::byte> convertImageDataToFile(std::span<const std::byte> imageData, ImageFormat format, uint16_t width, uint16_t height, FileFormat fileFormat = FileFormat::DEFAULT);
358
359[[nodiscard]] std::vector<std::byte> convertFileToImageData(std::span<const std::byte> fileData, ImageFormat& format, int& width, int& height, int& frameCount);
360
361enum class ResizeEdge {
362 // Matches stbir_edge
363 CLAMP = 0,
364 REFLECT,
365 WRAP,
366 ZERO,
367};
368
369enum class ResizeFilter {
370 // Matches stbir_filter
371 DEFAULT = 0,
372 BOX,
373 BILINEAR,
376 MITCHELL,
378
379 // User-defined
380 KAISER = 100,
382 NICE = 101,
383};
384
385enum class ResizeMethod {
386 NONE,
390};
391
393[[nodiscard]] uint16_t getResizedDim(uint16_t n, ResizeMethod method);
394
396void setResizedDims(uint16_t& width, ResizeMethod widthResize, uint16_t& height, ResizeMethod heightResize);
397
399[[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);
400
402[[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);
403
405[[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);
406
408[[nodiscard]] std::vector<std::byte> gammaCorrectImageData(std::span<const std::byte> imageData, ImageFormat format, uint16_t width, uint16_t height, float gamma);
409
411[[nodiscard]] std::vector<std::byte> invertGreenChannelForImageData(std::span<const std::byte> imageData, ImageFormat format, uint16_t width, uint16_t height);
412
417template<ImagePixel::PixelType P>
418[[nodiscard]] std::vector<std::byte> extractChannelFromImageData(std::span<const std::byte> imageData, auto P::*channel) {
419 using C = sourcepp::member_type_t<decltype(channel)>;
420 if (imageData.empty() || imageData.size() % sizeof(P) != 0) {
421 return {};
422 }
423
424 std::span pixels{reinterpret_cast<const P*>(imageData.data()), imageData.size() / sizeof(P)};
425
426 std::vector<std::byte> out(imageData.size() / sizeof(P) * sizeof(C));
427 BufferStream stream{out, false};
428 for (const auto& pixel : pixels) {
429 stream << pixel.*channel;
430 }
431 return out;
432}
433
434} // namespace ImageConversion
435
436} // 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 > 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 > 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, float quality=DEFAULT_COMPRESSED_QUALITY)
Converts several images from one format to another.
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