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

Save GIF without loss of quality #8251

Closed
zxbzxb180 opened this issue Jul 20, 2024 · 23 comments
Closed

Save GIF without loss of quality #8251

zxbzxb180 opened this issue Jul 20, 2024 · 23 comments
Labels

Comments

@zxbzxb180
Copy link

zxbzxb180 commented Jul 20, 2024

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)
image
This is the input GIF
input
This is the saved GIF
output

Here is my code:

from PIL import Image, ImageSequence, GifImagePlugin
GifImagePlugin.LOADING_STRATEGY = GifImagePlugin.LoadingStrategy.RGB_AFTER_DIFFERENT_PALETTE_ONLY

gif = Image.open("input.gif")
frames = [frame.copy() for frame in ImageSequence.Iterator(gif)]
frames[0].save(
    "output.gif",
    save_all=True,
    append_images=frames[1:],
    optimize=False,
    disposal=2,
    lossless=True,
    loop=0
)
@radarhere radarhere added the GIF label Jul 20, 2024
@Yay295
Copy link
Contributor

Yay295 commented Jul 20, 2024

If you convert the frames to mode P yourself, the first three lines of that function will be used, and they won't be converted a second time.

@zxbzxb180
Copy link
Author

如果您自己将帧转换为模式P,则该函数的前三行将被使用,并且不会再次转换。

Yes, but if I convert it myself, the quality of the GIF will also decrease, and the final effect will be the same。

@Yay295
Copy link
Contributor

Yay295 commented Jul 20, 2024

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))

@radarhere
Copy link
Member

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.

@zxbzxb180
Copy link
Author

这可能有用。我还没有测试过。

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))

Unfortunately, this will result in an error. I noticed that from the second frame onwards, getcolors() is set to None

@zxbzxb180

This comment was marked as duplicate.

@zxbzxb180
Copy link
Author

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.

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.

@radarhere
Copy link
Member

When you say 'modify the GIF resolution', are you planning on shrinking the image? If so, by how much?

@zxbzxb180
Copy link
Author

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?

@radarhere
Copy link
Member

If you're interested in reducing file size, I suggest you upgrade Pillow, so that you get the benefits of #7568

@zxbzxb180
Copy link
Author

zxbzxb180 commented Jul 20, 2024

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 im.show() has decreased

@zxbzxb180
Copy link
Author

zxbzxb180 commented Jul 20, 2024

Before running that code, im.show() is a normal color. I really don't know much about GIFs, so this makes me a little confused.

@zxbzxb180
Copy link
Author

output.gif
first frame
image
second frame
image

@radarhere
Copy link
Member

radarhere commented Jul 20, 2024

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.

@zxbzxb180
Copy link
Author

zxbzxb180 commented Jul 20, 2024

Thank you for your patient answer. Unfortunately, it is a limitation of the format. But can I make other attempts to achieve my goals?

@zxbzxb180
Copy link
Author

zxbzxb180 commented Jul 20, 2024

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.

@radarhere
Copy link
Member

radarhere commented Jul 20, 2024

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.

output

@radarhere radarhere changed the title Save GIF with loss of quality Save GIF without loss of quality Jul 20, 2024
@radarhere
Copy link
Member

radarhere commented Jul 20, 2024

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.
output.webp.zip

@zxbzxb180
Copy link
Author

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.

output output

This looks good! But I can't reduce the image size by deleting some frames, such as reducing it to 500kb or 300kb.Is there any way to reduce the size of the image in this way?
image
output

@zxbzxb180
Copy link
Author

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.
output

    [
      
    
        ![output](https://private-user-images.githubusercontent.com/3112309/350685290-94c31faf-5933-4f4a-8d26-7776c19f64f2.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE2MTU0MzksIm5iZiI6MTcyMTYxNTEzOSwicGF0aCI6Ii8zMTEyMzA5LzM1MDY4NTI5MC05NGMzMWZhZi01OTMzLTRmNGEtOGQyNi03Nzc2YzE5ZjY0ZjIuZ2lmP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDcyMiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA3MjJUMDIyNTM5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MTZlYTNhMzczN2ZjZDk1ZGRkMzNkNDNmZjNiYzc1NWE2Zjg2YjUxYWU3OTZhYzJmOGQzYmM3N2ExMjQ2Yjg5YSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.izHrZG3h8zagV7SB3HDLIFIZvwEGqvAlf8Hu8wFw6UY)
      ](https://private-user-images.githubusercontent.com/3112309/350685290-94c31faf-5933-4f4a-8d26-7776c19f64f2.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE2MTU0MzksIm5iZiI6MTcyMTYxNTEzOSwicGF0aCI6Ii8zMTEyMzA5LzM1MDY4NTI5MC05NGMzMWZhZi01OTMzLTRmNGEtOGQyNi03Nzc2YzE5ZjY0ZjIuZ2lmP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDcyMiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA3MjJUMDIyNTM5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MTZlYTNhMzczN2ZjZDk1ZGRkMzNkNDNmZjNiYzc1NWE2Zjg2YjUxYWU3OTZhYzJmOGQzYmM3N2ExMjQ2Yjg5YSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.izHrZG3h8zagV7SB3HDLIFIZvwEGqvAlf8Hu8wFw6UY)
    
    
      
        
          
        
        
          
          
        
      
      [
        
          
        
      ](https://private-user-images.githubusercontent.com/3112309/350685290-94c31faf-5933-4f4a-8d26-7776c19f64f2.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE2MTU0MzksIm5iZiI6MTcyMTYxNTEzOSwicGF0aCI6Ii8zMTEyMzA5LzM1MDY4NTI5MC05NGMzMWZhZi01OTMzLTRmNGEtOGQyNi03Nzc2YzE5ZjY0ZjIuZ2lmP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDcyMiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA3MjJUMDIyNTM5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MTZlYTNhMzczN2ZjZDk1ZGRkMzNkNDNmZjNiYzc1NWE2Zjg2YjUxYWU3OTZhYzJmOGQzYmM3N2ExMjQ2Yjg5YSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.izHrZG3h8zagV7SB3HDLIFIZvwEGqvAlf8Hu8wFw6UY)
    
   [ ![output](https://private-user-images.githubusercontent.com/3112309/350685290-94c31faf-5933-4f4a-8d26-7776c19f64f2.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE2MTU0MzksIm5iZiI6MTcyMTYxNTEzOSwicGF0aCI6Ii8zMTEyMzA5LzM1MDY4NTI5MC05NGMzMWZhZi01OTMzLTRmNGEtOGQyNi03Nzc2YzE5ZjY0ZjIuZ2lmP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDcyMiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA3MjJUMDIyNTM5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MTZlYTNhMzczN2ZjZDk1ZGRkMzNkNDNmZjNiYzc1NWE2Zjg2YjUxYWU3OTZhYzJmOGQzYmM3N2ExMjQ2Yjg5YSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.izHrZG3h8zagV7SB3HDLIFIZvwEGqvAlf8Hu8wFw6UY) ](https://private-user-images.githubusercontent.com/3112309/350685290-94c31faf-5933-4f4a-8d26-7776c19f64f2.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE2MTU0MzksIm5iZiI6MTcyMTYxNTEzOSwicGF0aCI6Ii8zMTEyMzA5LzM1MDY4NTI5MC05NGMzMWZhZi01OTMzLTRmNGEtOGQyNi03Nzc2YzE5ZjY0ZjIuZ2lmP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDcyMiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA3MjJUMDIyNTM5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MTZlYTNhMzczN2ZjZDk1ZGRkMzNkNDNmZjNiYzc1NWE2Zjg2YjUxYWU3OTZhYzJmOGQzYmM3N2ExMjQ2Yjg5YSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.izHrZG3h8zagV7SB3HDLIFIZvwEGqvAlf8Hu8wFw6UY)
  
    [
      
    
        ![output](https://private-user-images.githubusercontent.com/3112309/350685290-94c31faf-5933-4f4a-8d26-7776c19f64f2.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE2MTU0MzksIm5iZiI6MTcyMTYxNTEzOSwicGF0aCI6Ii8zMTEyMzA5LzM1MDY4NTI5MC05NGMzMWZhZi01OTMzLTRmNGEtOGQyNi03Nzc2YzE5ZjY0ZjIuZ2lmP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDcyMiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA3MjJUMDIyNTM5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MTZlYTNhMzczN2ZjZDk1ZGRkMzNkNDNmZjNiYzc1NWE2Zjg2YjUxYWU3OTZhYzJmOGQzYmM3N2ExMjQ2Yjg5YSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.izHrZG3h8zagV7SB3HDLIFIZvwEGqvAlf8Hu8wFw6UY)
      ](https://private-user-images.githubusercontent.com/3112309/350685290-94c31faf-5933-4f4a-8d26-7776c19f64f2.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE2MTU0MzksIm5iZiI6MTcyMTYxNTEzOSwicGF0aCI6Ii8zMTEyMzA5LzM1MDY4NTI5MC05NGMzMWZhZi01OTMzLTRmNGEtOGQyNi03Nzc2YzE5ZjY0ZjIuZ2lmP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDcyMiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA3MjJUMDIyNTM5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MTZlYTNhMzczN2ZjZDk1ZGRkMzNkNDNmZjNiYzc1NWE2Zjg2YjUxYWU3OTZhYzJmOGQzYmM3N2ExMjQ2Yjg5YSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.izHrZG3h8zagV7SB3HDLIFIZvwEGqvAlf8Hu8wFw6UY)
    
    
      
        
          
        
        
          
          
        
      
      [
        
          
        
      ](https://private-user-images.githubusercontent.com/3112309/350685290-94c31faf-5933-4f4a-8d26-7776c19f64f2.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE2MTU0MzksIm5iZiI6MTcyMTYxNTEzOSwicGF0aCI6Ii8zMTEyMzA5LzM1MDY4NTI5MC05NGMzMWZhZi01OTMzLTRmNGEtOGQyNi03Nzc2YzE5ZjY0ZjIuZ2lmP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDcyMiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA3MjJUMDIyNTM5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MTZlYTNhMzczN2ZjZDk1ZGRkMzNkNDNmZjNiYzc1NWE2Zjg2YjUxYWU3OTZhYzJmOGQzYmM3N2ExMjQ2Yjg5YSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.izHrZG3h8zagV7SB3HDLIFIZvwEGqvAlf8Hu8wFw6UY)
    
   [ ](https://private-user-images.githubusercontent.com/3112309/350685290-94c31faf-5933-4f4a-8d26-7776c19f64f2.gif?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE2MTU0MzksIm5iZiI6MTcyMTYxNTEzOSwicGF0aCI6Ii8zMTEyMzA5LzM1MDY4NTI5MC05NGMzMWZhZi01OTMzLTRmNGEtOGQyNi03Nzc2YzE5ZjY0ZjIuZ2lmP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDcyMiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA3MjJUMDIyNTM5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MTZlYTNhMzczN2ZjZDk1ZGRkMzNkNDNmZjNiYzc1NWE2Zjg2YjUxYWU3OTZhYzJmOGQzYmM3N2ExMjQ2Yjg5YSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.izHrZG3h8zagV7SB3HDLIFIZvwEGqvAlf8Hu8wFw6UY)

This looks good! But I can't reduce the image size by deleting some frames, such as reducing it to 500kb or 300kb.Is there any way to reduce the size of the image in this way? image output output

Oh, I found that reading GIFs with transparent backgrounds like this will result in an error ValueError: images do not match
image

@radarhere
Copy link
Member

Oh, I found that reading GIFs with transparent backgrounds like this will result in an error ValueError: images do not match

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.

@radarhere
Copy link
Member

But I can't reduce the image size by deleting some frames, such as reducing it to 500kb or 300kb.Is there any way to reduce the size of the image in this way?

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.

@zxbzxb180
Copy link
Author

But I can't reduce the image size by deleting some frames, such as reducing it to 500kb or 300kb.Is there any way to reduce the size of the image in this way?

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.

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

No branches or pull requests

3 participants