aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorViatrix2026-03-16 17:48:48 -0700
committerViatrix2026-03-16 17:53:39 -0700
commit90246c78b9b0a5c736c574d7d95159fbfe74c597 (patch)
treeca8696918acdf1913576cd5994989479cdce76a9
parentfbcbb4eff55d0703f9fee526e5caea4744e931f7 (diff)
Clip-paths now work!
-rw-r--r--imagemap.py19
-rw-r--r--tests/data/refs/imagemap__--maptype__HTML__clip-path__svg.out3
-rw-r--r--tests/data/svg/clip-path.svg24
-rw-r--r--tests/test_imagemap_comparison.py1
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',