aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/gerbolyze.hpp14
-rw-r--r--src/main.cpp10
-rw-r--r--src/svg_doc.cpp9
-rw-r--r--src/vec_core.cpp47
-rw-r--r--src/vec_core.h7
5 files changed, 81 insertions, 6 deletions
diff --git a/include/gerbolyze.hpp b/include/gerbolyze.hpp
index 01d089a..1d4f9bd 100644
--- a/include/gerbolyze.hpp
+++ b/include/gerbolyze.hpp
@@ -93,15 +93,27 @@ namespace gerbolyze {
class ImageVectorizer {
public:
+ virtual ~ImageVectorizer() {};
virtual void vectorize_image(cairo_t *cr, const pugi::xml_node &node, ClipperLib::Paths &clip_path, cairo_matrix_t &viewport_matrix, PolygonSink &sink, double min_feature_size_px) = 0;
};
ImageVectorizer *makeVectorizer(const std::string &name);
+ class VectorizerSelectorizer {
+ public:
+ VectorizerSelectorizer(const std::string default_vectorizer="dev-null", const std::string defs="");
+
+ ImageVectorizer *select(const pugi::xml_node &img);
+
+ private:
+ std::string m_default;
+ std::map<std::string, std::string> m_map;
+ };
+
class RenderSettings {
public:
double m_minimum_feature_size_mm = 0.1;
- ImageVectorizer *m_vec = nullptr;
+ VectorizerSelectorizer &m_vec_sel;
};
class SVGDocument {
diff --git a/src/main.cpp b/src/main.cpp
index 6484295..93b6e8f 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -43,7 +43,10 @@ int main(int argc, char **argv) {
"Comma-separated list of group IDs to export.",
1},
{"vectorizer", {"-b", "--vectorizer"},
- "Vectorizer to use for bitmap images. One of poisson-disc (default), hex-grid, square-grid, binary-contours.",
+ "Vectorizer to use for bitmap images. One of poisson-disc (default), hex-grid, square-grid, binary-contours, dev-null.",
+ 1},
+ {"vectorizer_map", {"--vectorizer-map"},
+ "Map from image element id to vectorizer. Overrides --vectorizer. Format: id1=vectorizer,id2=vectorizer,...",
1},
{"exclude_groups", {"-e", "--exclude-groups"},
"Comma-separated list of group IDs to exclude from export. Takes precedence over --only-groups.",
@@ -169,6 +172,7 @@ int main(int argc, char **argv) {
id_match(args["exclude_groups"], sel.exclude);
string vectorizer = args["vectorizer"] ? args["vectorizer"] : "poisson-disc";
+ /* Check argument */
ImageVectorizer *vec = makeVectorizer(vectorizer);
if (!vec) {
cerr << "Unknown vectorizer \"" << vectorizer << "\"." << endl;
@@ -176,10 +180,12 @@ int main(int argc, char **argv) {
fmt << usage.str() << argparser;
return EXIT_FAILURE;
}
+ delete vec;
+ VectorizerSelectorizer vec_sel(vectorizer, args["vectorizer_map"] ? args["vectorizer_map"] : "");
RenderSettings rset {
0.1,
- vec
+ vec_sel,
};
doc.render(rset, flattener ? *flattener : *sink, &sel);
diff --git a/src/svg_doc.cpp b/src/svg_doc.cpp
index 5b36f35..39c5724 100644
--- a/src/svg_doc.cpp
+++ b/src/svg_doc.cpp
@@ -173,11 +173,16 @@ void gerbolyze::SVGDocument::export_svg_group(const RenderSettings &rset, const
export_svg_path(rset, node, clip_path);
} else if (name == "image") {
- if (!rset.m_vec)
+ ImageVectorizer *vec = rset.m_vec_sel.select(node);
+ if (!vec) {
+ cerr << "Cannot resolve vectorizer for node \"" << node.attribute("id").value() << "\"" << endl;
continue;
+ }
double min_feature_size_px = mm_to_doc_units(rset.m_minimum_feature_size_mm);
- rset.m_vec->vectorize_image(cr, node, clip_path, viewport_matrix, *polygon_sink, min_feature_size_px);
+ vec->vectorize_image(cr, node, clip_path, viewport_matrix, *polygon_sink, min_feature_size_px);
+ delete vec;
+
} else if (name == "defs") {
/* ignore */
} else {
diff --git a/src/vec_core.cpp b/src/vec_core.cpp
index 6beab19..93c7a68 100644
--- a/src/vec_core.cpp
+++ b/src/vec_core.cpp
@@ -39,6 +39,8 @@ ImageVectorizer *gerbolyze::makeVectorizer(const std::string &name) {
return new VoronoiVectorizer(SQUAREGRID, /* relax */ false);
else if (name == "binary-contours")
return new OpenCVContoursVectorizer();
+ else if (name == "dev-null")
+ return new DevNullVectorizer();
return nullptr;
}
@@ -215,11 +217,15 @@ void gerbolyze::VoronoiVectorizer::vectorize_image(cairo_t *cr, const pugi::xml_
/* Scale intermediate image (step 1.2) to have <scale_featuresize_factor> pixels per min_feature_size. */
cv::Mat scaled(cv::Size{(int)round(px_w), (int)round(px_h)}, img.type());
cv::resize(img, scaled, scaled.size(), 0, 0);
+ cerr << "scaled " << img.cols << ", " << img.rows << " -> " << scaled.cols << ", " << scaled.rows << endl;
img.release();
/* Blur image with a kernel larger than our minimum feature size to avoid aliasing. */
cv::Mat blurred(scaled.size(), scaled.type());
int blur_size = (int)ceil(fmax(scaled.cols / width, scaled.rows / height) * center_distance);
+ if (blur_size%2 == 0)
+ blur_size += 1;
+ cerr << "blur size " << blur_size << endl;
cv::GaussianBlur(scaled, blurred, {blur_size, blur_size}, 0, 0);
scaled.release();
@@ -251,7 +257,11 @@ void gerbolyze::VoronoiVectorizer::vectorize_image(cairo_t *cr, const pugi::xml_
double pxd = (double)blurred.at<unsigned char>(
(int)round(center.y / height * blurred.rows),
(int)round(center.x / width * blurred.cols)) / 255.0;
- fill_factors[sites[i].index] = sqrt(pxd);
+ /* FIXME: This is a workaround for a memory corruption bug that happens with the square-grid setting. When using
+ * square-grid on a fairly small test image, sometimes sites[i].index will be out of bounds here.
+ */
+ if (sites[i].index < fill_factors.size())
+ fill_factors[sites[i].index] = sqrt(pxd);
}
/* Minimum gap between adjacent scaled site polygons. */
@@ -446,3 +456,38 @@ void gerbolyze::OpenCVContoursVectorizer::vectorize_image(cairo_t *cr, const pug
cairo_restore(cr);
}
+
+gerbolyze::VectorizerSelectorizer::VectorizerSelectorizer(const string default_vectorizer, const string defs)
+ : m_default(default_vectorizer) {
+ istringstream foo(defs);
+ string elem;
+ while (std::getline(foo, elem, ',')) {
+ size_t pos = elem.find_first_of("=");
+ if (pos == string::npos) {
+ cerr << "Error parsing vectorizer selection string at element \"" << elem << "\"" << endl;
+ continue;
+ }
+
+ const string parsed_id = elem.substr(0, pos);
+ const string mapping = elem.substr(pos+1);
+ m_map[parsed_id] = mapping;
+ }
+
+ cerr << "parsed " << m_map.size() << " vectorizers" << endl;
+ for (auto &elem : m_map) {
+ cerr << " " << elem.first << " -> " << elem.second << endl;
+ }
+}
+
+ImageVectorizer *gerbolyze::VectorizerSelectorizer::select(const pugi::xml_node &img) {
+ const string id = img.attribute("id").value();
+ cerr << "selecting vectorizer for image \"" << id << "\"" << endl;
+ if (m_map.contains(id)) {
+ cerr << " -> found" << endl;
+ return makeVectorizer(m_map[id]);
+ }
+
+ cerr << " -> default" << endl;
+ return makeVectorizer(m_default);
+}
+
diff --git a/src/vec_core.h b/src/vec_core.h
index 06099ab..adaa241 100644
--- a/src/vec_core.h
+++ b/src/vec_core.h
@@ -43,6 +43,13 @@ namespace gerbolyze {
virtual void vectorize_image(cairo_t *cr, const pugi::xml_node &node, ClipperLib::Paths &clip_path, cairo_matrix_t &viewport_matrix, PolygonSink &sink, double min_feature_size_px);
};
+ class DevNullVectorizer : public ImageVectorizer {
+ public:
+ DevNullVectorizer() {}
+
+ virtual void vectorize_image(cairo_t *, const pugi::xml_node &, ClipperLib::Paths &, cairo_matrix_t &, PolygonSink &, double) {}
+ };
+
void parse_img_meta(const pugi::xml_node &node, double &x, double &y, double &width, double &height);
std::string read_img_data(const pugi::xml_node &node);
void draw_bg_rect(cairo_t *cr, double width, double height, ClipperLib::Paths &clip_path, PolygonSink &sink, cairo_matrix_t &viewport_matrix);