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_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, double width, double height, bool update_cache = false, bool strict = false);
void clear();
};

View file

@ -86,12 +86,14 @@ class MAPNIK_DECL svg_parser : private util::noncopyable
{
using error_handler = svg_parser_error_handler;
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();
error_handler & err_handler();
void parse(std::string const& filename);
void parse_from_string(std::string const& svg);
svg_converter_type & path_;
double width_;
double height_;
bool is_defs_;
bool strict_;
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,
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())
{
@ -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());
svg_path_adapter svg_path(stl_storage);
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);
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());
svg_path_adapter svg_path(stl_storage);
svg_converter_type svg(svg_path, marker_path->attributes());
svg_parser p(svg, strict);
svg_parser p(svg, width, height, strict);
p.parse(uri);
if (!strict)

View file

@ -878,17 +878,29 @@ void parse_dimensions(svg_parser & parser, rapidxml::xml_node<char> const* node)
viewbox vbox = {0, 0, 0, 0};
bool has_percent_height = true;
bool has_percent_width = true;
bool overwrite_dimensions = false;
auto const* width_attr = node->first_attribute("width");
auto const* height_attr = node->first_attribute("height");
if (parser.width_ > 0 && parser.height_ > 0) // overwrite SVG document dimensions
{
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);
}
auto const* height_attr = node->first_attribute("height");
if (height_attr)
{
height = parse_svg_value(parser, height_attr->value(), has_percent_height);
}
}
parser.vbox_ = viewbox{0, 0, width, height} ;
auto const* viewbox_attr = node->first_attribute("viewBox");
if (viewbox_attr && parse_viewbox(parser.err_handler(), viewbox_attr->value(), vbox))
@ -896,12 +908,13 @@ void parse_dimensions(svg_parser & parser, rapidxml::xml_node<char> const* node)
agg::trans_affine t{};
parser.vbox_ = vbox;
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_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)
{
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),
width_(width),
height_(height),
is_defs_(false),
ignore_(false),
css_style_(false),

View file

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

View file

@ -152,7 +152,7 @@ struct main_marker_visitor
private:
std::string svg_name_;
double scale_factor_ = 1.0;
double scale_factor_;
bool verbose_;
bool auto_open_;
};
@ -167,6 +167,8 @@ int main (int argc,char** argv)
int status = 0;
std::vector<std::string> svg_files;
mapnik::logger::instance().set_severity(mapnik::logger::error);
double target_width = 0.0;
double target_height = 0.0;
double scale_factor = 1.0;
std::string usage = "Usage: svg2png [options] <svg-file(s)>";
try
@ -179,6 +181,8 @@ int main (int argc,char** argv)
("open,o","automatically open the file after rendering (os x only)")
("strict,s","enables strict SVG parsing")
("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")
;
@ -219,6 +223,14 @@ int main (int argc,char** argv)
{
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"))
{
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::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);
status = mapnik::util::apply_visitor(visitor, *marker);
}