Closed lxccc812 closed 1 year ago
Hi. You start out talking about memory, but then you switch to talking about file size. Memory is used temporarily during the execution of the script and then released afterwards. File size refers to the amount of space that the created GIF takes up when the script is done. I'm going to presume that you are just talking about file size.
Could you provide a self-contained example to demonstrate what is happening? That is, a copy of the script that you run, with any input images attached?
from PIL import ImageSequence, Image
def t1():
image_list = []
im = Image.open(r'C:\Users\LXC\Desktop\t1\666.gif')
for index, frame in enumerate(ImageSequence.Iterator(im)):
rate = 1
width = frame.size[0]
height = frame.size[1]
if width / height >= rate:
target_height = height
target_width = height * rate
point_1x = width / 2 - target_width / 2
point_1y = 0
point_2x = width / 2 + target_width / 2
point_2y = target_height
else:
target_width = width
target_height = width / rate
point_1x = 0
point_1y = height / 2 - target_height / 2
point_2x = target_width
point_2y = height / 2 + target_height / 2
cut_frame = frame.crop((point_1x, point_1y, point_2x, point_2y))
resize_frame = cut_frame.resize((240, 240), Image.ANTIALIAS)
image_list.append(resize_frame)
duration = (im.info).get('duration', 30)
transparency = (im.info).get('transparency', 255)
loop = (im.info).get('loop', 0)
comment = (im.info).get('comment', '')
image_list[0].save(
r'C:\Users\LXC\Desktop\t1\new666.gif',
save_all=True,
include_color_table=True,
disposal=2,
append_images=image_list[1:],
duration=duration,
transparency=transparency,
loop=loop,
comment=comment
)
After I cut and resize each image in the gif, I synthesize a new gif image. Its size is larger than the original gif. On the left is the file size between modifications, and on the right is the file size after modifications.
Could you attach a copy of the original GIF?
For this specific example, I find that if you change
resize_frame = cut_frame.resize((240, 240), Image.ANTIALIAS)
to
resize_frame = cut_frame.resize((240, 240))
then the created GIF is actually smaller than your original GIF.
According to the method you said, the file is really smaller after modification. But it is still not the effect I want. When I use 14 10 kb or so images to compose a gif, the file size becomes about 500 kb, which is unreasonable and incorrect. I'm not sure why this happened. The folder on the left is the picture I used, and the folder on the right is my composite gif. Its size is too large. I think this is wrong.
Could you attach the 14 images?
from PIL import Image, ImageSequence
def t2():
image_list = []
for i in range(14):
im = Image.open(fr'C:\Users\LXC\Desktop\t2\666-{i}.jpg')
print(im.mode)
image_list.append(im)
image_list[0].save(
r'C:\Users\LXC\Desktop\t2\new666.gif',
save_all=True,
include_color_table=True,
disposal=2,
append_images=image_list[1:],
duration=10,
loop=0
)
When I use this code to synthesize images, the gif is too large and not very reasonable
If I just open a single image and save it as a GIF,
Image.open("0.jpg").save("zero.gif")
then the 10kb JPG becomes a 44kb GIF. I tested converting the image with ImageMagick instead of Pillow, and it was 42kb. So I don't think Pillow is doing anything wrong explicitly. JPEGs and GIFs are different, and sometimes a GIF image might be bigger. Over at http://users.wfu.edu/matthews/misc/jpg_vs_gif/JpgVsGif-compact.html, they mention a particular GIF being 2.4 times bigger than a JPEG.
44kb * 14 = 616kb, which is greater than your final file size, so I don't think the problem has anything to do with the animation.
Experimenting, I found that for this specific example, if I insert this new line above image_list.append(im)
,
im = im.quantize(36, method=Image.Quantize.FASTOCTREE)
then your output image is now 180kb.
I watched the comparison between jpg and gif. It roughly means that the more colors in the image, the bigger the gif. But I still don't understand. I split the original gif to get a lot of pictures, then cut and limit the size of these pictures, and then synthesize the gif. The result is even larger than the original gif, which I can't understand. I observed every step in the process and strictly followed the document. Still can not achieve the effect I want.If I can make this phenomenon clear, I think I can avoid it.
Opening the image and resaving it
from PIL import Image, ImageSequence
im = Image.open("in.gif")
frames = []
for i, frame in enumerate(ImageSequence.Iterator(im)):
frames.append(frame.copy())
frames[0].save("out.gif", save_all=True, append_images=frames[1:])
gives a 493kb GIF.
If we crop it,
from PIL import Image, ImageSequence
im = Image.open("in.gif")
frames = []
for i, frame in enumerate(ImageSequence.Iterator(im)):
cropped_frame = frame.crop((0, 0, 247, 247))
frames.append(cropped_frame)
frames[0].save("out.gif", save_all=True, append_images=frames[1:])
then it gives a 307kb GIF. Fair enough, it is smaller.
If we crop and resize it with ANTIALIAS,
from PIL import Image, ImageSequence
im = Image.open("in.gif")
frames = []
for i, frame in enumerate(ImageSequence.Iterator(im)):
cropped_frame = frame.crop((0, 0, 247, 247))
resized_frame = cropped_frame.resize((240, 240), Image.ANTIALIAS)
frames.append(resized_frame)
frames[0].save("out.gif", save_all=True, append_images=frames[1:])
then it gives a 513kb GIF. Why is this bigger? Here is some code to count the number of colours in the image before and after it is resized.
from PIL import Image, ImageSequence
def get_number_of_colors(frame):
colors = []
for x in range(frame.width):
for y in range(frame.height):
color = frame.getpixel((x, y))
if color not in colors:
colors.append(color)
return len(colors)
im = Image.open("in.gif")
frames = []
for i, frame in enumerate(ImageSequence.Iterator(im)):
cropped_frame = frame.crop((0, 0, 247, 247))
print("Before resizing, there are "+str(get_number_of_colors(cropped_frame))+" colors")
resized_frame = cropped_frame.resize((240, 240), Image.ANTIALIAS)
print("After resizing, there are "+str(get_number_of_colors(resized_frame))+" colors")
frames.append(resized_frame)
frames[0].save("out.gif", save_all=True, append_images=frames[1:])
prints
Before resizing, there are 91 colors
After resizing, there are 91 colors
Before resizing, there are 93 colors
After resizing, there are 17891 colors
Before resizing, there are 93 colors
After resizing, there are 18622 colors
Before resizing, there are 90 colors
After resizing, there are 18082 colors
Before resizing, there are 93 colors
After resizing, there are 19052 colors
Before resizing, there are 89 colors
After resizing, there are 18140 colors
Before resizing, there are 92 colors
After resizing, there are 18444 colors
Before resizing, there are 90 colors
After resizing, there are 18013 colors
Before resizing, there are 90 colors
After resizing, there are 18097 colors
Before resizing, there are 91 colors
After resizing, there are 17609 colors
Before resizing, there are 91 colors
After resizing, there are 17429 colors
Before resizing, there are 93 colors
After resizing, there are 15807 colors
Before resizing, there are 93 colors
After resizing, there are 16406 colors
Before resizing, there are 93 colors
After resizing, there are 17394 colors
The resize operation has introduced more colours. The image has become less simple. It therefore seems reasonable that the GIF is larger.
Image.ANTIALIAS
is also the old way to refer to Image.Resampling.LANCZOS
.
https://pillow.readthedocs.io/en/stable/reference/Image.html#resampling-filters
I think Image.Resampling.NEAREST
may give the smallest size.
@lxccc812 has that explained things?
The problem has been solved. Thank you for your answer.
When I use the save method to save the picture list, the generated gif memory is too large. I have used 14 images within 10kb, but the generated gif accounts for about 400k. When I use the same image to generate gif repeatedly, the size of the generated gif is different each time. What is this situation? Can you answer it.