diff options
| author | Viatrix | 2026-03-16 17:48:48 -0700 |
|---|---|---|
| committer | Viatrix | 2026-03-16 17:53:39 -0700 |
| commit | 90246c78b9b0a5c736c574d7d95159fbfe74c597 (patch) | |
| tree | ca8696918acdf1913576cd5994989479cdce76a9 | |
| parent | fbcbb4eff55d0703f9fee526e5caea4744e931f7 (diff) | |
Clip-paths now work!
| -rw-r--r-- | imagemap.py | 19 | ||||
| -rw-r--r-- | tests/data/refs/imagemap__--maptype__HTML__clip-path__svg.out | 3 | ||||
| -rw-r--r-- | tests/data/svg/clip-path.svg | 24 | ||||
| -rw-r--r-- | tests/test_imagemap_comparison.py | 1 |
4 files changed, 45 insertions, 2 deletions
diff --git a/imagemap.py b/imagemap.py index 3595323..9eb4132 100644 --- a/imagemap.py +++ b/imagemap.py @@ -62,8 +62,7 @@ class ImageMap(inkex.OutputExtension): hscale=self.svg.viewport_height/viewBox[3] if viewBox[3]!=0 else 1 # preprocess shapes for our purposes. - # after this, the shapes within the image must: look the same as before (barring colour/alpha), not be clones, have no stroke, not intersect, be visually unaffected by `fill-rule`, and not go out of bounds. - # TODO pay attention to clip-path + # after this, the shapes within the image must: look the same as before (barring colour/alpha), not be clones, have no stroke, not intersect, be visually unaffected by `fill-rule`, not be clipped, and not go out of bounds. links=[] rects=[] svgIDs=[i.get_id() for i in self.svg.iterdescendants('{http://www.w3.org/2000/svg}svg')] @@ -92,13 +91,29 @@ class ImageMap(inkex.OutputExtension): self.svg.append(rect) rects+=[newid] + #clip-paths + clipped=[] + clippedpaths=set() + for clippedEl in self.svg.iterdescendants(): + if not isinstance(clippedEl,inkex.BaseElement): continue + if clippedEl.cascaded_style().get('clip-path','none')=='none': continue + clipped.append([clippedEl.get_id(),0]) + for el in clippedEl.descendants(): + if not isinstance(el,inkex.ShapeElement) or isinstance(el,inkex.elements._groups.GroupBase): + clipped[-1][1]+=1 # can overshoot number of groups but works + continue + clippedpaths.add((el.get_id(),el.cascaded_style().get(CSS_LINK_INDEX))) + if len(links)==0: raise inkex.AbortExtension(_("Image has no hyperlinks.\nAdd a hyperlink to an object with right-click → \"{}\".").format(_i("Create Anchor (Hyperlink)"))) command=\ ''.join(f'select-clear;select-by-id:{i};selection-ungroup;' for i in reversed(svgIDs)) \ + +''.join(f'select-clear;select-by-id:{i[0]};{"selection-ungroup;"*i[1]}' for i in reversed(clipped) if i[1]>0) \ + +''.join(f'select-clear;select-by-id:{i[0]};object-release-clip;unselect-by-id:{i[0]};selection-set-backup;select-clear;select-by-id:{i[0]};object-stroke-to-path;selection-ungroup;path-union;object-set-attribute:id,{i[0]};selection-restore-backup;select-by-id:{i[0]};path-intersection;object-set-attribute:style,{CSS_LINK_INDEX}:{i[1]};' for i in clippedpaths) \ +''.join(f'select-clear;select-by-selector:[style~="{CSS_LINK_INDEX}-{i}"];object-stroke-to-path;selection-ungroup;path-union;select-by-id:{rects[i]};path-intersection;object-set-attribute:style,{CSS_LINK_INDEX}:" {CSS_LINK_INDEX}-{i} ";' for i in range(len(links))) \ +'select-all;path-flatten;path-split' # (we re-set the existing style attribute in case it got unset on non-paths) + from lxml import etree newbytes=inkscape_command(self.svg,actions=command) self.svg=self.load(newbytes).getroot() # preprocessing done, now for map generation diff --git a/tests/data/refs/imagemap__--maptype__HTML__clip-path__svg.out b/tests/data/refs/imagemap__--maptype__HTML__clip-path__svg.out new file mode 100644 index 0000000..4cd2339 --- /dev/null +++ b/tests/data/refs/imagemap__--maptype__HTML__clip-path__svg.out @@ -0,0 +1,3 @@ +<area shape=poly coords=25,25,25,75,50,50 href=http://example.com/1> +<area shape=poly coords=127,27,150,50,127,73,173,73,173,27 href=http://example.com/2> +<area shape=poly coords=230,30,250,50,230,70,270,70,270,30 href=http://example.com/3> diff --git a/tests/data/svg/clip-path.svg b/tests/data/svg/clip-path.svg new file mode 100644 index 0000000..c3b6f7d --- /dev/null +++ b/tests/data/svg/clip-path.svg @@ -0,0 +1,24 @@ +<svg width="300" height="100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <clipPath id="slice" clipPathUnits="userSpaceOnUse"> + <polyline points="25,25 50,50 25,75"/> + </clipPath> + <clipPath id="antislice" clipPathUnits="userSpaceOnUse"> + <polyline points="125,25 150,50 125,75 175,75 175,25"/> + </clipPath> + <clipPath id="antislice2" clipPathUnits="userSpaceOnUse"> + <polyline points="225,25 250,50 225,75 275,75 275,25"/> + </clipPath> + </defs> + <a xlink:href="http://example.com/1"> + <rect x="25" y="25" width="50" height="50" clip-path="url(#slice)"/> + </a> + <a xlink:href="http://example.com/2" clip-path="url(#antislice)"> + <rect x="130" y="30" width="40" height="40" stroke-width="6" stroke="lime"/> + </a> + <g clip-path="url(#antislice2)"> + <a xlink:href="http://example.com/3"> + <rect x="230" y="30" width="40" height="40"/> + </a> + </g> +</svg> diff --git a/tests/test_imagemap_comparison.py b/tests/test_imagemap_comparison.py index 4b734b8..e5b59a1 100644 --- a/tests/test_imagemap_comparison.py +++ b/tests/test_imagemap_comparison.py @@ -5,6 +5,7 @@ class ImageMapComparisonTest(ComparisonMixin, TestCase): effect_class = ImageMap compare_file = ( 'svg/alt.svg', + 'svg/clip-path.svg', 'svg/enclave.svg', 'svg/fillstroke.svg', 'svg/group.svg', |
