Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No documented way to programmatically request single iteration of gif animation #7328

Closed
jagerber48 opened this issue Aug 8, 2023 · 5 comments · Fixed by #7329
Closed

No documented way to programmatically request single iteration of gif animation #7328

jagerber48 opened this issue Aug 8, 2023 · 5 comments · Fixed by #7329
Labels

Comments

@jagerber48
Copy link

jagerber48 commented Aug 8, 2023

What did you do?

Generate a .gif file using loop=1.

What did you expect to happen?

I expected this to cause the .gif animation to play through once and then not repeat.

What actually happened?

On some gif viewers the gif played once, on others it played twice.

What are your OS, Python and Pillow versions?

  • OS: Windows 11
  • Python: 3.9
  • Pillow: 9.1.1

Discussion

See this issue which spells out the problem in more detail: #4575

I was able to resolve my issue by omitting the loop argument from my gif save call altogether. In this case 1 iteration of the animation was reliably played on all gif players I tried. But how can I access the omitted argument behavior while still including the argument? Suppose I have code like:

def save_images_to_gif(images, gif_path, tot_duration, loop):
    duration = tot_duration / len(images)
    images[0].save(gif_path, save_all=True, append_iamges=images[1:], duration=duration, loop=loop)

What argument can a user of this function pass in for loop to get the same behavior as if no loop argument was supplied to save? 0 doesn't work, 1 doesn't work, None doesn't work. I don't know of any argument that works and as far as I can tell there is no such argument in the documentation.

@Yay295
Copy link
Contributor

Yay295 commented Aug 8, 2023

There isn't one. The code just checks whether or not loop has been set at all.

if "loop" in info:
header.append(
b"!"
+ o8(255) # extension intro
+ o8(11)
+ b"NETSCAPE2.0"
+ o8(3)
+ o8(1)
+ o16(info["loop"]) # number of loops
+ o8(0)
)

@jagerber48
Copy link
Author

Ok, thanks for the info and clarifying there is no way to do this. Would it be reasonable to request a way to be able to do this? For example using None, or some other sentinel, to realize this behavior?

@Yay295
Copy link
Contributor

Yay295 commented Aug 8, 2023

I think None currently raises an exception, right? If so, it could probably check that loop isn't None without breaking anyone's code.

@jagerber48
Copy link
Author

Yes, if I pass loop=None I get error: required argument is not an integer.

@radarhere
Copy link
Member

I've created PR #7329 to resolve this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants