From d79da3d0f945729ccba28b477fb2035e91041460 Mon Sep 17 00:00:00 2001
From: Viatrix
Date: Thu, 12 Mar 2026 20:28:27 -0700
Subject: Links going out of bounds now get cropped.
---
imagemap.py | 19 +++++++++++++++++--
.../data/refs/imagemap__--maptype__HTML__oob__svg.out | 1 +
tests/data/svg/oob.svg | 5 +++++
tests/test_imagemap_comparison.py | 1 +
4 files changed, 24 insertions(+), 2 deletions(-)
create mode 100644 tests/data/refs/imagemap__--maptype__HTML__oob__svg.out
create mode 100644 tests/data/svg/oob.svg
diff --git a/imagemap.py b/imagemap.py
index 30d0399..9a6b9c7 100644
--- a/imagemap.py
+++ b/imagemap.py
@@ -2,6 +2,7 @@ import inkex
from inkex import bezier
from inkex.command import inkscape_command
from inkex.localization import inkex_gettext as _
+from lxml.builder import E
# (X)HTML stuff:
ESCAPE=str.maketrans({'&':'&','<':'<','>':'>'})
@@ -54,9 +55,10 @@ 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, and be visually unaffected by `fill-rule`.
+ # 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
links=[]
+ rects=[]
svgIDs=[i.get_id() for i in self.svg.iterdescendants('{http://www.w3.org/2000/svg}svg')]
for a in self.svg.iterdescendants('{http://www.w3.org/2000/svg}a'):
# save link attributes because they get removed when flattening
@@ -70,11 +72,24 @@ class ImageMap(inkex.OutputExtension):
style['stroke']='none'
style['fill']='#000'
links += [link]
+
+ # for clipping out-of-bounds elements
+ newid=self.svg.get_unique_id('intersect')
+ rect=E('{http://www.w3.org/2000/svg}rect',
+ x=str(viewBox[0]),
+ y=str(viewBox[1]),
+ width='100%',
+ height='100%',
+ style='fill:#000;stroke:none',
+ id=newid)
+ self.svg.append(rect)
+ rects+=[newid]
+
if len(links)==0:
raise inkex.AbortExtension(_("Image has no hyperlinks.\nAdd a hyperlink to an object with right-click → \"{}\".").format(_("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-selector:[style~="{CSS_LINK_INDEX}-{i}"];object-stroke-to-path;selection-ungroup;path-union;object-set-attribute:style,{CSS_LINK_INDEX}:" {CSS_LINK_INDEX}-{i} ";' for i in range(len(links))) \
+ +''.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)
newbytes=inkscape_command(self.svg,actions=command)
diff --git a/tests/data/refs/imagemap__--maptype__HTML__oob__svg.out b/tests/data/refs/imagemap__--maptype__HTML__oob__svg.out
new file mode 100644
index 0000000..e62f2b7
--- /dev/null
+++ b/tests/data/refs/imagemap__--maptype__HTML__oob__svg.out
@@ -0,0 +1 @@
+
diff --git a/tests/data/svg/oob.svg b/tests/data/svg/oob.svg
new file mode 100644
index 0000000..d46ee63
--- /dev/null
+++ b/tests/data/svg/oob.svg
@@ -0,0 +1,5 @@
+
diff --git a/tests/test_imagemap_comparison.py b/tests/test_imagemap_comparison.py
index 445f981..994bc95 100644
--- a/tests/test_imagemap_comparison.py
+++ b/tests/test_imagemap_comparison.py
@@ -8,6 +8,7 @@ class ImageMapComparisonTest(ComparisonMixin, TestCase):
'svg/fillstroke.svg',
'svg/image.svg',
'svg/intersect.svg',
+ 'svg/oob.svg',
'svg/overlap.svg',
'svg/rounding.svg',
'svg/text.svg',
--
cgit