Porytiles
Loading...
Searching...
No Matches
png_indexed_image_saver.cpp
Go to the documentation of this file.
2
3#include <array>
4#include <filesystem>
5
6#include "fmt/format.h"
7#include "png++/png.hpp"
8
13
14namespace porytiles2 {
15
17 const Image<IndexPixel> &image, const std::filesystem::path &path, TilesPalMode mode) const
18{
19 using enum TilesPalMode;
20
21 const std::vector greyscale_pal = {
22 Rgba32{255, 255, 255, 255},
23 Rgba32{238, 238, 238, 255},
24 Rgba32{222, 222, 222, 255},
25 Rgba32{205, 205, 205, 255},
26 Rgba32{189, 189, 189, 255},
27 Rgba32{172, 172, 172, 255},
28 Rgba32{156, 156, 156, 255},
29 Rgba32{139, 139, 139, 255},
30 Rgba32{115, 115, 115, 255},
31 Rgba32{98, 98, 98, 255},
32 Rgba32{82, 82, 82, 255},
33 Rgba32{65, 65, 65, 255},
34 Rgba32{49, 49, 49, 255},
35 Rgba32{32, 32, 32, 255},
36 Rgba32{16, 16, 16, 255},
37 Rgba32{0, 0, 0, 255},
38 };
39
40 png::palette png_pal{0};
41 png::image<png::index_pixel> out{image.width(), image.height()};
42
43 // Bail if given path exists already and isn't a file (i.e. it's a directory)
44 if (exists(path) && !is_regular_file(path)) {
45 return FormattableError{fmt::format("{}: exists but is not a file", path.filename().c_str())};
46 }
47
48 // Determine which palette to use
49 std::vector<Rgba32> palette_to_use;
50 if (mode == true_color && image.palette().has_value()) {
51 palette_to_use = image.palette().value();
52 }
53 else {
54 // Use greyscale palette for greyscale mode OR when true_color mode but no image palette exists
55 palette_to_use = greyscale_pal;
56 }
57
58 // Set up PNG palette
59 for (const auto &color : palette_to_use) {
60 png_pal.emplace_back(color.red(), color.green(), color.blue());
61 }
62 out.set_palette(png_pal);
63
64 // Write data to PNG buffer
65 for (unsigned int pixel_index = 0; pixel_index < image.size(); pixel_index++) {
66 const auto row = pixel_index / image.width();
67 const auto col = pixel_index % image.width();
68 out[row][col] = image.at(pixel_index).index();
69 }
70
71 // Write PNG to filesystem
72 try {
73 out.write(path);
74 }
75 catch (const std::exception &e) {
76 return FormattableError{fmt::format("{}: save failed: {}", path.filename().c_str(), e.what())};
77 }
78
79 return {};
80}
81
82} // namespace porytiles2
A result type that maintains a chainable sequence of errors for debugging and error reporting.
General-purpose error implementation with formatted message support.
Definition error.hpp:117
A template for two-dimensional images with arbitrarily typed pixel values.
Definition image.hpp:24
std::size_t width() const
Gets the width of this image in pixels.
Definition image.hpp:108
const std::optional< std::vector< Rgba32 > > & palette() const
Definition image.hpp:133
PixelType at(std::size_t i) const
Fetches the pixel value at a given one-dimensional pixel index.
Definition image.hpp:45
std::size_t height() const
Gets the height of this image in pixels.
Definition image.hpp:118
std::size_t size() const
Gets the size of this image in pixels.
Definition image.hpp:128
virtual ChainableResult< void > save_to_file(const Image< IndexPixel > &image, const std::filesystem::path &path, TilesPalMode mode) const
Represents a 32-bit RGBA color.
Definition rgba32.hpp:21