Closed gavytron closed 2 years ago
I'm not able to reproduce this problem with Inkscape 1.3-dev (ab263b1, 2022-08-14) [Linux], the latest version of Simple Inkscape Scripting, and the following script:
rad = width/20
e = circle((width/2, height/2), rad, fill='yellow')
e1 = circle((0, 0), rad, fill='red')
e2 = circle((width, 0), rad, fill='green')
e3 = circle((0, height), rad, fill='blue')
e4 = circle((width, height), rad, fill='purple')
secs = 3
beg = 0
e.animate([e1, e2, e3, e4], duration=secs, begin_time=beg, key_times=[0.0, 0.0, 0.5, 0.75, 1.0], at_end=True)
Does that script work when you run it? Could you please provide a complete, failing script that I can use to investigate the crash?
Thank you very much! I am using the latest Inkscape for Windows: Inkscape 1.2.1 (9c6d41e410, 2022-07-14)
I tried the code provided by you above and it runs very well. So maybe the problem is the SVG file I used.
The SVG file has been created by the project "Primitive" which generates a SVG from an image, automatically: https://github.com/fogleman/primitive
A minimalistic SVG, generated by Primitive, to reproduce the error is:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="844" height="1024">
<rect x="0" y="0" width="844" height="1024" fill="#735346" />
<g transform="scale(4.000000) translate(0.5 0.5)">
<ellipse fill="#160000" fill-opacity="0.501961" cx="104" cy="65" rx="54" ry="54" />
<ellipse fill="#b89a84" fill-opacity="0.501961" cx="34" cy="209" rx="47" ry="47" />
<ellipse fill="#55d58a" fill-opacity="0.501961" cx="201" cy="120" rx="34" ry="34" />
<ellipse fill="#b1afb2" fill-opacity="0.501961" cx="9" cy="33" rx="30" ry="30" />
<ellipse fill="#ffd8c7" fill-opacity="0.501961" cx="182" cy="156" rx="16" ry="16" />
</g>
</svg>
The code below finds all the ellipses inside the group, and adds an animation (to scale the radius) to each ellipse.
largest = -1
beg_secs = 0.33
for r in all_shapes():
if r.tag == 'g':
for e in r:
#print(e.tag)
if e.tag == 'ellipse':
cx=e.svg_get('cx')
cy=e.svg_get('cy')
rx=e.svg_get('rx')
ry=e.svg_get('ry')
fill=e.svg_get('fill')
opacity=e.svg_get('fill-opacity')
if largest<0:
largest = rx
e1 = ellipse((cx, cy), (0, 0),fill=fill, opacity=opacity)
e2 = ellipse((cx, cy), (rx*0.8, ry*0.75),fill=fill, opacity=opacity)
e3 = ellipse((cx, cy), (rx*0.9, ry*0.90),fill=fill, opacity=opacity)
ani_duration = 1.0 + 3.0 * rx/largest
beg_secs = beg_secs + 8/7000
seconds_at_0_percent = beg_secs + 0
seconds_at_50_percent = beg_secs + ani_duration * 0.5
seconds_at_75_percent = beg_secs + ani_duration * 0.75
duration = beg_secs + ani_duration
key_at_0 = seconds_at_0_percent/duration
key_at_50 = seconds_at_50_percent/duration
key_at_75 = seconds_at_75_percent/duration
beg_s = "{}s".format( beg_secs )
duration_s = "{}s".format( duration)
e.animate([e1,e1,e2, e3, e], duration=duration_s, begin_time='0s', key_times=[0.0, 0.0, key_at_0, key_at_50, key_at_75, 1.0], at_end=True)
if you get rid of ", at_end=True" the code runs without errors. if you leave ", at_end=True" you can reproduce the error.
Thank you
Thanks for the reproducer. I believe I now know what the problem is. Simple Inkscape Scripting uses the first object's attributes to determine what to animate. With at_end=True
, the first object is e1
and contains the attributes rx
, ry
, stroke
, fill
, and opacity
. With at_end=False
, the first object is e
and contains only the attributes rx
and ry
.
In the former case, Simple Inkscape Scripting tries to interpolate across the following six sets of attributes:
rx |
ry |
stroke |
fill |
opacity |
---|---|---|---|---|
0 | 0 | black | #160000 | 0.501961 |
0 | 0 | black | #160000 | 0.501961 |
43.2 | 40.5 | black | #160000 | 0.501961 |
48.6 | 48.6 | black | #160000 | 0.501961 |
54 | 54 | None | None | None |
54 | 54 | None | None | None |
The code doesn't expect to see any of those None
values and therefore throws the
TypeError: sequence item 4: expected str instance, NoneType found
exception you observed.
Where do the None
values come from? SVG—annoyingly, in my opinion—provides multiple mechanisms for applying styles, such as fill
, to an object. Simple Inkscape Scripting does what Inkscape itself does and stores all styles using the style
attribute: style="fill:#160000"
. Your test SVG file uses a separate attribute per style: fill="#160000"
. While this is valid SVG, it implies that object e
has fill
, stroke
, and opacity
attributes while e1
, e2
, and e3
, which are generated with Simple Inkscape Scripting, have only a style
attribute and None
for the fill
, stroke
, and opacity
attributes.
I believe I can modify Simple Inkscape Scripting to ignore style attributes that are None
in some object instances. If I'm not mistaken, that should get your use case to work, but won't animate styles that are specified using one SVG mechanism in some objects and a different SVG mechanism in others.
BTW, thanks for the bug report, and please re-open the issue if my latest commit didn't fix the problem.
e.animate([e1,e2, e3, e4], duration=secs, begin_time=beg, key_times=[0.0, 0.0, 0.5, 0.75, 1.0], at_end=True)
line 882, in animate anim.set('values', '; '.join(vs)) TypeError: sequence item 4: expected str instance, NoneType found