-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Save GIF without loss of quality #8251
Comments
If you convert the frames to mode |
Yes, but if I convert it myself, the quality of the GIF will also decrease, and the final effect will be the same。 |
This might work. I haven't tested it. from PIL import ImagePalette
frames = [ ]
for frame in ImageSequence.Iterator(gif):
palette = ImagePalette.ImagePalette("RGB", [x for pixel in frame.getcolors() for x in pixel])
frames.append(frame.convert("P", dither=Image.Dither.NONE, palette=palette)) |
You may or may not be familiar with this, but each frame of a GIF can only contain 256 colours. However, those frames can be overlaid on each other, really meaning that each frame of a GIF can introduce up to 256 new colors to the animation. Taking a look, by the time you get to the last frame, there are 2989 colours. This is hard to convert to 256 without visible differences. You might say that the original GIF managed it somehow. Yes, it would be by starting out with a limited number of colours and then introducing more as the animation continues. I presume you're planning to apply some sort of transformation to these images down the line, and that will change the nature of this question again. |
Unfortunately, this will result in an error. I noticed that from the second frame onwards, getcolors() is set to None |
This comment was marked as duplicate.
This comment was marked as duplicate.
Yes, I am planning to use Pillow to help me modify the GIF resolution and delete some frames in order to reduce the size of the GIF, but I don't want this to lower the color quality. |
When you say 'modify the GIF resolution', are you planning on shrinking the image? If so, by how much? |
Yes, this may not be fixed, some are 300x300, some are 512x512. At the same time, I am considering deleting some frames to achieve the goal of reducing the image size, such as reducing it to below 500kb. Perhaps there are other ways? |
If you're interested in reducing file size, I suggest you upgrade Pillow, so that you get the benefits of #7568 |
Okay, I will try upgrading the version, but I have found that the color quality of the first frame of the saved GIF is normal, and changes only occur from the second frame onwards. At present, I have found that after running the line of code mentioned in my issue, the color quality of the frames seen by |
Before running that code, |
I'll try rephrasing this. Each image in a GIF file is limited to 256 colours. That has nothing to do with Pillow, that is a limitation of the format. So the line that you have found is converting each frame from however many colours down to 256. Attempting to do so with an image with more than 256 colours can't be lossless, naturally, so that's why it comes out looking different. But if GIF frames only have 256 colours per frame, you might ask, why isn't that already the case in the GIF file I start with? Within your 400x400 file, the second frame does not necessarily have all 400x400 pixels written. It might only have a certain region, or it might only have the pixels that changed, leaving the others transparent. It looks normal in the end though because that frame can be pasted on top of the first one. Because of this pasting operation, there can be more than 256 colours as the animation goes on. |
Thank you for your patient answer. Unfortunately, it is a limitation of the format. But can I make other attempts to achieve my goals? |
I think my question is similar to Example 2 in #6832 ,but I did not achieve a similar effect using the convertToP function you provided at the time, I have upgraded to 10.4.0. |
One way to try and workaround the problem is to not combine the GIF images in the first place. from PIL import Image, ImageSequence, GifImagePlugin
# The following line patches Pillow so that the images aren't loaded loaded as combined RGB images
# The individual images will look broken,
# but if the GIF is saved with the same settings as the original, the combined result will look ok
GifImagePlugin.GifImageFile.load_end = lambda self: None
with Image.open("input.gif") as im:
frames = [frame.resize((300, 300)) for frame in ImageSequence.Iterator(im)]
frames[0].save(
"output.gif",
save_all=True,
append_images=frames[1:],
transparency=0,
loop=0
) gives a 1.3mb file, that I think doesn't have the quality issues from before. |
Also, just to think outside the box, if you don't strictly need a GIF, WebP is worth considering. from PIL import Image, ImageSequence
with Image.open("input.gif") as im:
frames = [frame.copy() for frame in ImageSequence.Iterator(im)]
frames[0].save(
"output.webp",
save_all=True,
append_images=frames[1:],
loop=0
) gives a 461kb file. |
I was providing code specific to your image. If you'd like to discuss another specific image, please attach it. This is a slightly awkward process because in general, Pillow doesn't explicitly provide functionality to extract the original frames from a GIF and re-combine them. |
As I said, GIFs can potentially introduce 256 new colours with each frame. If you remove frames, you remove the opportunity to add those new colours. If your final frame has 2989 colours, then you need at minimum 12 frames to get to that result. |
Thank you very much for your assistance. Currently, my solution is to first use Pillow to obtain each frame for processing, and then use ffmpeg to synthesize GIFs from the processed frames, so that there will be no color issues. |
I am currently using Pillow 9.4.0 and have noticed that the GifImagePlugin. py source code of Pillow uses this code to convert RGBA to P mode when processing GIFs, resulting in a loss of image quality. How can I resolve this issue?
im=im.convert("P", palette=Image. Palette. AdaPTIVE)
This is the input GIF
This is the saved GIF
Here is my code:
The text was updated successfully, but these errors were encountered: