diff options
Diffstat (limited to 'svg-flatten')
23 files changed, 91 insertions, 27 deletions
diff --git a/svg-flatten/src/svg_doc.cpp b/svg-flatten/src/svg_doc.cpp index 1d85fd8..aae5abf 100644 --- a/svg-flatten/src/svg_doc.cpp +++ b/svg-flatten/src/svg_doc.cpp @@ -218,7 +218,7 @@ void gerbolyze::SVGDocument::export_svg_path(xform2d &mat, const RenderSettings vector<double> dasharray; parse_dasharray(node, dasharray); double stroke_dashoffset = usvg_double_attr(node, "stroke-dashoffset", /* default */ 0.0); - /* TODO add stroke-miterlimit */ + double stroke_miterlimit = usvg_double_attr(node, "stroke-miterlimit", /* default */ 4.0); if (!fill_color && !stroke_color) { /* Ignore "transparent" paths */ return; @@ -230,14 +230,12 @@ void gerbolyze::SVGDocument::export_svg_path(xform2d &mat, const RenderSettings /* FIXME transform stroke width here? */ stroke_width = local_xf.doc2phys_dist(stroke_width); - PolyTree ptree_stroke; + Paths stroke_open, stroke_closed; PolyTree ptree_fill; PolyTree ptree; - load_svg_path(local_xf, node, ptree_stroke, ptree_fill, rset.curve_tolerance_mm); + load_svg_path(local_xf, node, stroke_open, stroke_closed, ptree_fill, rset.curve_tolerance_mm); - Paths open_paths, closed_paths, fill_paths; - OpenPathsFromPolyTree(ptree_stroke, open_paths); - ClosedPathsFromPolyTree(ptree_stroke, closed_paths); + Paths fill_paths; PolyTreeToPaths(ptree_fill, fill_paths); bool has_fill = fill_color; @@ -299,9 +297,10 @@ void gerbolyze::SVGDocument::export_svg_path(xform2d &mat, const RenderSettings if (has_stroke) { ClipperOffset offx; offx.ArcTolerance = 0.01 * clipper_scale; /* 10µm; TODO: Make this configurable */ + offx.MiterLimit = stroke_miterlimit; /* For stroking we have to separately handle open and closed paths */ - for (auto &poly : closed_paths) { + for (auto &poly : stroke_closed) { if (poly.empty()) continue; @@ -331,7 +330,7 @@ void gerbolyze::SVGDocument::export_svg_path(xform2d &mat, const RenderSettings } } - for (const auto &poly : open_paths) { + for (const auto &poly : stroke_open) { Paths out; dash_path(poly, out, dasharray, stroke_dashoffset); @@ -440,13 +439,13 @@ void gerbolyze::SVGDocument::load_clips(const RenderSettings &rset) { * rendering, and the only way a group might stay is if it affects rasterization (e.g. through mask, clipPath). */ for (const auto &child : node.children("path")) { - PolyTree ptree_stroke; /* discarded */ + Paths _stroke_open, _stroke_closed; /* discarded */ PolyTree ptree_fill; /* TODO: we currently only support clipPathUnits="userSpaceOnUse", not "objectBoundingBox". */ xform2d child_xf(local_xf); child_xf.transform(xform2d(child.attribute("transform").value())); - load_svg_path(child_xf, child, ptree_stroke, ptree_fill, rset.curve_tolerance_mm); + load_svg_path(child_xf, child, _stroke_open, _stroke_closed, ptree_fill, rset.curve_tolerance_mm); Paths paths; PolyTreeToPaths(ptree_fill, paths); diff --git a/svg-flatten/src/svg_path.cpp b/svg-flatten/src/svg_path.cpp index 8b5be9e..f122626 100644 --- a/svg-flatten/src/svg_path.cpp +++ b/svg-flatten/src/svg_path.cpp @@ -28,7 +28,7 @@ using namespace std; -static pair<bool, bool> flatten_path(gerbolyze::xform2d &mat, ClipperLib::Clipper &c_stroke, ClipperLib::Clipper &c_fill, const pugi::char_t *path_data, double distance_tolerance_mm) { +static pair<bool, bool> flatten_path(gerbolyze::xform2d &mat, ClipperLib::Paths &stroke_open, ClipperLib::Paths &stroke_closed, ClipperLib::Clipper &c_fill, const pugi::char_t *path_data, double distance_tolerance_mm) { istringstream in(path_data); string cmd; @@ -45,7 +45,7 @@ static pair<bool, bool> flatten_path(gerbolyze::xform2d &mat, ClipperLib::Clippe assert(!first || cmd == "M"); if (cmd == "Z") { /* Close path */ - c_stroke.AddPath(in_poly, ClipperLib::ptSubject, true); + stroke_closed.push_back(in_poly); c_fill.AddPath(in_poly, ClipperLib::ptSubject, true); has_closed = true; @@ -54,7 +54,7 @@ static pair<bool, bool> flatten_path(gerbolyze::xform2d &mat, ClipperLib::Clippe } else if (cmd == "M") { /* Move to */ if (!first && !in_poly.empty()) { - c_stroke.AddPath(in_poly, ClipperLib::ptSubject, false); + stroke_open.push_back(in_poly); c_fill.AddPath(in_poly, ClipperLib::ptSubject, true); num_subpaths += 1; in_poly.clear(); @@ -114,7 +114,7 @@ static pair<bool, bool> flatten_path(gerbolyze::xform2d &mat, ClipperLib::Clippe } if (!in_poly.empty()) { - c_stroke.AddPath(in_poly, ClipperLib::ptSubject, false); + stroke_open.push_back(in_poly); c_fill.AddPath(in_poly, ClipperLib::ptSubject, true); num_subpaths += 1; } @@ -122,18 +122,16 @@ static pair<bool, bool> flatten_path(gerbolyze::xform2d &mat, ClipperLib::Clippe return {has_closed, num_subpaths > 1}; } -void gerbolyze::load_svg_path(xform2d &mat, const pugi::xml_node &node, ClipperLib::PolyTree &ptree_stroke, ClipperLib::PolyTree &ptree_fill, double curve_tolerance) { +void gerbolyze::load_svg_path(xform2d &mat, const pugi::xml_node &node, ClipperLib::Paths &stroke_open, ClipperLib::Paths &stroke_closed, ClipperLib::PolyTree &ptree_fill, double curve_tolerance) { auto *path_data = node.attribute("d").value(); auto fill_rule = clipper_fill_rule(node); /* For open paths, clipper does not correctly remove self-intersections. Thus, we pass everything into * clipper twice: Once with all paths set to "closed" to compute fill areas, and once with correct * open/closed properties for stroke offsetting. */ - ClipperLib::Clipper c_stroke; ClipperLib::Clipper c_fill; - c_stroke.StrictlySimple(true); c_fill.StrictlySimple(true); - auto res = flatten_path(mat, c_stroke, c_fill, path_data, curve_tolerance); + auto res = flatten_path(mat, stroke_open, stroke_closed, c_fill, path_data, curve_tolerance); bool has_closed = res.first, has_multiple = res.second; if (!has_closed && !has_multiple) { @@ -155,15 +153,11 @@ void gerbolyze::load_svg_path(xform2d &mat, const pugi::xml_node &node, ClipperL auto le_max = ClipperLib::hiRange; ClipperLib::Path p = {{le_min, le_min}, {le_max, le_min}, {le_max, le_max}, {le_min, le_max}}; - c_stroke.AddPath(p, ClipperLib::ptClip, /* closed= */ true); - c_stroke.Execute(ClipperLib::ctIntersection, ptree_stroke, fill_rule, ClipperLib::pftNonZero); - c_fill.AddPath(p, ClipperLib::ptClip, /* closed= */ true); c_fill.Execute(ClipperLib::ctIntersection, ptree_fill, fill_rule, ClipperLib::pftNonZero); } else { /* We cannot clip the polygon here since that would produce incorrect results for our stroke. */ - c_stroke.Execute(ClipperLib::ctUnion, ptree_stroke, fill_rule, ClipperLib::pftNonZero); c_fill.Execute(ClipperLib::ctUnion, ptree_fill, fill_rule, ClipperLib::pftNonZero); } } @@ -265,5 +259,10 @@ void gerbolyze::dash_path(const ClipperLib::Path &in, ClipperLib::Paths &out, co current_dash.push_back(p2); } } + + /* Finish last dash */ + if (current_dash.size() > 0 && (dash_idx%2 == 0)) { + out.push_back(current_dash); + } } diff --git a/svg-flatten/src/svg_path.h b/svg-flatten/src/svg_path.h index 611f517..c0b2d88 100644 --- a/svg-flatten/src/svg_path.h +++ b/svg-flatten/src/svg_path.h @@ -23,7 +23,7 @@ #include "geom2d.hpp" namespace gerbolyze { -void load_svg_path(xform2d &mat, const pugi::xml_node &node, ClipperLib::PolyTree &ptree_stroke, ClipperLib::PolyTree &ptree_fill, double curve_tolerance); +void load_svg_path(xform2d &mat, const pugi::xml_node &node, ClipperLib::Paths &stroke_open, ClipperLib::Paths &stroke_closed, ClipperLib::PolyTree &ptree_fill, double curve_tolerance); void parse_dasharray(const pugi::xml_node &node, std::vector<double> &out); void dash_path(const ClipperLib::Path &in, ClipperLib::Paths &out, const std::vector<double> dasharray, double dash_offset=0.0); } diff --git a/svg-flatten/src/test/svg_tests.py b/svg-flatten/src/test/svg_tests.py index a5139ec..c457ed4 100644 --- a/svg-flatten/src/test/svg_tests.py +++ b/svg-flatten/src/test/svg_tests.py @@ -34,11 +34,48 @@ def run_svg_flatten(input_file, output_file, **kwargs): class SVGRoundTripTests(unittest.TestCase): - def compare_images(self, reference, output, test_name, mean=0.01): + # Notes on test cases: + # Our stroke join test shows a discrepancy in miter handling between resvg and gerbolyze. Gerbolyze's miter join is + # the one from Clipper, which unfortunately cannot be configured. resvg uses one looking like that from the SVG 2 + # spec. Gerbolyze's join is legal by the 1.1 spec since this spec does not explicitly define the miter offset. It + # only contains a blurry picture, and that picture looks like what gerbolyze produces. + + test_mean_default = 0.02 + test_mean_overrides = { + # Both of these produce high errors for two reasons: + # * By necessity, we get some error accumulation because we are dashing the path *after* flattening, and + # flattened path length is always a tiny bit smaller than actual path length for curved paths. + # * Since the image contains a lot of edges there are lots of small differences in anti-aliasing. + # Both are expected and OK. + 'stroke_dashes_comparison': 0.03, + 'stroke_dashes': 0.05, + } + + # Force use of rsvg-convert instead of resvg for these test cases + rsvg_override = { + # resvg is bad at rendering patterns. Both scale and offset are wrong, and the result is a blurry mess. + # See https://github.com/RazrFalcon/resvg/issues/221 + 'pattern_fill', + 'pattern_stroke', + 'pattern_stroke_dashed' + } + + def compare_images(self, reference, output, test_name, mean, rsvg_workaround=False): ref = np.array(Image.open(reference)) out = np.array(Image.open(output)) + if rsvg_workaround: + # For some stupid reason, rsvg-convert does not actually output black as in "black" pixels when asked to. + # Instead, it outputs #010101. We fix this in post here. + ref = (ref - 1.0) * (255/254) delta = np.abs(out - ref).astype(float) / 255 + + #def print_stats(ref): + # print('img:', ref.min(), ref.mean(), ref.max(), 'std:', ref.std(), 'channels:', *(ref[:,:,i].mean() for i in + # range(ref.shape[2]))) + #print_stats(ref) + #print_stats(out) + #print(f'{test_name}: mean={delta.mean():.5g}') self.assertTrue(delta.mean() < mean, @@ -51,11 +88,21 @@ class SVGRoundTripTests(unittest.TestCase): run_svg_flatten(test_in_svg, tmp_out_svg.name, format='svg') - subprocess.run(['resvg', tmp_out_svg.name, tmp_out_png.name], check=True, stdout=subprocess.DEVNULL) - subprocess.run(['resvg', test_in_svg, tmp_in_png.name], check=True, stdout=subprocess.DEVNULL) + use_rsvg = test_in_svg.stem in SVGRoundTripTests.rsvg_override + + if not use_rsvg: # default! + subprocess.run(['resvg', tmp_out_svg.name, tmp_out_png.name], check=True, stdout=subprocess.DEVNULL) + subprocess.run(['resvg', test_in_svg, tmp_in_png.name], check=True, stdout=subprocess.DEVNULL) + + else: + subprocess.run(['rsvg-convert', tmp_out_svg.name, '-f', 'png', '-o', tmp_out_png.name], check=True, stdout=subprocess.DEVNULL) + subprocess.run(['rsvg-convert', test_in_svg, '-f', 'png', '-o', tmp_in_png.name], check=True, stdout=subprocess.DEVNULL) try: - self.compare_images(tmp_in_png, tmp_out_png, test_in_svg.stem) + self.compare_images(tmp_in_png, tmp_out_png, test_in_svg.stem, + SVGRoundTripTests.test_mean_overrides.get(test_in_svg.stem, SVGRoundTripTests.test_mean_default), + rsvg_workaround=use_rsvg) + except AssertionError as e: import shutil shutil.copyfile(tmp_in_png.name, f'/tmp/gerbolyze-fail-{test_in_svg.stem}-in.png') diff --git a/svg-flatten/testdata/svg/circles.svg b/svg-flatten/testdata/svg/circles.svg index 9be474e..8dc8a22 100644 --- a/svg-flatten/testdata/svg/circles.svg +++ b/svg-flatten/testdata/svg/circles.svg @@ -48,6 +48,7 @@ inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="svg8" /> + <rect width="100%" height="100%" fill="white"/> <circle style="fill:#000000;stroke:none;stroke-width:0.0264583;stroke-linejoin:round;stop-color:#000000" id="path950" diff --git a/svg-flatten/testdata/svg/compound_xform.svg b/svg-flatten/testdata/svg/compound_xform.svg index 229e05d..e4b3688 100644 --- a/svg-flatten/testdata/svg/compound_xform.svg +++ b/svg-flatten/testdata/svg/compound_xform.svg @@ -48,6 +48,7 @@ inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="svg8" /> + <rect width="100%" height="100%" fill="white"/> <g id="g1200"> <g diff --git a/svg-flatten/testdata/svg/empty.svg b/svg-flatten/testdata/svg/empty.svg index d2cdc52..7e959f7 100644 --- a/svg-flatten/testdata/svg/empty.svg +++ b/svg-flatten/testdata/svg/empty.svg @@ -8,4 +8,5 @@ viewBox="0 0 50 50" version="1.1" id="svg8"> + <rect width="100%" height="100%" fill="white"/> </svg> diff --git a/svg-flatten/testdata/svg/empty_inkscape.svg b/svg-flatten/testdata/svg/empty_inkscape.svg index 716379f..ce43b2b 100644 --- a/svg-flatten/testdata/svg/empty_inkscape.svg +++ b/svg-flatten/testdata/svg/empty_inkscape.svg @@ -47,6 +47,7 @@ </cc:Work> </rdf:RDF> </metadata> + <rect width="100%" height="100%" fill="white"/> <g inkscape:label="Layer 1" inkscape:groupmode="layer" diff --git a/svg-flatten/testdata/svg/groups.svg b/svg-flatten/testdata/svg/groups.svg index d94dad0..87c7444 100644 --- a/svg-flatten/testdata/svg/groups.svg +++ b/svg-flatten/testdata/svg/groups.svg @@ -48,6 +48,7 @@ inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="svg8" /> + <rect width="100%" height="100%" fill="white"/> <rect style="fill:#000000;stroke:none;stroke-width:0.0264583;stroke-linejoin:round;stop-color:#000000" id="rect1002" diff --git a/svg-flatten/testdata/svg/pattern_fill.svg b/svg-flatten/testdata/svg/pattern_fill.svg index 21789e6..6b43c65 100644 --- a/svg-flatten/testdata/svg/pattern_fill.svg +++ b/svg-flatten/testdata/svg/pattern_fill.svg @@ -111,6 +111,7 @@ inkscape:current-layer="svg8" inkscape:document-units="mm" showguides="false" /> + <rect width="100%" height="100%" fill="white"/> <circle style="opacity:0.99435;fill:url(#pattern3461);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:4.00001, 4.00001;stroke-dashoffset:2.19001;stop-color:#000000" id="path1374" diff --git a/svg-flatten/testdata/svg/pattern_stroke.svg b/svg-flatten/testdata/svg/pattern_stroke.svg index 5564df0..086ef69 100644 --- a/svg-flatten/testdata/svg/pattern_stroke.svg +++ b/svg-flatten/testdata/svg/pattern_stroke.svg @@ -80,6 +80,7 @@ inkscape:current-layer="svg8" inkscape:document-units="mm" showguides="false" /> + <rect width="100%" height="100%" fill="white"/> <circle style="opacity:0.99435;fill:none;stroke:url(#pattern3520);stroke-width:8;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:10.95;stroke-opacity:1;stop-color:#000000" id="path3513" diff --git a/svg-flatten/testdata/svg/pattern_stroke_dashed.svg b/svg-flatten/testdata/svg/pattern_stroke_dashed.svg index 3d8145e..6c0fb93 100644 --- a/svg-flatten/testdata/svg/pattern_stroke_dashed.svg +++ b/svg-flatten/testdata/svg/pattern_stroke_dashed.svg @@ -80,6 +80,7 @@ inkscape:current-layer="svg8" inkscape:document-units="mm" showguides="false" /> + <rect width="100%" height="100%" fill="white"/> <circle style="opacity:0.99435;fill:#000000;stroke:url(#pattern3520);stroke-width:12;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:6,6;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000" id="path3513" diff --git a/svg-flatten/testdata/svg/rect.svg b/svg-flatten/testdata/svg/rect.svg index 297ff7e..adb2dff 100644 --- a/svg-flatten/testdata/svg/rect.svg +++ b/svg-flatten/testdata/svg/rect.svg @@ -48,6 +48,7 @@ inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="svg8" /> + <rect width="100%" height="100%" fill="white"/> <rect style="fill:#000000;stroke:none;stroke-width:0.0264583;stroke-linejoin:round;stop-color:#000000" id="rect832" diff --git a/svg-flatten/testdata/svg/rect_occlusion.svg b/svg-flatten/testdata/svg/rect_occlusion.svg index ce0e531..5cbe90e 100644 --- a/svg-flatten/testdata/svg/rect_occlusion.svg +++ b/svg-flatten/testdata/svg/rect_occlusion.svg @@ -48,6 +48,7 @@ inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="svg8" /> + <rect width="100%" height="100%" fill="white"/> <rect style="fill:#000000;stroke:none;stroke-width:0.0264583;stroke-linejoin:round;stop-color:#000000" id="rect832" diff --git a/svg-flatten/testdata/svg/rotation.svg b/svg-flatten/testdata/svg/rotation.svg index 961ef0f..af68d91 100644 --- a/svg-flatten/testdata/svg/rotation.svg +++ b/svg-flatten/testdata/svg/rotation.svg @@ -48,6 +48,7 @@ inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="svg8" /> + <rect width="100%" height="100%" fill="white"/> <rect style="fill:#000000;stroke:none;stroke-width:0.0264583;stroke-linejoin:round;stop-color:#000000" id="rect1022" diff --git a/svg-flatten/testdata/svg/rotation_90.svg b/svg-flatten/testdata/svg/rotation_90.svg index dcca867..bcec2c4 100644 --- a/svg-flatten/testdata/svg/rotation_90.svg +++ b/svg-flatten/testdata/svg/rotation_90.svg @@ -48,6 +48,7 @@ inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="svg8" /> + <rect width="100%" height="100%" fill="white"/> <rect style="fill:#000000;stroke:none;stroke-width:0.0264583;stroke-linejoin:round;stop-color:#000000" id="rect1022" diff --git a/svg-flatten/testdata/svg/scale.svg b/svg-flatten/testdata/svg/scale.svg index 91b28d6..de98236 100644 --- a/svg-flatten/testdata/svg/scale.svg +++ b/svg-flatten/testdata/svg/scale.svg @@ -48,6 +48,7 @@ inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="svg8" /> + <rect width="100%" height="100%" fill="white"/> <g id="g1082" transform="matrix(0.81799278,0,0,0.81799278,12.474166,-0.98587389)" diff --git a/svg-flatten/testdata/svg/shear.svg b/svg-flatten/testdata/svg/shear.svg index ec7875f..9739f4a 100644 --- a/svg-flatten/testdata/svg/shear.svg +++ b/svg-flatten/testdata/svg/shear.svg @@ -48,6 +48,7 @@ inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="svg8" /> + <rect width="100%" height="100%" fill="white"/> <ellipse style="fill:#000000;stroke:none;stroke-width:0.0307622;stroke-linejoin:round;stop-color:#000000" id="path1130" diff --git a/svg-flatten/testdata/svg/stroke.svg b/svg-flatten/testdata/svg/stroke.svg index 6a4b334..aa26012 100644 --- a/svg-flatten/testdata/svg/stroke.svg +++ b/svg-flatten/testdata/svg/stroke.svg @@ -50,6 +50,7 @@ inkscape:current-layer="svg8" inkscape:document-units="mm" showguides="false" /> + <rect width="100%" height="100%" fill="white"/> <rect style="fill:#ffffff;stroke:#000000;stroke-width:9.99998;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stop-color:#000000" id="rect1220" diff --git a/svg-flatten/testdata/svg/stroke_caps.svg b/svg-flatten/testdata/svg/stroke_caps.svg index 6b89a34..e261dca 100644 --- a/svg-flatten/testdata/svg/stroke_caps.svg +++ b/svg-flatten/testdata/svg/stroke_caps.svg @@ -50,6 +50,7 @@ inkscape:current-layer="svg8" inkscape:document-units="mm" showguides="false" /> + <rect width="100%" height="100%" fill="white"/> <path style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" d="M 8.1209509,7.3978548 20.159949,7.3803896 9.2562029,14.249268 c 19.4757851,0.912458 -2.156778,6.498823 6.5634261,12.04404" diff --git a/svg-flatten/testdata/svg/stroke_dashes.svg b/svg-flatten/testdata/svg/stroke_dashes.svg index c1d6f5c..04240af 100644 --- a/svg-flatten/testdata/svg/stroke_dashes.svg +++ b/svg-flatten/testdata/svg/stroke_dashes.svg @@ -50,6 +50,7 @@ inkscape:current-layer="svg8" inkscape:document-units="mm" showguides="false" /> + <rect width="100%" height="100%" fill="white"/> <path style="fill:none;stroke:#000000;stroke-width:3.00000008;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:3.00000008,3.00000008;stroke-dashoffset:0" d="M 8.1209509,7.3978548 20.159949,7.3803896 9.2562029,14.249268 c 19.4757851,0.912458 -2.156778,6.498823 6.5634261,12.04404" diff --git a/svg-flatten/testdata/svg/stroke_joins.svg b/svg-flatten/testdata/svg/stroke_joins.svg index ee3e1ac..3694319 100644 --- a/svg-flatten/testdata/svg/stroke_joins.svg +++ b/svg-flatten/testdata/svg/stroke_joins.svg @@ -50,6 +50,7 @@ inkscape:current-layer="svg8" inkscape:document-units="mm" showguides="false" /> + <rect width="100%" height="100%" fill="white"/> <path style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none" d="M 8.1209509,7.3978548 20.159949,7.3803896 9.2562029,14.249268 c 19.4757851,0.912458 -2.156778,6.498823 6.5634261,12.04404" diff --git a/svg-flatten/testdata/svg/text.svg b/svg-flatten/testdata/svg/text.svg index bd8c390..e08de4a 100644 --- a/svg-flatten/testdata/svg/text.svg +++ b/svg-flatten/testdata/svg/text.svg @@ -81,6 +81,7 @@ inkscape:current-layer="svg8" inkscape:document-units="mm" showguides="false" /> + <rect width="100%" height="100%" fill="white"/> <text xml:space="preserve" id="text3558" |