Here is an example of cropping SVG throgh viewBox
attribute.
def verify_bbox(bbox):
if not isinstance(bbox, (tuple, list)):
raise TypeError(f"Bounding box should be a tuple or list, got {type(bbox)}")
if len(bbox) != 4:
raise ValueError(f"Bounding box should have 4 values [left, top, right, bottom], got {len(bbox)}")
for b in bbox:
if not isinstance(b,(int,float)) or b < 0 or b > 1:
raise ValueError(f"Bounding box values should be between 0 and 1, got {b}")
def crop_svg(svg, bbox):
verify_bbox(bbox) # left, top, right, bottom in 0-1 range
def crop_viewbox(m):
vb, *_ = m.groups()
x,y,w,h = [int(v) for v in vb.split()]
X, Y = bbox[0]*w + x, bbox[1]*h + y # offset by original viewbox
W, H = (bbox[2] - bbox[0])*w, (bbox[3] - bbox[1])*h
return m.group().replace(vb, f'{X} {Y} {W} {H}') # Replace viewbox with new values
return re.sub(r'viewBox\=[\"\'](.*?)[\"\']', crop_viewbox, svg ,1)
svg = '''<svg xmlns="http://www.w3.org/2000/svg" height="50px" viewBox="0 0 25 25" fill="red" stroke-width="2" transform="rotate(45)">\n <rect x="9" y="0" width="8" height="6"/>\n <rect x="9" y="7" width="1" height="10"/>\n <rect x="12" y="7" width="2" height="10"/>\n <rect x="16" y="7" width="1" height="10"/>\n <polygon points="9 18,17 18,13 25,9 18"></polygon>\n</svg>'''
crop_svg(svg, [0.5,0,1,1])
'<svg xmlns="http://www.w3.org/2000/svg" height="50px" viewBox="12.5 0 12.5 25" fill="red" stroke-width="2" transform="rotate(45)">\n <rect x="9" y="0" width="8" height="6"/>\n <rect x="9" y="7" width="1" height="10"/>\n <rect x="12" y="7" width="2" height="10"/>\n <rect x="16" y="7" width="1" height="10"/>\n <polygon points="9 18,17 18,13 25,9 18"></polygon>\n</svg>'
There are two things to be noted:
height
or width
should be 'auto'
or missing to view correctly or both reset accordingly. You can add following line:re.sub(r'height\=[\"\'](.*?)[\"\']', 'height="auto"', svg,1)