current_element().attributes.class_ = class_;
}
+void SVGAnalyzer::set_fill(std::string_view fill) {
+ current_element().attributes.fill = fill;
+}
+
void SVGAnalyzer::set_height(double height) {
current_element().attributes.height = height;
}
void on_enter_element_text() override;
void on_enter_element_title() override;
void on_exit_element() override;
+ void set_fill(std::string_view fill) override;
void set_height(double height) override;
void set_id(std::string_view id) override;
void set_class(std::string_view) override;
virtual void on_enter_element_title() = 0;
virtual void on_exit_element() = 0;
virtual void set_class(std::string_view) = 0;
+ virtual void set_fill(std::string_view fill) = 0;
virtual void set_height(double height) = 0;
virtual void set_id(std::string_view id) = 0;
virtual void set_text(std::string_view text) = 0;
return out;
}
+// convert a valid color specification to the flavor that Graphviz uses
+static std::string to_graphviz_color(const std::string &color) {
+ if (color == "rgb(0,0,0)") {
+ return "black";
+ } else if (color == "rgb(255,255,255)") {
+ return "white";
+ } else if (color.starts_with("rgb")) {
+ const auto comma1 = color.find_first_of(",");
+ const auto r = std::stoi(color.substr(4, comma1 - 1));
+ const auto comma2 = color.find_first_of(",", comma1 + 1);
+ const auto g = std::stoi(color.substr(comma1 + 1, comma2 - 1));
+ const auto close_par = color.find_first_of(")", comma2 + 1);
+ const auto b = std::stoi(color.substr(comma2 + 1, close_par - 1));
+ return fmt::format("#{:02x}{:02x}{:02x}", r, g, b);
+ } else {
+ return color;
+ }
+}
+
void SVG::SVGElement::append_attribute(std::string &output,
const std::string &attribute) const {
if (attribute.empty()) {
output += attribute;
}
+std::string SVG::SVGElement::fill_attribute_to_string() const {
+ if (attributes.fill.empty()) {
+ return "";
+ }
+
+ return fmt::format(R"(fill="{}")", to_graphviz_color(attributes.fill));
+}
+
std::string SVG::SVGElement::id_attribute_to_string() const {
if (attributes.id.empty()) {
return "";
append_attribute(attributes_str, id_attribute_to_string());
switch (type) {
case SVG::SVGElementType::Ellipse:
- // ignore for now
+ append_attribute(attributes_str, fill_attribute_to_string());
break;
case SVG::SVGElementType::Group:
attributes_str += fmt::format(R"( class="{}")", attributes.class_);
}
break;
case SVG::SVGElementType::Path:
- // ignore for now
+ append_attribute(attributes_str, fill_attribute_to_string());
break;
case SVG::SVGElementType::Polygon:
- // ignore for now
+ append_attribute(attributes_str, fill_attribute_to_string());
break;
case SVG::SVGElementType::Polyline:
- // ignore for now
+ append_attribute(attributes_str, fill_attribute_to_string());
break;
case SVG::SVGElementType::Svg:
attributes_str += fmt::format(
struct SVGAttributes {
std::string class_;
+ std::string fill;
double height;
std::string id;
std::optional<SVGMatrix> transform;
void append_attribute(std::string &output,
const std::string &attribute) const;
std::string id_attribute_to_string() const;
+ std::string fill_attribute_to_string() const;
void to_string_impl(std::string &output, std::size_t indent_size,
std::size_t current_indent) const;
};
#include <any>
+#include <stdexcept>
#include <boost/array.hpp>
+#include <fmt/format.h>
#include "svg_analyzer_interface.h"
#include "svgpp_context.h"
+static std::string to_color_string(SvgppContext::color_t color) {
+ return fmt::format("rgb({},{},{})", (color >> 16) & 0xff, (color >> 8) & 0xff,
+ (color >> 0) & 0xff);
+}
+
SvgppContext::SvgppContext(ISVGAnalyzer *svgAnalyzer)
: m_svgAnalyzer(svgAnalyzer){};
(void)v;
}
+void SvgppContext::set(svgpp::tag::attribute::fill, svgpp::tag::value::none) {
+ m_svgAnalyzer->set_fill("none");
+}
+
+void SvgppContext::set(svgpp::tag::attribute::fill,
+ svgpp::tag::value::currentColor) {
+ throw std::runtime_error{
+ "the 'fill' attribute 'currentColor' value is not yet implemented"};
+}
+
+void SvgppContext::set(svgpp::tag::attribute::fill, color_t color,
+ svgpp::tag::skip_icc_color) {
+ m_svgAnalyzer->set_fill(to_color_string(color));
+}
+
void SvgppContext::transform_matrix(const boost::array<double, 6> &matrix) {
double a = matrix.at(0);
double b = matrix.at(1);
#pragma once
#include <any>
+#include <stdexcept>
#include <boost/range/iterator_range_core.hpp>
#include <svgpp/svgpp.hpp>
void path_exit();
void set(svgpp::tag::attribute::cy cy, double v);
void set(svgpp::tag::attribute::cx cx, double v);
+
+ void set(svgpp::tag::attribute::fill, svgpp::tag::value::none);
+ void set(svgpp::tag::attribute::fill, svgpp::tag::value::currentColor);
+ using color_t = int;
+ void set(svgpp::tag::attribute::fill, color_t color,
+ svgpp::tag::skip_icc_color = svgpp::tag::skip_icc_color());
+ template <class IRI> void set(svgpp::tag::attribute::fill, IRI const &) {
+ throw std::runtime_error{
+ "this flavor of the 'fill' attribute is not yet implemented"};
+ };
+ template <class IRI>
+ void set(svgpp::tag::attribute::fill, svgpp::tag::iri_fragment, IRI const &) {
+ throw std::runtime_error{
+ "this flavor of the 'fill' attribute is not yet implemented"};
+ };
+ template <class IRI>
+ void set(svgpp::tag::attribute::fill, IRI const &, svgpp::tag::value::none) {
+ throw std::runtime_error{
+ "this flavor of the 'fill' attribute is not yet implemented"};
+ };
+ template <class IRI>
+ void set(svgpp::tag::attribute::fill, svgpp::tag::iri_fragment, IRI const &,
+ svgpp::tag::value::none) {
+ throw std::runtime_error{
+ "this flavor of the 'fill' attribute is not yet implemented"};
+ };
+ template <class IRI>
+ void set(svgpp::tag::attribute::fill, IRI const &,
+ svgpp::tag::value::currentColor) {
+ throw std::runtime_error{
+ "this flavor of the 'fill' attribute is not yet implemented"};
+ };
+ template <class IRI>
+ void set(svgpp::tag::attribute::fill, svgpp::tag::iri_fragment, IRI const &,
+ svgpp::tag::value::currentColor) {
+ throw std::runtime_error{
+ "this flavor of the 'fill' attribute is not yet implemented"};
+ };
+ template <class IRI>
+ void set(svgpp::tag::attribute::fill, IRI const &, color_t,
+ svgpp::tag::skip_icc_color = svgpp::tag::skip_icc_color()) {
+ throw std::runtime_error{
+ "this flavor of the 'fill' attribute is not yet implemented"};
+ };
+ template <class IRI>
+ void set(svgpp::tag::attribute::fill, svgpp::tag::iri_fragment, IRI const &,
+ color_t, svgpp::tag::skip_icc_color = svgpp::tag::skip_icc_color()) {
+ throw std::runtime_error{
+ "this flavor of the 'fill' attribute is not yet implemented"};
+ };
void transform_matrix(const boost::array<double, 6> &matrix);
void set(svgpp::tag::attribute::r r, double v);
void set(svgpp::tag::attribute::rx rx, double v);
using processed_attributes_t =
boost::mpl::set<svgpp::traits::shapes_attributes_by_element,
svgpp::tag::attribute::class_, //
+ svgpp::tag::attribute::fill, //
svgpp::tag::attribute::height, //
svgpp::tag::attribute::id, //
svgpp::tag::attribute::transform, //
boost::split(recreated_svg_lines, recreated_svg, boost::is_any_of("\n"));
for (std::size_t i = 0; i < original_svg_lines.size(); i++) {
REQUIRE(i < recreated_svg_lines.size());
- if (recreated_svg_lines[i] == "<polygon/>") {
+ if (recreated_svg_lines[i] == "<polygon fill=\"white\"/>") {
// stop comparison here since we do not yet handle all attributes on the
// 'polygon' element
break;
CHECK(recreated_svg.find("<text>a</text>") != std::string::npos);
CHECK(recreated_svg.find("<text>b</text>") != std::string::npos);
}
- CHECK(recreated_svg.find("<polygon/>") != std::string::npos);
- CHECK(recreated_svg.find("<path/>") != std::string::npos);
+ CHECK(recreated_svg.find("<polygon fill=\"white\"/>") != std::string::npos);
+ CHECK(recreated_svg.find("<path fill=\"none\"/>") != std::string::npos);
CHECK(recreated_svg.find("<!-- a -->") != std::string::npos);
CHECK(recreated_svg.find("<!-- b -->") != std::string::npos);
CHECK(recreated_svg.find("<!-- a->b -->") != std::string::npos);