Skip to content

Commit da7e82f

Browse files
committed
Check for negative SVG dimensions (#167).
1 parent 414214a commit da7e82f

2 files changed

Lines changed: 20 additions & 5 deletions

File tree

mapmaker/sources/svg/__init__.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
from .styling import StyleMatcher, wrap_element
5858
from .transform import SVGTransform
5959
from .utils import circle_from_bounds, geometry_from_svg_path, length_as_pixels
60-
from .utils import length_as_points, svg_markup, parse_svg_path, SVG_TAG
60+
from .utils import check_non_negative, length_as_points, svg_markup, parse_svg_path, SVG_TAG
6161

6262
#===============================================================================
6363

@@ -451,6 +451,7 @@ def __get_geometry(self, element, properties, transform) -> Optional[BaseGeometr
451451
##
452452
## Returns path element as a `shapely` object.
453453
##
454+
element_id = properties.get('id')
454455
path_tokens = []
455456
if element.tag == SVG_TAG('path'):
456457
path_tokens = list(parse_svg_path(element.attrib.get('d', '')))
@@ -460,18 +461,20 @@ def __get_geometry(self, element, properties, transform) -> Optional[BaseGeometr
460461
y = length_as_pixels(element.attrib.get('y', 0))
461462
width = length_as_pixels(element.attrib.get('width', 0))
462463
height = length_as_pixels(element.attrib.get('height', 0))
463-
rx = length_as_pixels(element.attrib.get('rx'))
464-
ry = length_as_pixels(element.attrib.get('ry'))
464+
width = check_non_negative(width, 'rect', 'width', element_id)
465+
height = check_non_negative(height, 'rect', 'height', element_id)
465466
if width == 0 or height == 0: return None
466467

468+
rx = length_as_pixels(element.attrib.get('rx'))
469+
ry = length_as_pixels(element.attrib.get('ry'))
467470
if rx is None and ry is None:
468471
rx = ry = 0
469472
elif ry is None:
470473
ry = rx
471474
elif rx is None:
472475
rx = ry
473-
rx = min(rx, width/2)
474-
ry = min(ry, height/2)
476+
rx = check_non_negative(rx, 'rect', 'x-radius', element_id)
477+
ry = check_non_negative(ry, 'rect', 'y-radius', element_id)
475478
if rx == 0 and ry == 0:
476479
path_tokens = ['M', x, y,
477480
'H', x+width,
@@ -480,6 +483,8 @@ def __get_geometry(self, element, properties, transform) -> Optional[BaseGeometr
480483
'V', y,
481484
'Z']
482485
else:
486+
rx = min(rx, width/2)
487+
ry = min(ry, height/2)
483488
path_tokens = ['M', x+rx, y,
484489
'H', x+width-rx,
485490
'A', rx, ry, 0, 0, 1, x+width, y+ry,
@@ -510,6 +515,7 @@ def __get_geometry(self, element, properties, transform) -> Optional[BaseGeometr
510515
cx = length_as_pixels(element.attrib.get('cx', 0))
511516
cy = length_as_pixels(element.attrib.get('cy', 0))
512517
r = length_as_pixels(element.attrib.get('r', 0))
518+
r = check_non_negative(r, 'circle', 'radius', element_id)
513519
if r == 0: return None
514520
path_tokens = ['M', cx+r, cy,
515521
'A', r, r, 0, 0, 0, cx, cy-r,
@@ -523,6 +529,8 @@ def __get_geometry(self, element, properties, transform) -> Optional[BaseGeometr
523529
cy = length_as_pixels(element.attrib.get('cy', 0))
524530
rx = length_as_pixels(element.attrib.get('rx', 0))
525531
ry = length_as_pixels(element.attrib.get('ry', 0))
532+
rx = check_non_negative(rx, 'ellipse', 'x-radius', element_id)
533+
ry = check_non_negative(ry, 'ellipse', 'y-radius', element_id)
526534
if rx == 0 or ry == 0: return None
527535
path_tokens = ['M', cx+rx, cy,
528536
'A', rx, ry, 0, 0, 0, cx, cy-ry,

mapmaker/sources/svg/utils.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,13 @@ def SVG_TAG(tag): # An SVG namespaced lxml.etree tag
8181
'ex': None, # ex/pt depends on current font size
8282
}
8383

84+
def check_non_negative(length: float, element: str, what: str, id: Optional[str]) -> float:
85+
#==========================================================================================
86+
if length < 0:
87+
length = 0
88+
log.warning(f'Unexpected negative {what} for `{element}` element', id=id)
89+
return length
90+
8491
def length_as_pixels(length: str | float) -> float:
8592
#==================================================
8693
if not isinstance(length, str):

0 commit comments

Comments
 (0)