aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjaseg <git@jaseg.de>2021-01-29 21:58:42 +0100
committerjaseg <git@jaseg.de>2021-01-29 21:58:42 +0100
commita34efc058a18021143b75e30efdfd8dd0e72df10 (patch)
tree4198c33da5b4e95f192eb1a965e60a920fb8c6ed
parent6d1a7750c5fa0d78c7fe35a7b7bff8934b86089d (diff)
downloadgerbolyze-a34efc058a18021143b75e30efdfd8dd0e72df10.tar.gz
gerbolyze-a34efc058a18021143b75e30efdfd8dd0e72df10.tar.bz2
gerbolyze-a34efc058a18021143b75e30efdfd8dd0e72df10.zip
Add direct image export
-rw-r--r--.gitmodules3
-rw-r--r--Makefile3
-rw-r--r--src/main.cpp159
-rw-r--r--src/vec_core.cpp2
m---------upstream/subprocess.h0
5 files changed, 156 insertions, 11 deletions
diff --git a/.gitmodules b/.gitmodules
index 36615a6..e42d3c4 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -13,3 +13,6 @@
[submodule "upstream/CavalierContours"]
path = upstream/CavalierContours
url = https://github.com/jbuckmccready/CavalierContours
+[submodule "upstream/subprocess.h"]
+ path = upstream/subprocess.h
+ url = https://github.com/sheredom/subprocess.h
diff --git a/Makefile b/Makefile
index ed71204..a188e87 100644
--- a/Makefile
+++ b/Makefile
@@ -26,9 +26,10 @@ POISSON_INCLUDES ?= -Iupstream/poisson-disk-sampling/thinks/poisson_disk_sampli
BASE64_INCLUDES ?= -Iupstream/cpp-base64
ARGAGG_INCLUDES ?= -Iupstream/argagg/include/argagg
CAVC_INCLUDES ?= -Iupstream/CavalierContours/include/cavc/
+SUBPROCESS_INCLUDES ?= -Iupstream/subprocess.h
SOURCES += $(CLIPPER_SOURCES)
-INCLUDES := -Iinclude -Isrc $(CLIPPER_INCLUDES) $(VORONOI_INCLUDES) $(POISSON_INCLUDES) $(BASE64_INCLUDES) $(ARGAGG_INCLUDES) $(CAVC_INCLUDES)
+INCLUDES := -Iinclude -Isrc $(CLIPPER_INCLUDES) $(VORONOI_INCLUDES) $(POISSON_INCLUDES) $(BASE64_INCLUDES) $(ARGAGG_INCLUDES) $(CAVC_INCLUDES) $(SUBPROCESS_INCLUDES)
CXXFLAGS := -std=c++2a -g -Wall -Wextra -O0
CXXFLAGS += $(shell $(PKG_CONFIG) --cflags pangocairo pugixml opencv4)
diff --git a/src/main.cpp b/src/main.cpp
index 93b6e8f..931ab74 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,12 +1,16 @@
#include <cstdlib>
+#include <cstdio>
+#include <filesystem>
#include <iostream>
#include <fstream>
#include <algorithm>
#include <string>
#include <argagg.hpp>
+#include <subprocess.h>
#include <gerbolyze.hpp>
#include "vec_core.h"
+#include <base64.h>
using argagg::parser_results;
using argagg::parser;
@@ -33,6 +37,9 @@ int main(int argc, char **argv) {
{"svg_dark_color", {"--dark-color"},
"SVG color to use for \"dark\" areas (default: black)",
1},
+ {"min_feature_size", {"-d", "--trace-space"},
+ "Minimum feature size of elements in vectorized graphics (trace/space) in mm. Default: 0.1mm.",
+ 1},
{"no_header", {"--no-header"},
"Do not export output format header/footer, only export the primitives themselves",
0},
@@ -48,6 +55,18 @@ int main(int argc, char **argv) {
{"vectorizer_map", {"--vectorizer-map"},
"Map from image element id to vectorizer. Overrides --vectorizer. Format: id1=vectorizer,id2=vectorizer,...",
1},
+ {"force_svg", {"--force-svg"},
+ "Force SVG input irrespective of file name",
+ 0},
+ {"force_png", {"--force-png"},
+ "Force bitmap graphics input irrespective of file name",
+ 0},
+ {"size", {"-s", "--size"},
+ "Bitmap mode only: Physical size of output image in mm. Format: 12.34x56.78",
+ 1},
+ {"skip_usvg", {"--no-usvg"},
+ "Do not preprocess input using usvg (do not use unless you know *exactly* what you're doing)",
+ 0},
{"exclude_groups", {"-e", "--exclude-groups"},
"Comma-separated list of group IDs to exclude from export. Takes precedence over --only-groups.",
1},
@@ -119,13 +138,6 @@ int main(int argc, char **argv) {
out_f = &out_f_file;
}
-
- SVGDocument doc;
- if (!doc.load(*in_f)) {
- cerr << "Error loading input file \"" << in_f_name << "\", exiting." << endl;
- return EXIT_FAILURE;
- }
-
bool only_polys = args["no_header"];
int precision = 6;
@@ -134,7 +146,7 @@ int main(int argc, char **argv) {
}
string fmt = args["ofmt"] ? args["ofmt"] : "gerber";
- transform(fmt.begin(), fmt.end(), fmt.begin(), [](unsigned char c){ return std::tolower(c); });
+ transform(fmt.begin(), fmt.end(), fmt.begin(), [](unsigned char c){ return std::tolower(c); }); /* c++ yeah */
PolygonSink *sink = nullptr;
PolygonSink *flattener = nullptr;
@@ -182,13 +194,142 @@ int main(int argc, char **argv) {
}
delete vec;
+ /*
+ double min_feature_size_px = mm_to_doc_units(rset.m_minimum_feature_size_mm);
+ vec->vectorize_image(cr, node, clip_path, viewport_matrix, *polygon_sink, min_feature_size_px);
+ delete vec;
+ */
+ double min_feature_size = 0.1; /* mm */
+ if (args["min_feature_size"]) {
+ min_feature_size = args["min_feature_size"].as<double>();
+ }
+
+ string ending = "";
+ auto idx = in_f_name.rfind(".");
+ if (idx != string::npos) {
+ ending = in_f_name.substr(idx);
+ transform(ending.begin(), ending.end(), ending.begin(), [](unsigned char c){ return std::tolower(c); }); /* c++ yeah */
+ }
+
+ filesystem::path barf = { filesystem::temp_directory_path() /= (std::tmpnam(nullptr) + string(".svg")) };
+ filesystem::path frob = { filesystem::temp_directory_path() /= (std::tmpnam(nullptr) + string(".svg")) };
+
+ bool is_svg = args["force_svg"] || (ending == ".svg" && !args["force_png"]);
+ if (!is_svg) {
+ cerr << "writing bitmap into svg" << endl;
+ if (!args["size"]) {
+ cerr << "Error: --size must be given when using bitmap input." << endl;
+ argagg::fmt_ostream fmt(cerr);
+ fmt << usage.str() << argparser;
+ return EXIT_FAILURE;
+ }
+
+ string sz = args["size"].as<string>();
+ auto pos = sz.find_first_of("x*,");
+ if (pos == string::npos) {
+ cerr << "Error: --size must be of form 12.34x56.78" << endl;
+ argagg::fmt_ostream fmt(cerr);
+ fmt << usage.str() << argparser;
+ return EXIT_FAILURE;
+ }
+
+ string x_str = sz.substr(0, pos);
+ string y_str = sz.substr(pos+1);
+
+ double width = std::strtod(x_str.c_str(), nullptr);
+ double height = std::strtod(y_str.c_str(), nullptr);
+
+ if (width < 1 || height < 1) {
+ cerr << "Error: --size must be of form 12.34x56.78 and values must be positive floating-point numbers in mm" << endl;
+ argagg::fmt_ostream fmt(cerr);
+ fmt << usage.str() << argparser;
+ return EXIT_FAILURE;
+ }
+
+ ofstream svg(barf.c_str());
+
+ svg << "<svg width=\"" << width << "mm\" height=\"" << height << "mm\" viewBox=\"0 0 "
+ << width << " " << height << "\" "
+ << "xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">" << endl;
+
+ svg << "<image width=\"" << width << "\" height=\"" << height << "\" x=\"0\" y=\"0\" xlink:href=\"data:image/png;base64,";
+
+ /* c++ has the best hacks */
+ std::ostringstream sstr;
+ sstr << in_f->rdbuf();
+ string le_data = sstr.str();
+
+ svg << base64_encode(le_data);
+ svg << "\"/>" << endl;
+
+ svg << "</svg>" << endl;
+ svg.close();
+
+ } else { /* svg file */
+ cerr << "copying svg input into temp svg" << endl;
+
+ /* c++ has the best hacks */
+ std::ostringstream sstr;
+ sstr << in_f->rdbuf();
+
+ ofstream tmp_out(barf.c_str());
+ tmp_out << sstr.str();
+ tmp_out.close();
+
+ }
+
+ if (args["skip_usvg"]) {
+ cerr << "skippint usvg" << endl;
+ frob = barf;
+
+ } else {
+ cerr << "calling usvg on " << barf << " and " << frob << endl;
+ const char *command_line[] = {"usvg", barf.c_str(), frob.c_str(), NULL};
+ struct subprocess_s subprocess;
+ int rc = subprocess_create(command_line, subprocess_option_inherit_environment, &subprocess);
+ if (rc) {
+ cerr << "Error calling usvg!" << endl;
+ return EXIT_FAILURE;
+ }
+
+ int usvg_rc = 0;
+ rc = subprocess_join(&subprocess, &usvg_rc);
+ if (rc) {
+ cerr << "Error calling usvg!" << endl;
+ return EXIT_FAILURE;
+ }
+ if (usvg_rc) {
+ cerr << "usvg returned an error code: " << usvg_rc << endl;
+ return EXIT_FAILURE;
+ }
+
+ rc = subprocess_destroy(&subprocess);
+ if (rc) {
+ cerr << "Error calling usvg!" << endl;
+ return EXIT_FAILURE;
+ }
+ }
+
VectorizerSelectorizer vec_sel(vectorizer, args["vectorizer_map"] ? args["vectorizer_map"] : "");
RenderSettings rset {
- 0.1,
+ min_feature_size,
vec_sel,
};
+ SVGDocument doc;
+ cerr << "Loading temporary file " << frob << endl;
+ ifstream load_f(frob);
+ if (!doc.load(load_f)) {
+ cerr << "Error loading input file \"" << in_f_name << "\", exiting." << endl;
+ return EXIT_FAILURE;
+ }
+
doc.render(rset, flattener ? *flattener : *sink, &sel);
+ if (!is_svg) {
+ remove(frob.c_str());
+ remove(barf.c_str());
+ }
return EXIT_SUCCESS;
}
+
diff --git a/src/vec_core.cpp b/src/vec_core.cpp
index 93c7a68..81a2a96 100644
--- a/src/vec_core.cpp
+++ b/src/vec_core.cpp
@@ -36,7 +36,7 @@ ImageVectorizer *gerbolyze::makeVectorizer(const std::string &name) {
else if (name == "hex-grid")
return new VoronoiVectorizer(HEXGRID, /* relax */ false);
else if (name == "square-grid")
- return new VoronoiVectorizer(SQUAREGRID, /* relax */ false);
+ return new VoronoiVectorizer(SQUAREGRID, /* relax */ true);
else if (name == "binary-contours")
return new OpenCVContoursVectorizer();
else if (name == "dev-null")
diff --git a/upstream/subprocess.h b/upstream/subprocess.h
new file mode 160000
+Subproject d4d5c01ba9ffbb19fd552f8f3664691b44ff0ea