I have a gif
that I would like to resize with pillow
so that its size decreases. The current size of the gif
is 2MB.
I am trying to
resize it so its height / width is smaller
decrease its quality.
With JPEG, the following piece of code is usually enough so that large image drastically decrease in size.
from PIL import Image
im = Image.open("my_picture.jpg")
im = im.resize((im.size[0] // 2, im.size[1] // 2), Image.ANTIALIAS) # decreases width and height of the image
im.save("out.jpg", optimize=True, quality=85) # decreases its quality
With a GIF, though, it does not seem to work. The following piece of code even makes the out.gif
bigger than the initial gif:
im = Image.open("my_gif.gif")
im.seek(im.tell() + 1) # loads all frames
im.save("out.gif", save_all=True, optimize=True, quality=10) # should decrease its quality
print(os.stat("my_gif.gif").st_size) # 2096558 bytes / roughly 2MB
print(os.stat("out.gif").st_size) # 7536404 bytes / roughly 7.5MB
If I add the following line, then only the first frame of the GIF is saved, instead of all of its frame.
im = im.resize((im.size[0] // 2, im.size[1] // 2), Image.ANTIALIAS) # should decrease its size
I've been thinking about calling resize()
on im.seek()
or im.tell()
but neither of these methods return an Image object, and therefore I cannot call resize()
on their output.
Would you know how I can use Pillow to decrease the size of my GIF while keeping all of its frames?
[edit] Partial solution:
Following Old Bear's response, I have done the following changes:
I am using BigglesZX's script to extract all frames. It is useful to note that this is a Python 2 script, and my project is written in Python 3 (I did mention that detail initially, but it was edited out by the Stack Overflow Community). Running
2to3 -w gifextract.py
makes that script compatible with Python 3.I have been resicing each frame individually:
frame.resize((frame.size[0] // 2, frame.size[1] // 2), Image.ANTIALIAS)
I've been saving all the frames together:
img.save("out.gif", save_all=True, optimize=True)
.
The new gif is now saved and works, but there is 2 main problems :
I am not sure that the resize method works, as
out.gif
is still 7.5MB. The initial gif was 2MB.The gif speed is increased and the gif does not loop. It stops after its first run.
Example:
original gif my_gif.gif
:
Gif after processing (out.gif
) https://i.imgur.com/zDO4cE4.mp4 (I could not add it to Stack Overflow ). Imgur made it slower (and converted it to mp4). When I open the gif file from my computer, the entire gif lasts about 1.5 seconds.
Using BigglesZX's script, I have created a new script which resizes a GIF using Pillow.
Original GIF (2.1 MB):
Output GIF after resizing (1.7 MB):
I have saved the script here. It is using the
thumbnail
method of Pillow rather than theresize
method as I found theresize
method did not work.The is not perfect so feel free to fork and improve it. Here are a few unresolved issues:
stack.imgur
. Only the first frame was displayed (you can see it here).Full code (should the above gist be deleted):
I am using the function below to resize and crop images including animated ones (GIF, WEBP) Simply, we need to iterate each frame in the gif or webp.
According to Pillow 4.0x, the Image.resize function only works on a single image/frame.
To achieve what you want, I believe you have to first extract every frame from the .gif file, resize each frame one at a time and then reassemble them up again.
To do the first step, there appears to be some detail that needs to be attended to. E.g. whether each gif frame uses a local palette or a global palette is applied over all frames, and whether gif replace each image using a full or partial frame. BigglesZX has developed a script to address these issues while extracting every frame from a gif file so leverage on that.
Next, you have to write the scripts to resize each of the extracted frame and assemble them all as a new .gif using the PIL.Image.resize() and PIL.Image.save().
I noticed you wrote "
im.seek(im.tell() + 1) # load all frames
". I think this is incorrect. Rather it is use to increment between frames of a .gif file. I noticed you used quality=10 in your save function for your .gif file. I did not find this as provided in the PIL documentation. You can learn more about the tile attribute mentioned in BiggleZX's script by reading this link