-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpngcomb.cc
130 lines (122 loc) · 3.9 KB
/
pngcomb.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <array>
#include <charconv>
#include <iostream>
#include <vector>
#include <boost/program_options.hpp>
#include <png++/png.hpp>
using ai2_t = std::array<int, 2>;
class PngInput {
public:
PngInput(const std::string& path, int x_shift=0, int y_shift=0) :
path_{path}, x_shift_{x_shift}, y_shift_{y_shift} {
image_.read(path);
std::cerr << path << " w="<<Width() << " h="<<Height() << '\n';
}
const png::rgb_pixel& GetPixel(int x, int y) const { return image_[y][x]; }
const png::rgb_pixel GetPixelShited(int x, int y) const {
return GetPixel(x - x_shift_, y - y_shift_);
}
size_t Width() const { return image_.get_width(); }
size_t Height() const { return image_.get_height(); }
ai2_t Shift() const { return ai2_t{x_shift_, y_shift_}; }
private:
const std::string path_;
const int x_shift_;
const int y_shift_;
png::image<png::rgb_pixel> image_;
};
static int GetImages(
std::vector<PngInput> &pngs,
const std::vector<std::string>& paths_xys) {
int rc = 0;
pngs.reserve(paths_xys.size());
for (const std::string& path_xy: paths_xys) {
std::string path{path_xy};
const char *cs = path_xy.data(), *cse = cs + path_xy.size();
int x_shift = 0, y_shift = 0;
auto w = path_xy.find('+');
if (w != std::string::npos) {
path = std::string(cs, w);
auto fc_rc = std::from_chars(cs + w + 1, cse, x_shift);
if (fc_rc.ec == std::errc()) {
fc_rc = std::from_chars(fc_rc.ptr + 1, cse, y_shift);
}
if ((rc == 0) && (fc_rc.ec != std::errc())) {
rc = 1;
std::cerr << "Bad input option in " << path_xy << '\n';
}
}
pngs.push_back(PngInput(path, x_shift, y_shift));
}
return rc;
}
static void MaxBy(int &v, int x) {
if (v < x) { v = x; }
}
template <typename T>
static void MinBy(T &v, T x) {
if (v > x) { v = x; }
}
static ai2_t GetOutputSize(const std::vector<PngInput>& inputs) {
int w_out = 0, h_out = 0;
for (const PngInput &i: inputs) {
const ai2_t shift = i.Shift();
MaxBy(w_out, i.Width() + shift[0]);
MaxBy(h_out, i.Height() + shift[1]);
}
std::cerr << "w_out="<<w_out << " h_out="<<h_out << '\n';
return ai2_t{w_out, h_out};
}
static int Combine(
png::image<png::rgb_pixel> &out,
const std::vector<PngInput>& inputs) {
int rc = 0;
const int w_out = out.get_width();
const int h_out = out.get_height();
for (int x = 0; x < w_out; ++x) {
for (int y = 0; y < h_out; ++y) {
png::rgb_pixel& pixel = out[y][x];
pixel.red = pixel.green = pixel.blue = 0xff;
for (const PngInput &i: inputs) {
const ai2_t shift = i.Shift();
if ((shift[0] <= x) && (x < i.Width() + shift[0]) &&
(shift[1] <= y) && (y < i.Height() + shift[1])) {
png::rgb_pixel ipixel = i.GetPixelShited(x, y);
MinBy(pixel.red, ipixel.red);
MinBy(pixel.green, ipixel.green);
MinBy(pixel.blue, ipixel.blue);
}
}
}
}
return rc;
}
int main(int argc, char **argv) {
namespace po = boost::program_options;
int rc = 0;
po::variables_map vm;
po::options_description desc("3333-server options");
desc.add_options()
("help", "produce help message")
("input,i",
po::value<std::vector<std::string>>()->multitoken()->required(),
"input PNG path with optional +<x>+<y>")
("output,o", po::value<std::string>()->required(), "output PNG path")
("debug", po::value<std::string>()->default_value("0"), "Debug flags")
;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
if (vm.count("help")) {
std::cout << desc << "\n";
} else {
std::vector<PngInput> in_pngs;
GetImages(in_pngs, vm["input"].as<std::vector<std::string>>());
ai2_t out_size = GetOutputSize(in_pngs);
png::image<png::rgb_pixel> png_out(out_size[0], out_size[1]);
rc = Combine(png_out, in_pngs);
if (rc == 0) {
png_out.write(vm["output"].as<std::string>());
}
}
return rc;
}