-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathimageExtractor.cpp
More file actions
165 lines (149 loc) · 5.72 KB
/
imageExtractor.cpp
File metadata and controls
165 lines (149 loc) · 5.72 KB
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#include "image/image.h"
#include <iostream>
#include <limits>
#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
#include <cmath>
#include <iomanip>
#include <optional>
using namespace std::string_literals;
template<typename T>
void die(T msg) {
std::cerr << msg << '\n';
std::exit(1);
}
struct CommandLine {
std::vector<std::string> parameters;
std::unordered_map<std::string, std::string> flags;
std::string flagOrDie(std::string const & flagname) {
auto it = flags.find(flagname);
if( it == flags.end() ) die("missing " + flagname + " flag");
return it->second;
}
std::string flagOrDefault(std::string const & flagname, std::string const & defValue) {
auto it = flags.find(flagname);
return it == flags.end() ? defValue : it->second;
}
std::optional<std::string> flagOptional(std::string const & flagname) {
auto it = flags.find(flagname);
if( it == flags.end() ) return std::nullopt;
return std::optional(it->second);
}
};
struct Point {
int x,y;
static Point parse(std::string const & str) {
auto iss = std::istringstream(str);
auto result = Point();
iss >> result.x;
if( iss.get() != 'x' ) die("missing x when parsing point");
iss >> result.y;
if( result.x < 0 || result.y < 0 ) die("invalid negative values in point");
return result;
}
};
struct FilenameBuilder {
std::string filename;
std::string extension;
int digits;
explicit FilenameBuilder(std::string const & fileAndExt, int maxNum) {
auto iPt = fileAndExt.rfind('.');
if( iPt == std::string::npos ) die("missing extension in the filename");
filename = fileAndExt.substr(0,iPt);
extension = fileAndExt.substr(iPt);
digits = int(std::log10(maxNum)) + 1;
}
std::string build(int num) {
std::ostringstream oss;
oss << filename << std::setfill('0') << std::setw(digits) << num << extension;
return oss.str();
}
};
CommandLine parseCommandLine(int argc, char **argv);
img::Color parseColor(std::string const & colorStr);
// TODO add a flag to save all images in a single one
int main(int argc, char * argv[]) {
auto commandLine = parseCommandLine(argc, argv);
if( commandLine.parameters.size() < 2 ) die("no source and target files specified");
auto targetImages = std::stoi(commandLine.flagOrDefault("target_images","1"));
if( targetImages < 1 ) die("invalid target_images flag");
auto targetImageNameBuilder = FilenameBuilder(commandLine.parameters[1],targetImages);
auto startingPoint = Point::parse(commandLine.flagOrDefault("starting_point","0x0"));
auto tgtImgSize = Point::parse(commandLine.flagOrDie("target_image_size"));
auto endingPoint = Point{
tgtImgSize.x + startingPoint.x,
tgtImgSize.y + startingPoint.y,
};
auto offsetX = std::stoi(commandLine.flagOrDefault("offset_x","0"));
offsetX += tgtImgSize.x;
auto offsetY = std::stoi(commandLine.flagOrDefault("offset_y","0"));
offsetY += tgtImgSize.y;
auto imagesPerLine = std::stoi(commandLine.flagOrDefault("images_per_line","-1"));
if( imagesPerLine < -1 ) die("invalid images_per_line flag");
if( imagesPerLine == -1 ) imagesPerLine = std::numeric_limits<int>::max();
img::Color transpColor,newTranspColor;
auto optTranspColor = commandLine.flagOptional("transparent_color");
if( optTranspColor ) {
transpColor = parseColor(*optTranspColor);
newTranspColor = transpColor;
newTranspColor.a = 0;
}
auto sourceImage = img::Image(commandLine.parameters[0]);
auto topLeft = startingPoint;
auto bottomRight = endingPoint;
for( int i = 1; i <= targetImages; ++i ) {
auto targetImage = sourceImage.clip(topLeft.x,topLeft.y,bottomRight.x,bottomRight.y);
if( optTranspColor ) {
targetImage = std::move(targetImage.to32bpp().replace(transpColor,newTranspColor));
}
auto targetFilename = targetImageNameBuilder.build(i);
std::cout << "writing " << targetFilename << std::endl;
targetImage.save(targetFilename);
if( i % imagesPerLine == 0 ) {
topLeft.x = startingPoint.x;
topLeft.y += offsetY;
bottomRight.x = endingPoint.x;
bottomRight.y += offsetY;
} else {
topLeft.x += offsetX;
bottomRight.x += offsetX;
}
}
}
CommandLine parseCommandLine(int argc, char **argv) {
auto result = CommandLine();
auto flagname = std::string();
for (int i = 1; i < argc; ++i) {
auto current = std::string(argv[i]);
if( flagname.empty() ) {
if (current[0] == '-') {
flagname = std::move(current);
flagname = flagname.substr(1);
} else {
result.parameters.push_back(std::move(current));
}
} else {
result.flags.insert_or_assign(std::move(flagname),std::move(current));
flagname.clear(); // it is moved away, but...
}
}
return result;
}
img::Color parseColor(std::string const & colorStr) {
auto iss = std::istringstream(colorStr);
auto result = img::Color();
auto extractInt = [&iss](auto & var) -> std::istringstream & { int intVar; iss >> intVar; var = intVar; return iss; };
extractInt(result.r);
if( iss.get() != ',' ) die("missing a comma when parsing color");
extractInt(result.g);
if( iss.get() != ',' ) die("missing a comma when parsing color");
if( ! extractInt(result.b) ) die("invalid color values");
if( iss.get() == ',' ) {
if( ! extractInt(result.a) ) die("invalid color values");
} else {
result.a = 255;
}
return result;
}