SVG - add experimental "target" width and height which overwrite SVG's outermost "width" and "height" attributes [WIP]

This commit is contained in:
Artem Pavlenko 2021-04-16 16:01:39 +01:00
parent 21fd41b9a9
commit 792519e66a
6 changed files with 57 additions and 20 deletions

View file

@ -56,6 +56,7 @@ public:
bool is_svg_uri(std::string const& path); bool is_svg_uri(std::string const& path);
bool is_image_uri(std::string const& path); bool is_image_uri(std::string const& path);
std::shared_ptr<marker const> find(std::string const& key, bool update_cache = false, bool strict = false); std::shared_ptr<marker const> find(std::string const& key, bool update_cache = false, bool strict = false);
std::shared_ptr<marker const> find(std::string const& key, double width, double height, bool update_cache = false, bool strict = false);
void clear(); void clear();
}; };

View file

@ -86,12 +86,14 @@ class MAPNIK_DECL svg_parser : private util::noncopyable
{ {
using error_handler = svg_parser_error_handler; using error_handler = svg_parser_error_handler;
public: public:
explicit svg_parser(svg_converter_type & path, bool strict = false); explicit svg_parser(svg_converter_type & path, double width, double height, bool strict = false);
~svg_parser(); ~svg_parser();
error_handler & err_handler(); error_handler & err_handler();
void parse(std::string const& filename); void parse(std::string const& filename);
void parse_from_string(std::string const& svg); void parse_from_string(std::string const& svg);
svg_converter_type & path_; svg_converter_type & path_;
double width_;
double height_;
bool is_defs_; bool is_defs_;
bool strict_; bool strict_;
bool ignore_; bool ignore_;

View file

@ -144,6 +144,12 @@ struct visitor_create_marker
std::shared_ptr<mapnik::marker const> marker_cache::find(std::string const& uri, std::shared_ptr<mapnik::marker const> marker_cache::find(std::string const& uri,
bool update_cache, bool strict) bool update_cache, bool strict)
{
return find(uri, 0, 0, update_cache, strict);
}
std::shared_ptr<mapnik::marker const> marker_cache::find(std::string const& uri, double width, double height,
bool update_cache, bool strict)
{ {
if (uri.empty()) if (uri.empty())
{ {
@ -176,7 +182,7 @@ std::shared_ptr<mapnik::marker const> marker_cache::find(std::string const& uri,
vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source()); vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source());
svg_path_adapter svg_path(stl_storage); svg_path_adapter svg_path(stl_storage);
svg_converter_type svg(svg_path, marker_path->attributes()); svg_converter_type svg(svg_path, marker_path->attributes());
svg_parser p(svg, strict); svg_parser p(svg, width, height, strict);
p.parse_from_string(known_svg_string); p.parse_from_string(known_svg_string);
if (!strict) if (!strict)
@ -216,7 +222,7 @@ std::shared_ptr<mapnik::marker const> marker_cache::find(std::string const& uri,
vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source()); vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source());
svg_path_adapter svg_path(stl_storage); svg_path_adapter svg_path(stl_storage);
svg_converter_type svg(svg_path, marker_path->attributes()); svg_converter_type svg(svg_path, marker_path->attributes());
svg_parser p(svg, strict); svg_parser p(svg, width, height, strict);
p.parse(uri); p.parse(uri);
if (!strict) if (!strict)

View file

@ -878,16 +878,28 @@ void parse_dimensions(svg_parser & parser, rapidxml::xml_node<char> const* node)
viewbox vbox = {0, 0, 0, 0}; viewbox vbox = {0, 0, 0, 0};
bool has_percent_height = true; bool has_percent_height = true;
bool has_percent_width = true; bool has_percent_width = true;
bool overwrite_dimensions = false;
auto const* width_attr = node->first_attribute("width"); auto const* width_attr = node->first_attribute("width");
if (width_attr)
{
width = parse_svg_value(parser, width_attr->value(), has_percent_width);
}
auto const* height_attr = node->first_attribute("height"); auto const* height_attr = node->first_attribute("height");
if (height_attr)
if (parser.width_ > 0 && parser.height_ > 0) // overwrite SVG document dimensions
{ {
height = parse_svg_value(parser, height_attr->value(), has_percent_height); has_percent_height = false;
has_percent_width = false;
overwrite_dimensions = true;
width = parser.width_;
height = parser.height_;
}
else
{
if (width_attr)
{
width = parse_svg_value(parser, width_attr->value(), has_percent_width);
}
if (height_attr)
{
height = parse_svg_value(parser, height_attr->value(), has_percent_height);
}
} }
parser.vbox_ = viewbox{0, 0, width, height} ; parser.vbox_ = viewbox{0, 0, width, height} ;
auto const* viewbox_attr = node->first_attribute("viewBox"); auto const* viewbox_attr = node->first_attribute("viewBox");
@ -896,12 +908,13 @@ void parse_dimensions(svg_parser & parser, rapidxml::xml_node<char> const* node)
agg::trans_affine t{}; agg::trans_affine t{};
parser.vbox_ = vbox; parser.vbox_ = vbox;
parser.normalized_diagonal_ = std::sqrt(vbox.width * vbox.width + vbox.height * vbox.height)/std::sqrt(2.0); parser.normalized_diagonal_ = std::sqrt(vbox.width * vbox.width + vbox.height * vbox.height)/std::sqrt(2.0);
if (!overwrite_dimensions)
if (has_percent_width) width = vbox.width * width; {
else if (!width_attr || width == 0) width = vbox.width; if (has_percent_width) width = vbox.width * width;
if (has_percent_height) height = vbox.height * height; else if (!width_attr || width == 0) width = vbox.width;
else if (!height_attr || height == 0) height = vbox.height; if (has_percent_height) height = vbox.height * height;
else if (!height_attr || height == 0) height = vbox.height;
}
if (width > 0 && height > 0 && vbox.width > 0 && vbox.height > 0) if (width > 0 && height > 0 && vbox.width > 0 && vbox.height > 0)
{ {
std::pair<unsigned,bool> preserve_aspect_ratio {xMidYMid, true}; std::pair<unsigned,bool> preserve_aspect_ratio {xMidYMid, true};
@ -1583,8 +1596,10 @@ void parse_linear_gradient(svg_parser & parser, rapidxml::xml_node<char> const*
} }
svg_parser::svg_parser(svg_converter_type & path, bool strict) svg_parser::svg_parser(svg_converter_type & path, double width, double height, bool strict)
: path_(path), : path_(path),
width_(width),
height_(height),
is_defs_(false), is_defs_(false),
ignore_(false), ignore_(false),
css_style_(false), css_style_(false),

View file

@ -48,7 +48,7 @@ namespace // internal
: stl_storage(path.source()) : stl_storage(path.source())
, svg_path(stl_storage) , svg_path(stl_storage)
, svg(svg_path, path.attributes()) , svg(svg_path, path.attributes())
, p(svg, strict) , p(svg, 0, 0, strict)
{} {}
mapnik::svg::svg_parser* operator->() mapnik::svg::svg_parser* operator->()

View file

@ -152,7 +152,7 @@ struct main_marker_visitor
private: private:
std::string svg_name_; std::string svg_name_;
double scale_factor_ = 1.0; double scale_factor_;
bool verbose_; bool verbose_;
bool auto_open_; bool auto_open_;
}; };
@ -167,6 +167,8 @@ int main (int argc,char** argv)
int status = 0; int status = 0;
std::vector<std::string> svg_files; std::vector<std::string> svg_files;
mapnik::logger::instance().set_severity(mapnik::logger::error); mapnik::logger::instance().set_severity(mapnik::logger::error);
double target_width = 0.0;
double target_height = 0.0;
double scale_factor = 1.0; double scale_factor = 1.0;
std::string usage = "Usage: svg2png [options] <svg-file(s)>"; std::string usage = "Usage: svg2png [options] <svg-file(s)>";
try try
@ -179,6 +181,8 @@ int main (int argc,char** argv)
("open,o","automatically open the file after rendering (os x only)") ("open,o","automatically open the file after rendering (os x only)")
("strict,s","enables strict SVG parsing") ("strict,s","enables strict SVG parsing")
("scale-factor", po::value<double>(), "provide scaling factor (default: 1.0)") ("scale-factor", po::value<double>(), "provide scaling factor (default: 1.0)")
("width", po::value<double>(), "width of the SVG document")
("height", po::value<double>(), "height of the SVG document")
("svg",po::value<std::vector<std::string> >(),"svg file to read") ("svg",po::value<std::vector<std::string> >(),"svg file to read")
; ;
@ -219,6 +223,14 @@ int main (int argc,char** argv)
{ {
scale_factor = vm["scale-factor"].as<double>(); scale_factor = vm["scale-factor"].as<double>();
} }
if (vm.count("width"))
{
target_width = vm["width"].as<double>();
}
if (vm.count("height"))
{
target_height = vm["height"].as<double>();
}
if (vm.count("svg")) if (vm.count("svg"))
{ {
svg_files=vm["svg"].as< std::vector<std::string> >(); svg_files=vm["svg"].as< std::vector<std::string> >();
@ -242,7 +254,8 @@ int main (int argc,char** argv)
{ {
std::clog << "found: " << svg_name << "\n"; std::clog << "found: " << svg_name << "\n";
} }
std::shared_ptr<mapnik::marker const> marker = mapnik::marker_cache::instance().find(svg_name, false, strict); std::shared_ptr<mapnik::marker const> marker =
mapnik::marker_cache::instance().find(svg_name, target_width, target_height, false, strict);
main_marker_visitor visitor(svg_name, scale_factor, verbose, auto_open); main_marker_visitor visitor(svg_name, scale_factor, verbose, auto_open);
status = mapnik::util::apply_visitor(visitor, *marker); status = mapnik::util::apply_visitor(visitor, *marker);
} }