I'm trying to use Beautiful soup to create a looping SVG animation.
I have four svgs created from the same picture with some nodes adjusted. I'm trying to find all the path tags that share the same id between each of the 4 svgs, but which contain different values for the d attribute.
If you run the program on the svgs at this repo it looks like I'm animating the a change between the first and second picture, but then the animation stops, and also the first picture is still behind the second picture.
I would like this program to create a looping svg animation from the 4 svgs that I give as input to it
from bs4 import BeautifulSoup
from re import compile
def handler_from_file(filename):
html = open(filename, 'r')
return BeautifulSoup(html, 'xml')
def group(svgs):
"""The first svg is a base img. Adds additional svgs as animation tags
Args:
svgs ([[string, int]]): [[svg filename, length of animation]]
"""
base = handler_from_file(svgs[0][0])
tags = base.find_all('path')
soups = [handler_from_file(name) for [name, dur] in svgs]
durs = [svg[1] for svg in svgs]
for tag in tags:
id = tag.get('id')
d = tag.get('d')
if not id:
continue
matches = [x for x in [s.find('path', id=id) for s in soups] if x is not None]
if (len(matches) == 0):
continue
ds = [mch.get('d') for mch in matches]
if (len(set(ds + [d])) == 1):
continue
# print(f"ds: {len(ds)}, durs: {len(durs)}, range: {range(1,len(ds))} ")
for cnt in range(1,len(ds)):
animId = f"{id}-{str(cnt)}"
animate = base.new_tag('animate', id=animId)
animate.attrs['to'] = ds[cnt]
animate.attrs['attributeName'] = 'd'
animate.attrs['dur'] = f"{durs[cnt]}ms"
animate.attrs['fill'] = "freeze"
if cnt == 1: #If this is the first animation layer
animate.attrs['begin'] = f"0s;{id}-{str(len(ds) - 1)}.end" #start the animation at 0s, and the end of the last animation(loops)
else:
animate.attrs['begin'] = f"{id}-{str(cnt - 1)}.end" #start the animation at the end of the previous animation
tag.append(animate)
return base
def write(output, svg):
with open(output, "w") as file:
file.write(str(svg))
svgs = [
["./trombone.svg", 1000],
["./trombone2.svg", 1000],
["./trombone3.svg", 1000],
["./trombone4.svg", 1000],
]
output="trombone-anim.svg"
animation = group(svgs)
write(output, animation)
from Using Beautiful soup to create a looping svg animation from multiple svg frames
No comments:
Post a Comment