From d406b1f1d08ef1c47a717d54e466709434d16684 Mon Sep 17 00:00:00 2001
From: jaseg <git@jaseg.de>
Date: Wed, 29 Sep 2021 00:24:30 +0200
Subject: Add rgba color support for newer resvg/usvg

---
 svg-flatten/src/out_svg.cpp   |  8 ++---
 svg-flatten/src/svg_color.cpp | 73 ++++++++++++++++++++++++++++++++-----------
 svg-flatten/src/svg_color.h   |  8 ++---
 svg-flatten/src/svg_doc.cpp   |  6 ++--
 4 files changed, 66 insertions(+), 29 deletions(-)

(limited to 'svg-flatten/src')

diff --git a/svg-flatten/src/out_svg.cpp b/svg-flatten/src/out_svg.cpp
index e778d6b..d94edc0 100644
--- a/svg-flatten/src/out_svg.cpp
+++ b/svg-flatten/src/out_svg.cpp
@@ -37,7 +37,7 @@ SimpleSVGOutput::SimpleSVGOutput(ostream &out, bool only_polys, int digits_frac,
 }
 
 void SimpleSVGOutput::header_impl(d2p origin, d2p size) {
-    cerr << "svg: header" << endl;
+    //cerr << "svg: header" << endl;
     m_offset[0] = origin[0];
     m_offset[1] = origin[1];
     m_out << "<svg width=\"" << size[0] << "mm\" height=\"" << size[1] << "mm\" viewBox=\"0 0 "
@@ -45,7 +45,7 @@ void SimpleSVGOutput::header_impl(d2p origin, d2p size) {
 }
 
 SimpleSVGOutput &SimpleSVGOutput::operator<<(GerberPolarityToken pol) {
-    cerr << "svg: got polarity " << pol << endl;
+    //cerr << "svg: got polarity " << pol << endl;
     if (pol == GRB_POL_DARK) {
         m_current_color = m_dark_color;
     } else if (pol == GRB_POL_CLEAR) {
@@ -58,7 +58,7 @@ SimpleSVGOutput &SimpleSVGOutput::operator<<(GerberPolarityToken pol) {
 }
 
 SimpleSVGOutput &SimpleSVGOutput::operator<<(const Polygon &poly) {
-    cerr << "svg: got poly of size " << poly.size() << endl;
+    //cerr << "svg: got poly of size " << poly.size() << endl;
     if (poly.size() < 3) {
         cerr << "Warning: " << poly.size() << "-element polygon passed to SimpleGerberOutput" << endl;
         return *this;
@@ -78,7 +78,7 @@ SimpleSVGOutput &SimpleSVGOutput::operator<<(const Polygon &poly) {
 }
 
 void SimpleSVGOutput::footer_impl() {
-    cerr << "svg: footer" << endl;
+    //cerr << "svg: footer" << endl;
     m_out << "</svg>" << endl;
 }
 
diff --git a/svg-flatten/src/svg_color.cpp b/svg-flatten/src/svg_color.cpp
index 62b11bf..ef2336d 100644
--- a/svg-flatten/src/svg_color.cpp
+++ b/svg-flatten/src/svg_color.cpp
@@ -40,10 +40,6 @@ enum gerber_color gerbolyze::svg_color_to_gerber(string color, string opacity, e
         assert(*endptr == '\0');
     }
 
-    if (alpha < 0.5f) {
-        return GRB_NONE;
-    }
-
     if (color.empty()) {
         return default_val;
     }
@@ -56,8 +52,17 @@ enum gerber_color gerbolyze::svg_color_to_gerber(string color, string opacity, e
         return GRB_PATTERN_FILL;
     }
 
-    if (color.length() == 7 && color[0] == '#') {
-        HSVColor hsv(color);
+    if ((color.length() == 7 && color[0] == '#') || color.rfind("rgba", 0) != string::npos) {
+        RGBAColor rgba(color);
+        HSVColor hsv(rgba);
+
+        if (alpha == 1.0)
+            alpha = rgba.a;
+
+        if (alpha < 0.5f) {
+            return GRB_NONE;
+        }
+
         if ((hsv.v >= 0.5) != rset.flip_color_interpretation) {
             return GRB_CLEAR;
         } else {
@@ -68,20 +73,52 @@ enum gerber_color gerbolyze::svg_color_to_gerber(string color, string opacity, e
     return GRB_DARK;
 }
 
-gerbolyze::RGBColor::RGBColor(string hex) {
-    assert(hex[0] == '#');
-    char *endptr = nullptr;
-    const char *c = hex.data();
-    int rgb = strtol(c + 1, &endptr, 16);
-    assert(endptr);
-    assert(endptr == c + 7);
-    assert(*endptr == '\0');
-    r = ((rgb >> 16) & 0xff) / 255.0f;
-    g = ((rgb >>  8) & 0xff) / 255.0f;
-    b = ((rgb >>  0) & 0xff) / 255.0f;
+gerbolyze::RGBAColor::RGBAColor(string spec) {
+    /* resvg/usvg v0.18.0 added support for rgba(...) color specs */
+    if (spec.rfind("rgba(", 0) != string::npos) {
+        /* "rgba(127, 127, 200, 255)" */
+        std::regex reg("rgba\\(([0-9]+),([0-9]+),([0-9]+),([0-9]+)\\)");
+        std::smatch match;
+
+        assert(std::regex_match(spec, match, reg));
+
+        int c[4];
+        for (size_t i=0; i<4; i++) {
+            assert (match.size() == 5);
+            char *endptr = nullptr;
+            string span = match[i+1].str();
+            c[i] = strtoul(span.data(), &endptr, 10);
+            assert(endptr && endptr != span.data());
+            assert(*endptr == '\0');
+        }
+
+        assert (0 <= c[0] && c[0] <= 255);
+        assert (0 <= c[1] && c[1] <= 255);
+        assert (0 <= c[2] && c[2] <= 255);
+        assert (0 <= c[3] && c[3] <= 255);
+
+        r = c[0]/255.0f;
+        g = c[1]/255.0f;
+        b = c[2]/255.0f;
+        a = c[3]/255.0f;
+
+    } else {
+        /* "#FF00E3" */
+        assert(spec[0] == '#');
+        char *endptr = nullptr;
+        const char *c = spec.data();
+        int rgb = strtol(c + 1, &endptr, 16);
+        assert(endptr);
+        assert(endptr == c + 7);
+        assert(*endptr == '\0');
+        r = ((rgb >> 16) & 0xff) / 255.0f;
+        g = ((rgb >>  8) & 0xff) / 255.0f;
+        b = ((rgb >>  0) & 0xff) / 255.0f;
+        a = 1.0;
+    }
 };
 
-gerbolyze::HSVColor::HSVColor(const RGBColor &color) {
+gerbolyze::HSVColor::HSVColor(const RGBAColor &color) {
     float xmax = fmax(color.r, fmax(color.g, color.b));
     float xmin = fmin(color.r, fmin(color.g, color.b));
     float c = xmax - xmin;
diff --git a/svg-flatten/src/svg_color.h b/svg-flatten/src/svg_color.h
index 752c2ed..d2cd75e 100644
--- a/svg-flatten/src/svg_color.h
+++ b/svg-flatten/src/svg_color.h
@@ -31,16 +31,16 @@ enum gerber_color {
     GRB_PATTERN_FILL,
 };
 
-class RGBColor {
+class RGBAColor {
 public:
-    float r, g, b;
-    RGBColor(std::string hex);
+    float r, g, b, a;
+    RGBAColor(std::string spec);
 };
 
 class HSVColor {
 public:
     float h, s, v;
-    HSVColor(const RGBColor &color);
+    HSVColor(const RGBAColor &color);
 };
 
 enum gerber_color svg_color_to_gerber(std::string color, std::string opacity, enum gerber_color default_val, const RenderSettings &rset);
diff --git a/svg-flatten/src/svg_doc.cpp b/svg-flatten/src/svg_doc.cpp
index a3186ec..6767b84 100644
--- a/svg-flatten/src/svg_doc.cpp
+++ b/svg-flatten/src/svg_doc.cpp
@@ -110,7 +110,7 @@ double gerbolyze::SVGDocument::doc_units_to_mm(double px) const {
 
 bool IDElementSelector::match(const pugi::xml_node &node, bool is_toplevel, bool parent_include) const {
     string id = node.attribute("id").value();
-    cerr << "match id=" << id << " toplevel=" << is_toplevel << " parent=" << parent_include << endl;
+    //cerr << "match id=" << id << " toplevel=" << is_toplevel << " parent=" << parent_include << endl;
     if (is_toplevel && layers) {
         bool layer_match = std::find(layers->begin(), layers->end(), id) != layers->end();
         if (!layer_match) {
@@ -124,7 +124,7 @@ bool IDElementSelector::match(const pugi::xml_node &node, bool is_toplevel, bool
 
     bool include_match = std::find(include.begin(), include.end(), id) != include.end();
     bool exclude_match = std::find(exclude.begin(), exclude.end(), id) != exclude.end();
-    cerr << "  excl=" << exclude_match << " incl=" << include_match << endl;
+    //cerr << "  excl=" << exclude_match << " incl=" << include_match << endl;
 
     if (is_toplevel) {
         if (!include.empty())
@@ -227,7 +227,7 @@ void gerbolyze::SVGDocument::export_svg_group(RenderContext &ctx, const pugi::xm
 void gerbolyze::SVGDocument::export_svg_path(RenderContext &ctx, const pugi::xml_node &node) {
     enum gerber_color fill_color = gerber_fill_color(node, ctx.settings());
     enum gerber_color stroke_color = gerber_stroke_color(node, ctx.settings());
-    cerr << "path: resolved colors, stroke=" << stroke_color << ", fill=" << fill_color << endl;
+    //cerr << "path: resolved colors, stroke=" << stroke_color << ", fill=" << fill_color << endl;
 
     double stroke_width = usvg_double_attr(node, "stroke-width", /* default */ 1.0);
     assert(stroke_width > 0.0);
-- 
cgit