libvips / pyvips

python binding for libvips using cffi
MIT License
640 stars 49 forks source link

Gif only saves as first frame #366

Open will-171 opened 1 year ago

will-171 commented 1 year ago

Hi! I want to add some text to a gif, but when I save it runs with no errors but only saves the first frame. After removing everything else and just loading and saving it still doesnt work:

gif = pyvips.Image.magickload('https://media.tenor.com/BSi7CbeeVSEAAAAd/gato-cat.gif')
gif.magicksave('./test.gif')

Im using pyvips 2.2.1 on linux mint 20.3 Not sure why its not saving the full gif? Using print(gif.get('n-pages')) shows the correct number of frames so im not sure whats wrong. I also tried using gifload_source and gifsave but I get an error: AttributeError: 'str' object has no attribute 'pointer' How can I get the gif to save properly?

Thanks in advance

jcupitt commented 1 year ago

Hello @will-171,

libvips only loads one page of many-page images by default. You can use n and page to set the first page to load and the number of pages to load. Set n=-1 to load all pages.

libvips has its own GIF loader, so you don't need to go via imagemagic.

For example:

https://github.com/libvips/pyvips/blob/master/examples/watermark.py

I can run that program like this:

$ ./watermark.py ~/pics/3198.gif[n=-1] x.gif "hello"

And it'll draw text on each frame.

jcupitt commented 1 year ago

You can also load all frames with eg.:

image = pyvips.Image.new_from_file("x.gif", n=-1, access="sequential")

Setting the access hint can give a nice speed improvement, if your image processing pipeline can run in streaming mode.

will-171 commented 1 year ago

@jcupitt Thanks for responding I used your code to load my gif and it loads all frames now, I just have one more issue I need to load the gif from a link and thats why I was trying to use magickload, when I try new_from_source in place of new_from_file it gives me this error:

Traceback (most recent call last):
  File "/home/wt/Desktop/test/script.py", line 109, in <module>
    gif = pyvips.Image.new_from_source("https://media.tenor.com/BSi7CbeeVSEAAAAd/gato-cat.gif", n=-1, access="sequential", options="")
  File "/usr/local/lib/python3.8/dist-packages/pyvips/vimage.py", line 662, in new_from_source
    pointer = vips_lib.vips_foreign_find_load_source(source.pointer)
AttributeError: 'str' object has no attribute 'pointer''

From this line:

gif = pyvips.Image.new_from_source("https://media.tenor.com/BSi7CbeeVSEAAAAd/gato-cat.gif", n=-1, access="sequential", options="")

How can I fix this? Thanks

jcupitt commented 1 year ago

libvips doesn't have anything to download from a URL, but you can link the load/save operations up to any byte source or destination. See eg.:

https://github.com/libvips/pyvips/blob/master/examples/connection.py

So just swap the file source there for your favourite python package to download from a URL.

ruby-vips has a closer example:

https://github.com/libvips/ruby-vips/blob/master/example/connection.rb