Skip to content

SVG: support <use> in <clipPath> and <clipPath> outside <defs>, as Illustrator writes them - #2145

Open
RavSinghChandan wants to merge 4 commits into
py-pdf:masterfrom
RavSinghChandan:svg-clip-path-outside-defs
Open

RavSinghChandan wants to merge 4 commits into
py-pdf:masterfrom
RavSinghChandan:svg-clip-path-outside-defs

Conversation

@RavSinghChandan

Copy link
Copy Markdown

Adobe Illustrator writes every clip path like this, next to the elements it clips rather than in <defs>:

<g>
  <defs><rect id="SVGID_1_" width="50" height="50"/></defs>
  <clipPath id="SVGID_2_"><use xlink:href="#SVGID_1_" overflow="visible"/></clipPath>
  <path clip-path="url(#SVGID_2_)" d="..."/>
</g>

fpdf2 ignores both the <clipPath> outside <defs> ("Ignoring unsupported SVG tag: ") and the <use> inside it ("Ignoring unsupported child tag: "), so the clip path is never registered and every element that uses it fails with KeyError: '#SVGID_2_'. The six file-type icons in PyMuPDF's documentation (docs/images/icons/icon-pdf.svg etc.) all fail this way.

  • A <clipPath> found among the children of a group is now handled like one in <defs> (the shared code moved to build_clip_path_tag()); it is never rendered directly.
  • A <use> in a <clipPath> now adds the shape or path it references, with its x/y and transform applied as SVG specifies (translate(x, y) first, like build_xref() does). A <use> that references another <use> or a group is still ignored with a warning: the spec only allows shapes, text and paths there.

The six PyMuPDF icons render correctly with this change (checked visually).

Added test_svg_clip_path_outside_defs, test_svg_clip_path_with_use, test_svg_clip_path_with_use_placement and test_svg_clip_path_unsupported_child; the first three fail on master, and the new code is fully covered. pytest test/svg test/drawing, black, pylint and mypy pass

@andersonhc

Copy link
Copy Markdown
Collaborator

pylint is failint:

************* Module test.svg.test_svg
test/svg/test_svg.py:324:0: W1404: Implicit string concatenation found in list (implicit-str-concat)
test/svg/test_svg.py:326:0: W1404: Implicit string concatenation found in list (implicit-str-concat)

@RavSinghChandan
RavSinghChandan force-pushed the svg-clip-path-outside-defs branch from 9ae7327 to 78b4437 Compare November 10, 2026 04:01
@RavSinghChandan

Copy link
Copy Markdown
Author

Thanks, fixed: the concatenated strings in that parametrize list are now in parentheses, and pylint passes on the test file. I also rebased on master.

Comment thread fpdf/svg.py

@force_nodocument
def build_clipping_path(self, shape: "Element", clip_id: Optional[str]) -> None:
clipping_path_shape = self._clipping_path_shape(shape)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When references a , this helper returns a PaintedPath rather than a ClippingPath

@RavSinghChandan
RavSinghChandan force-pushed the svg-clip-path-outside-defs branch from 78b4437 to 74de58c Compare November 10, 2026 12:59
@RavSinghChandan
RavSinghChandan force-pushed the svg-clip-path-outside-defs branch from 74de58c to e4717a7 Compare November 10, 2026 14:10

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants