From 3e88a2be4d0871b4adf156f1b4d82e99612c558b Mon Sep 17 00:00:00 2001 From: Charlotte Curtis Date: Thu, 21 Nov 2024 02:25:30 +0000 Subject: [PATCH] Reduce number of clipping paths created during PDF import --- .../internal/pdfinput/svg-builder.cpp | 88 +- src/extension/internal/pdfinput/svg-builder.h | 6 +- src/helper/geom.cpp | 74 ++ src/helper/geom.h | 2 + testfiles/cli_tests/CMakeLists.txt | 1 + .../pdfinput/Annot_w_AP_expected.svg | 565 ++-------- .../testcases/pdfinput/clipping_shift.pdf | 152 +++ .../pdfinput/clipping_shift_expected.svg | 228 ++++ .../pdfinput/gs_linewidth_expected.svg | 57 +- .../pdfinput/multi-page-sample_expected.svg | 995 ++++++------------ .../pdfinput/transparency-groups_expected.svg | 82 +- 11 files changed, 990 insertions(+), 1260 deletions(-) create mode 100644 testfiles/cli_tests/testcases/pdfinput/clipping_shift.pdf create mode 100644 testfiles/cli_tests/testcases/pdfinput/clipping_shift_expected.svg diff --git a/src/extension/internal/pdfinput/svg-builder.cpp b/src/extension/internal/pdfinput/svg-builder.cpp index a74147d074d..cdd8d755e82 100644 --- a/src/extension/internal/pdfinput/svg-builder.cpp +++ b/src/extension/internal/pdfinput/svg-builder.cpp @@ -47,6 +47,7 @@ #include "object/sp-defs.h" #include "object/sp-item-group.h" #include "object/sp-namedview.h" +#include "object/sp-text.h" #include "svg/css-ostringstream.h" #include "svg/path-string.h" #include "svg/svg.h" @@ -55,6 +56,7 @@ #include "xml/node.h" #include "xml/repr.h" #include "xml/sp-css-attr.h" +#include "helper/geom.h" namespace Inkscape { namespace Extension { @@ -350,11 +352,7 @@ void SvgBuilder::_addToContainer(Inkscape::XML::Node *node, bool release) void SvgBuilder::_setClipPath(Inkscape::XML::Node *node) { if (_clip_history->hasClipPath() || _clip_text) { - auto tr = Geom::identity(); - if (auto attr = node->attribute("transform")) { - sp_svg_transform_read(attr, &tr); - } - if (auto clip_path = _getClip(tr)) { + if (auto clip_path = _getClip(node)) { gchar *urltext = g_strdup_printf("url(#%s)", clip_path->attribute("id")); node->setAttribute("clip-path", urltext); g_free(urltext); @@ -794,29 +792,34 @@ void SvgBuilder::setClip(GfxState *state, GfxClipType clip, bool is_bbox) /** * Return the active clip as a new xml node. */ -Inkscape::XML::Node *SvgBuilder::_getClip(const Geom::Affine &node_tr) +Inkscape::XML::Node *SvgBuilder::_getClip(const Inkscape::XML::Node *node) { // In SVG the path-clip transforms are compounded, so we have to do extra work to // pull transforms back out of the clipping object and set them. Otherwise this // would all be a lot simpler. + Geom::Affine node_tr = Geom::identity(); + if (auto attr = node->attribute("transform")) { + sp_svg_transform_read(attr, &node_tr); + } + if (_clip_text) { - auto node = _clip_text; + auto clip_node = _clip_text; auto text_tr = Geom::identity(); - if (auto attr = node->attribute("transform")) { + if (auto attr = clip_node->attribute("transform")) { sp_svg_transform_read(attr, &text_tr); - node->removeAttribute("transform"); + clip_node->removeAttribute("transform"); } - for (auto child = node->firstChild(); child; child = child->next()) { + for (auto child = clip_node->firstChild(); child; child = child->next()) { Geom::Affine child_tr = text_tr * _page_affine * node_tr.inverse(); svgSetTransform(child, child_tr); } _clip_text = nullptr; - return node; + return clip_node; } - if (_clip_history->hasClipPath()) { + if (_shouldClip(node)) { std::string clip_d = svgInterpretPath(_clip_history->getClipPath()); Geom::Affine tr = _clip_history->getAffine() * _page_affine * node_tr.inverse(); return _createClip(clip_d, tr, _clip_history->evenOdd()); @@ -824,8 +827,65 @@ Inkscape::XML::Node *SvgBuilder::_getClip(const Geom::Affine &node_tr) return nullptr; } +bool SvgBuilder::_shouldClip(const Inkscape::XML::Node *node) const +{ + if (!_clip_history->hasClipPath()) { + return false; + } + + // Calculate bounding boxes for both the node and the clip path + Geom::PathVector node_vec = sp_svg_read_pathv(node->attribute("d")); + + if (node_vec.empty()) { + // Non-path node (text, image, etc) + // Create a PathVector of the bounding box instead + _doc->ensureUpToDate(); + auto item = cast(_doc->getObjectByRepr(const_cast(node))); + // transform will be applied later, so default identity is good + Geom::OptRect bounds; + bounds = item ? item->visualBounds() : bounds; + + if (!bounds.empty()) { + node_vec.push_back(Geom::Path(*bounds)); + } else { + // not sure what this is, default to clipping it + return true; + } + } + + Geom::PathVector clip_vec = sp_svg_read_pathv(svgInterpretPath(_clip_history->getClipPath())); + + // Clip transform is compounded with page, node inverse, and node transforms + // Skip the node inverse * node part as it's just identity. + // Also skip the page transform as it should be applied equally to both. + Geom::Affine clip_tr = _clip_history->getAffine(); + Geom::Affine node_tr = Geom::identity(); + if (auto attr = node->attribute("transform")) { + sp_svg_transform_read(attr, &node_tr); + } + + node_vec *= node_tr; + clip_vec *= clip_tr; + + return !pathv_fully_contains(clip_vec, node_vec); +} + Inkscape::XML::Node *SvgBuilder::_createClip(const std::string &d, const Geom::Affine tr, bool even_odd) { + if (_prev_clip) { + // Check if the previous clipping path would be identical to the new one. + auto prev_path = _prev_clip->firstChild(); + std::string prev_d = prev_path->attribute("d"); + std::string prev_tr = prev_path->attribute("transform") ? prev_path->attribute("transform") + : sp_svg_transform_write(Geom::identity()); + bool prev_even_odd = prev_path->attribute("clip-rule") ? prev_path->attribute("clip-rule") == "evenodd" : false; + + // Don't create an identical new clipping path + if (prev_d == d && prev_tr == sp_svg_transform_write(tr) && prev_even_odd == even_odd) { + return _prev_clip; + } + } + Inkscape::XML::Node *clip_path = _xml_doc->createElement("svg:clipPath"); clip_path->setAttribute("clipPathUnits", "userSpaceOnUse"); @@ -843,6 +903,10 @@ Inkscape::XML::Node *SvgBuilder::_createClip(const std::string &d, const Geom::A // Append clipPath to defs and get id _doc->getDefs()->getRepr()->appendChild(clip_path); Inkscape::GC::release(clip_path); + + // update the previous clip path + _prev_clip = clip_path; + return clip_path; } diff --git a/src/extension/internal/pdfinput/svg-builder.h b/src/extension/internal/pdfinput/svg-builder.h index 3cbe5eaea89..ae6b916bcb0 100644 --- a/src/extension/internal/pdfinput/svg-builder.h +++ b/src/extension/internal/pdfinput/svg-builder.h @@ -227,7 +227,8 @@ private: std::vector _mask_groups; int _clip_groups = 0; - Inkscape::XML::Node *_getClip(const Geom::Affine &node_tr); + Inkscape::XML::Node *_getClip(const Inkscape::XML::Node *node); + bool _shouldClip(const Inkscape::XML::Node *node) const; Inkscape::XML::Node *_addToContainer(const char *name); Inkscape::XML::Node *_renderText(std::shared_ptr cairo_font, double font_size, const Geom::Affine &transform, @@ -288,6 +289,9 @@ private: ClipHistoryEntry *_clip_history; // clip path stack Inkscape::XML::Node *_clip_text = nullptr; Inkscape::XML::Node *_clip_text_group = nullptr; + + // Keep track of the previously created clip path + Inkscape::XML::Node *_prev_clip = nullptr; }; diff --git a/src/helper/geom.cpp b/src/helper/geom.cpp index c912d932e6f..7169b65c40e 100644 --- a/src/helper/geom.cpp +++ b/src/helper/geom.cpp @@ -192,6 +192,43 @@ bool pathv_similar(Geom::PathVector const &apv, Geom::PathVector const &bpv, dou return true; } +/* +* Checks if the path describes a simple rectangle, returning true and populating rect if it does. +*/ +bool is_simple_rect(Geom::PathVector const &pathv, Geom::OptRect &rect, double precision) +{ + // "Simple rectangle" is a single path with 4 line segments. + if (pathv.size() != 1) { + return false; + } + + auto const &path = pathv.front(); + // might be a better way to check if all the curves are line segments + if (!path.closed() || path.size() != 4 || + std::any_of(path.begin(), path.end(), [](auto const &curve) { return !curve.isLineSegment(); })) { + return false; + } + + auto p0 = path.initialPoint(); + auto start = p0; + int prev_change = 0; + for (auto const &seg : path) { + auto end = seg.finalPoint(); + // define a change in X as 1, change in Y as -1. Both is 0 + int change = (abs(end[X] - start[X]) < precision ? 0 : 1) + (abs(end[Y] - start[Y]) < precision ? 0 : -1); + if (change == 0 || change == prev_change) { + // Changing in both x and y, or continuing the same direction as the previous segment. + return false; + } + start = end; + prev_change = change; + } + // if we've made it this far, we can assume that the final point of the second segment is the opposite corner + auto p1 = path[1].finalPoint(); + rect = Geom::OptRect(p0, p1); + return true; +} + static void geom_line_wind_distance (Geom::Coord x0, Geom::Coord y0, Geom::Coord x1, Geom::Coord y1, Geom::Point const &pt, int *wind, Geom::Coord *best) { @@ -506,6 +543,43 @@ bool pathvs_have_nonempty_overlap(Geom::PathVector const &a, Geom::PathVector co return false; } +/* + * Checks whether pathvector b is completely within the bounds of pathvector a. + */ +bool pathv_fully_contains(Geom::PathVector const &a, Geom::PathVector const &b) +{ + Geom::OptRect a_bounds; + bool a_is_rect = is_simple_rect(a, a_bounds); + if (!a_is_rect) { + a_bounds = a.boundsExact(); + } + + // At minimum, BBox of a must contain bbox of b + if (!a_bounds.contains(b.boundsExact())) { + return false; + } else if (a_is_rect) { + // If a is a rectangle, then it is the same as its bounding box + return true; + } + + // check winding numbers - all nodes of b need to be contained by a to be fully contained. + // Non-zero winding is a necessary but not sufficient condition. + for (auto &node : b.nodes()) { + if (!a.winding(node)) { + return false; + } + } + + // As in pathvs_have_nonempty_overlap, windings may not account for nodeless Bézier arc intersections. + auto intersections = a.intersect(b); + if (!intersections.empty()) { + return false; + } + + // BBox is fully contained, passed the winding test, no intersections, the path must be contained + return true; +} + /* * Converts all segments in all paths to Geom::LineSegment or Geom::HLineSegment or * Geom::VLineSegment or Geom::CubicBezier. diff --git a/src/helper/geom.h b/src/helper/geom.h index 7213629f096..d837702927e 100644 --- a/src/helper/geom.h +++ b/src/helper/geom.h @@ -29,6 +29,7 @@ void pathv_matrix_point_bbox_wind_distance ( Geom::PathVector const & pathv, Geo Geom::Coord tolerance, Geom::Rect const *viewbox); bool pathvs_have_nonempty_overlap(Geom::PathVector const &a, Geom::PathVector const &b); +bool pathv_fully_contains(Geom::PathVector const &a, Geom::PathVector const &b); // Functions used mostly by LPE's size_t count_pathvector_nodes(Geom::PathVector const &pathv); @@ -41,6 +42,7 @@ Geom::PathVector pathv_to_linear_and_cubic_beziers( Geom::PathVector const &path Geom::PathVector pathv_to_linear( Geom::PathVector const &pathv, double maxdisp ); Geom::PathVector pathv_to_cubicbezier( Geom::PathVector const &pathv, bool nolines); bool pathv_similar(Geom::PathVector const &apv, Geom::PathVector const &bpv, double precission = 0.001); +bool is_simple_rect(Geom::PathVector const &pathv, Geom::OptRect &rect, double precision = 0.001); void recursive_bezier4(const double x1, const double y1, const double x2, const double y2, const double x3, const double y3, const double x4, const double y4, std::vector &pointlist, diff --git a/testfiles/cli_tests/CMakeLists.txt b/testfiles/cli_tests/CMakeLists.txt index 4b8b7ef2fb6..b5e31ff3798 100644 --- a/testfiles/cli_tests/CMakeLists.txt +++ b/testfiles/cli_tests/CMakeLists.txt @@ -940,6 +940,7 @@ add_pdfinput_test(multiple-style-same-text-block 1 keep) add_pdfinput_test(gs_linewidth all draw-all) add_pdfinput_test(XObj_layer all draw-all) add_pdfinput_test(Annot_w_AP all draw-all) +add_pdfinput_test(clipping_shift 1 keep) ########################### ### file format support ### diff --git a/testfiles/cli_tests/testcases/pdfinput/Annot_w_AP_expected.svg b/testfiles/cli_tests/testcases/pdfinput/Annot_w_AP_expected.svg index c4c856aaefd..c2e32a04d32 100644 --- a/testfiles/cli_tests/testcases/pdfinput/Annot_w_AP_expected.svg +++ b/testfiles/cli_tests/testcases/pdfinput/Annot_w_AP_expected.svg @@ -16,392 +16,59 @@ id="defs1"> - - - - - - - - - - - - - - - - - - + id="clipPath9"> + id="path9" /> - - - - - - - - - - - - - - - + id="clipPath15"> - - - - - - - - - - - - - - - + id="path15" /> + id="clipPath21"> - - - - - - - - - - - - - - - - - - + id="path21" /> + id="clipPath28"> - - - - - - - - - - - - - - - - - - + id="path28" /> + id="clipPath35"> - - - - - - - - - - - - - - - - - - - - - + id="path35" /> + id="clipPath42"> - - - - - - - - - - - - - - - + id="path42" /> + id="clipPath49"> - - - - - - - - - - - - - - - - - - + id="path49" /> + transform="matrix(1.3333333,0,0,-1.3333333,27.50688,900.25181)" /> + transform="matrix(1.3333333,0,0,-1.3333333,536.10608,900.25181)" /> + transform="matrix(1.3333333,0,0,-1.3333333,295.03475,456.10035)" /> + transform="matrix(1.3333333,0,0,-1.3333333,529.36555,456.10035)" /> + transform="matrix(1.3333333,0,0,-1.3333333,295.03475,871.84795)" /> + transform="matrix(1.3333333,0,0,-1.3333333,529.36555,871.84795)" /> + id="g14"> 2,00 mm + id="tspan9">2,00 mm + id="path10" /> + id="path11" /> + id="path12" /> + id="path13" /> + id="path14" /> + id="g20"> 3,00 mm + id="tspan15">3,00 mm + id="path16" /> + id="path17" /> + id="path18" /> + id="path19" /> + id="path20" /> + id="g27"> 135,00 mm + id="tspan21">135,00 mm + id="path22" /> + id="path23" /> + id="path24" /> + id="path25" /> + id="path26" /> + id="path27" /> + id="g34"> 217,00 mm + id="tspan28">217,00 mm + id="path29" /> + id="path30" /> + id="path31" /> + id="path32" /> + id="path33" /> + id="path34" /> + id="g41"> 60,00 mm + id="tspan35">60,00 mm + id="path36" /> + id="path37" /> + id="path38" /> + id="path39" /> + id="path40" /> + id="path41" /> + id="g48"> + id="path43" /> 73,00 mm + id="tspan43">73,00 mm + id="path44" /> + id="path45" /> + id="path46" /> + id="path47" /> + id="path48" /> + id="g55"> 107,00 mm + id="tspan49">107,00 mm + id="path50" /> + id="path51" /> + id="path52" /> + id="path53" /> + id="path54" /> + id="path55" /> diff --git a/testfiles/cli_tests/testcases/pdfinput/clipping_shift.pdf b/testfiles/cli_tests/testcases/pdfinput/clipping_shift.pdf new file mode 100644 index 00000000000..c9961e88412 --- /dev/null +++ b/testfiles/cli_tests/testcases/pdfinput/clipping_shift.pdf @@ -0,0 +1,152 @@ +%PDF-1.3 +%¿÷¢þ +1 0 obj +<< /Pages 2 0 R /Type /Catalog >> +endobj +2 0 obj +<< /Count 1 /Kids [ 3 0 R ] /Type /Pages >> +endobj +3 0 obj +<< /Contents [ 4 0 R 5 0 R ] /MediaBox [ 0 0 612 792 ] /Parent 2 0 R /Resources << /Font << /F1 6 0 R >> >> /Type /Page >> +endobj +4 0 obj +<< /Length 0 >> +stream + +endstream +endobj +5 0 obj +<< /Length 1849 >> +stream +% page size [0, 0, 612, 792] +q +100 100 300 300 re +W % define clipping path +s % also stroke it +0 0 m +1 0 0 RG +1 0 0 rg +200 200 l % a clipped line +s +0 0 1 RG % blue stroke to show unclipped lines +150 200 m +150 300 l % clipping path has no effect +s +q +1 0 0 1 10 10 cm % tiny silly shift +150 200 m +150 300 l % clipping path has no effect +s +1 0 0 1 10 10 cm % another tiny silly shift +150 200 m +150 300 l % clipping path has no effect +s +BT +/F1 12 Tf +110 110 Td +( Unclipped Text ) Tj +ET +Q +1 0 0 RG % red stroke to show shifted stuff +1 0 0 1 150 50 cm % shift the origin +100 100 300 300 re % redraw the same rectangle +s +0 0 m +200 200 l % and clipped line +s +0.75 0 1 RG % purple to show shifted unclipped lines +0.75 0 1 rg +150 200 m +150 300 l % clipping path has no effect +s +q +1 0 0 1 10 10 cm % tiny silly shift +150 200 m +150 300 l % clipping path has no effect +s +1 0 0 1 10 10 cm % another tiny silly shift +150 200 m +150 300 l % clipping path has no effect +s +BT +/F1 12 Tf +110 110 Td +( Unclipped Text ) Tj +ET +Q +Q +q +% a new clipping path with a funky shape +1 0 0 1 0 300 cm +300.852 324 m +171.863 312.695 l +128.094 366.84 l +162 270 l +85.254 194.086 l +177.996 253.582 235.582 239.305 258.008 151.246 c +254.703 221.414 224.117 311.098 300.852 324 c +h +300.852 324 m +W +s % stroke and clip the path +1 0 0 RG % red lines are clipped +275 300 m +200 300 l % clipped just by curved path +s +BT +/F1 12 Tf +200 300 Td +( Clipped by curve ) Tj +ET +200 250 m +100 250 l % clipped by straight path +s +BT +/F1 12 Tf +100 250 Td +( Clipped by straight line ) Tj +ET +0 0 1 RG % blue lines are not clipped +220 250 m +200 275 l % no clip +s +Q +BT +/F1 12 Tf +400 720 Td +( Black: Clipping paths ) Tj +ET +1 0 0 rg +BT +/F1 12 Tf +400 700 Td +( Red: Clipped lines ) Tj +ET +0 0 1 rg +BT +400 680 Td +( Blue: Unclipped lines ) Tj +ET +0.75 0 1 rg +BT +400 660 Td +( Purple: Shifted unclipped lines ) Tj +ET +endstream +endobj +6 0 obj +<< /BaseFont /Helvetica /Subtype /Type1 /Type /Font >> +endobj +xref +0 7 +0000000000 65535 f +0000000015 00000 n +0000000064 00000 n +0000000123 00000 n +0000000261 00000 n +0000000310 00000 n +0000002211 00000 n +trailer << /Root 1 0 R /Size 7 /ID [] >> +startxref +2281 +%%EOF diff --git a/testfiles/cli_tests/testcases/pdfinput/clipping_shift_expected.svg b/testfiles/cli_tests/testcases/pdfinput/clipping_shift_expected.svg new file mode 100644 index 00000000000..2f31e971ce1 --- /dev/null +++ b/testfiles/cli_tests/testcases/pdfinput/clipping_shift_expected.svg @@ -0,0 +1,228 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unclipped Text + + + + + + Unclipped Text + + + Clipped by curve + + Clipped by straight line + + Black: Clipping paths + Red: Clipped lines + Blue: Unclipped lines + Purple: Shifted unclipped lines + + diff --git a/testfiles/cli_tests/testcases/pdfinput/gs_linewidth_expected.svg b/testfiles/cli_tests/testcases/pdfinput/gs_linewidth_expected.svg index a728e09b1db..95adf82ba84 100644 --- a/testfiles/cli_tests/testcases/pdfinput/gs_linewidth_expected.svg +++ b/testfiles/cli_tests/testcases/pdfinput/gs_linewidth_expected.svg @@ -13,44 +13,7 @@ xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"> - - - - - - - - - - - - - + id="defs1" /> + transform="matrix(1.0008984,0,0,1.0008984,37.333331,37.333331)" /> + transform="matrix(1.0008984,0,0,1.0008984,45.340516,45.340516)" /> + transform="matrix(1.0008984,0,0,1.0008984,45.340516,45.340516)" /> + transform="matrix(1.0008984,0,0,1.0008984,45.340516,45.340516)" /> diff --git a/testfiles/cli_tests/testcases/pdfinput/multi-page-sample_expected.svg b/testfiles/cli_tests/testcases/pdfinput/multi-page-sample_expected.svg index 82b8547db64..150c7272949 100644 --- a/testfiles/cli_tests/testcases/pdfinput/multi-page-sample_expected.svg +++ b/testfiles/cli_tests/testcases/pdfinput/multi-page-sample_expected.svg @@ -37,80 +37,6 @@ transform="matrix(0.00797433,0,0,0.00798299,-1.742515,-3.2814372)" id="path2" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + id="radialGradient14"> + id="stop12" /> + id="stop13" /> + id="stop14" /> - - - - - - + id="linearGradient20"> + id="stop18" /> + id="stop19" /> + id="stop20" /> + id="linearGradient24"> + id="stop21" /> + id="stop22" /> + id="stop23" /> + id="stop24" /> + id="mask28" /> + id="linearGradient29"> + id="stop28" /> + id="stop29" /> + id="clipPath29"> + id="path29" /> + id="linearGradient31"> + id="stop30" /> + id="stop31" /> - - - + id="clipPath32"> - - - - - - + id="path32" /> - - - - - + id="pattern34"> - + d="m 10000,10000 0,-5000 -5000,5000 5000,0 z M 5000,0 5000,5000 10000,0 5000,0 Z M 0,0 5000,5000 5000,10000 0,5000 0,0 Z" + style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" + opacity="1" + id="path34" /> + + id="clipPath36"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + id="path36" /> + id="clipPath37"> + id="path37" /> - - - - - - + id="clipPath106"> + id="path106" /> + id="clipPath108"> + id="path108" /> + id="clipPath109"> + id="path109" /> - - - - - - + id="clipPath114"> + id="path114" /> + id="mask114"> + clip-path="url(#clipPath116)" /> + id="mask115"> + id="image115" /> + id="clipPath116"> + id="path116" /> + id="linearGradient117"> + id="stop116" /> + id="stop117" /> + id="clipPath117"> + id="path117" /> + id="clipPath118"> + id="path118" /> + id="clipPath120"> + id="path120" /> + id="clipPath121"> + id="path121" /> + id="clipPath122"> + id="path122" /> + id="clipPath123"> + id="path123" /> + id="clipPath124"> + id="path124" /> + id="clipPath125"> + id="path125" /> + id="clipPath126"> + id="path126" /> + id="clipPath127"> + id="path127" /> + id="clipPath132"> - - - - - - - - - + id="path132" /> + id="clipPath133"> + id="path133" /> - - - - - - - - - + id="clipPath141"> + id="path141" /> + id="mask141"> + clip-path="url(#clipPath143)" /> + id="mask142"> + id="image142" /> + id="clipPath143"> + id="path143" /> + id="clipPath144"> + id="path144" /> + id="clipPath145"> + id="path145" /> + id="mask147"> + clip-path="url(#clipPath149)" /> + id="mask148"> + id="image148" /> + id="clipPath149"> + id="path149" /> + id="clipPath150"> + id="path150" /> + id="clipPath151"> + id="path151" /> @@ -840,795 +553,759 @@ id="image2" transform="matrix(167.20323,0,0,167.02187,291.35413,548.07177)" clip-path="url(#clipPath2)" /> - - - - + - - - + - - + id="path5" /> + id="g7"> + id="path6" /> + id="path7" /> + id="g11"> + id="path10" /> + id="path11" /> - - - + id="path12" /> + id="g16"> + id="path14" /> + id="path15" /> + id="path16" /> - - - + id="path17" /> + style="fill:url(#linearGradient24);stroke:none" /> + id="g31" + clip-path="url(#clipPath32)"> + id="path31" /> - - - - + - - + id="path35" /> + id="image35" + clip-path="url(#clipPath36)" /> + id="g38"> + clip-path="url(#clipPath37)" + id="path38" /> + id="g39"> + id="g40"> + clip-path="url(#clipPath37)" + id="path39" /> + id="g41"> + id="g50"> + clip-path="url(#clipPath37)" + id="path41" /> + clip-path="url(#clipPath37)" + id="path42" /> + clip-path="url(#clipPath37)" + id="path43" /> + clip-path="url(#clipPath37)" + id="path44" /> + clip-path="url(#clipPath37)" + id="path45" /> + clip-path="url(#clipPath37)" + id="path46" /> + clip-path="url(#clipPath37)" + id="path47" /> + clip-path="url(#clipPath37)" + id="path48" /> + clip-path="url(#clipPath37)" + id="path49" /> + clip-path="url(#clipPath37)" + id="path50" /> + id="g51"> + clip-path="url(#clipPath37)" + id="path51" /> + id="g53"> + clip-path="url(#clipPath37)" + id="path53" /> + id="g104"> + id="g108" + clip-path="url(#clipPath108)"> + id="g107"> + clip-path="url(#clipPath106)" + id="path107" /> + id="g110"> + clip-path="url(#clipPath109)" + id="path110" /> + id="g111"> + clip-path="url(#clipPath109)" + id="path111" /> + id="g112" /> + id="g114" + clip-path="url(#clipPath114)"> + id="g113"> + clip-path="url(#clipPath109)" + id="path112" /> + mask="url(#mask114)" + id="g120"> + clip-path="url(#clipPath118)" + id="g119"> + clip-path="url(#clipPath117)" + id="path119" /> + id="g132" + clip-path="url(#clipPath132)"> + clip-path="url(#clipPath121)" + id="g128"> + clip-path="url(#clipPath120)" + id="path128" /> + clip-path="url(#clipPath123)" + id="g129"> + clip-path="url(#clipPath122)" + id="path129" /> + clip-path="url(#clipPath125)" + id="g130"> + clip-path="url(#clipPath124)" + id="path130" /> + clip-path="url(#clipPath127)" + id="g131"> + clip-path="url(#clipPath126)" + id="path131" /> + id="g134"> + clip-path="url(#clipPath133)" + id="path134" /> + id="g135"> + clip-path="url(#clipPath133)" + id="path135" /> + id="g136"> + clip-path="url(#clipPath133)" + id="path136" /> + id="g137"> + clip-path="url(#clipPath133)" + id="path137" /> + id="g138"> + clip-path="url(#clipPath133)" + id="path138" /> + id="g139"> + clip-path="url(#clipPath133)" + id="path139" /> + id="g140" + clip-path="url(#clipPath141)"> + clip-path="url(#clipPath133)" + id="path140" /> + mask="url(#mask141)" + id="g147"> + clip-path="url(#clipPath145)" + id="g146"> + clip-path="url(#clipPath144)" + id="path146" /> + mask="url(#mask147)" + id="g153"> + clip-path="url(#clipPath151)" + id="g152"> + clip-path="url(#clipPath150)" + id="path152" /> diff --git a/testfiles/cli_tests/testcases/pdfinput/transparency-groups_expected.svg b/testfiles/cli_tests/testcases/pdfinput/transparency-groups_expected.svg index c142fb87c9d..48759219e4d 100644 --- a/testfiles/cli_tests/testcases/pdfinput/transparency-groups_expected.svg +++ b/testfiles/cli_tests/testcases/pdfinput/transparency-groups_expected.svg @@ -17,54 +17,10 @@ - - - - - - - - - - - - - - - - - - + id="path1" /> + id="g5"> + clip-path="url(#clipPath1)" + id="g4"> - + - - + id="path2" /> + id="path3" /> + id="path4" /> + id="path5" /> -- GitLab