问题描述
我有一个 gif
,我想用枕头
调整大小,以便缩小尺寸。 gif
的当前大小为2MB。
我正在尝试
-
调整大小以使其高度/宽度较小
-
降低质量。
使用JPEG,以下代码通常足以使大图像的大小急剧减少。
来自PIL导入图片
im = Image.open(my_picture.jpg)
im = im.resize((im.size [0] // 2,im.size [1] // 2),Image.ANTIALIAS)#减少图像的宽度和高度
im.save(out。 jpg,optimize = True,quality = 85)#降低其质量
但是,使用GIF,它似乎不起作用。以下代码甚至使 out.gif
大于最初的gif:
im = Image.open(my_gif.gif)
im.seek(im.tell()+ 1)#loading all frames
im.save(out.gif, save_all = True,optimize = True,quality = 10)#应该降低它的质量
print(os.stat(my_gif.gif)。st_size)#2096558 bytes /大约2MB
print(os.stat(out.gif)。st_size)#7536404 bytes /大约7.5MB
如果我添加以下行,则只保存GIF的第一帧,而不是保存所有帧。
im = im.resize((im.size [0] // 2,im.size [1] // 2),Image.ANTIALIAS)#应减小其大小
我一直在考虑在 im.seek上调用
或 resize()
( ) im.tell()
但这些方法都没有返回Image对象,因此我无法调用 resize( )
你愿意吗?现在我如何使用Pillow来减小我的GIF的大小,同时保留所有的帧?
[edit]部分解决方案:
在
处理后的Gif( out.gif
)
调整大小后输出GIF(1.7 MB):
我保存了脚本。它使用Pillow的缩略图
方法而不是 resize
方法,因为我发现调整大小
方法不起作用。
这不是完美的,所以随意分叉并改进它。以下是一些未解决的问题:
- 虽然GIF在imgur托管时显示正常,但是当我打开它时出现速度问题我的电脑,整个GIF只需1.5秒。
- 同样,虽然imgur似乎弥补了速度问题,但当我尝试将其上传到 stack.imgur 。仅显示第一帧(您可以在查看)。
完整代码(如果上面的要点被删除):
def resize_gif(path,save_as = None,resize_to = None):
将GIF调整为给定长度:
Args:
path:GIF文件的路径
save_as(可选):调整大小的gif的路径。如果没有设置,原始的gif将被覆盖。
resize_to(可选):gif的新大小。格式:(int,int)。如果没有设置,原始GIF将调整为
大小的一半。
all_frames = extract_and_resize_frames(path,resize_to)
如果不是save_as:
save_as = path
如果len(all_frames)== 1:
print(警告:只找到1帧)
all_frames [0] .save(save_as,optimize = True)
else:
all_frames [0] .save(save_as,optimize = True,save_all = True,append_images = all_frames [1:],loop = 1000)
def analyseImage(path):
预处理通过图像以确定模式(完整或添加)。
评估单帧时不可靠。在处理所有帧之前需要知道模式
。
im = Image.open(路径)
results = {
'size':im.size,
'mode':'full',
}
尝试:
而True:
if im.tile:
tile = im.tile [0]
update_region = tile [1]
update_region_dimensions = update_region [2:]
if update_region_dimensions!= im.size:
results ['mode'] ='partial'
break
im.seek(im .tell()+ 1)
除了EOFError:
传递
返回结果
def extract_and_resize_frames(path,resize_to = None):
迭代GIF,提取每一帧并调整大小
返回:
所有帧的数组
mode = analyseImage(path)['mode']
im = Image.open(path)
如果不是resize_to:
resize_to =(im.size [0 ] // 2,im.size [1] // 2)
i = 0
p = im.getpalette()
last_frame = im.convert('RGBA')
all_frames = []
尝试:
而True:
#print(保存%s(%s)帧%d,%s% s%(path,mode,i,im.size,im.tile))
'''
如果GIF使用本地颜色表,则每个帧都有自己的调色板。
如果没有,我们需要将全局调色板应用于新帧。
'''
如果不是im.getpalette():
im.putpalette(p)
new_frame = Image.new('RGBA',im.size )
'''
此文件是部分模式GIF,其中帧更新与整个图像不同大小的区域?
如果是这样,我们需要通过将它粘贴在前面的帧之上来构造新帧。
'''
如果模式=='部分':
new_frame.paste(last_frame)
new_frame.paste(im,(0,0),im .convert('RGBA'))
new_frame.thumbnail(resize_to,Image.ANTIALIAS)
all_frames.append(new_frame)
i + = 1
last_frame = new_frame
im.seek(im.tell()+ 1)
除了EOFError:
传递
返回all_frames
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 the resize
method as I found the resize
method did not work.
The is not perfect so feel free to fork and improve it. Here are a few unresolved issues:
- While the GIF displays just fine when hosted by imgur, there is a speed issue when I open it from my computer where the entire GIF only take 1.5 seconds.
- Likewise, while imgur seems to make up for the speed problem, the GIF wouldn't display correctly when I tried to upload it to
stack.imgur
. Only the first frame was displayed (you can see it here).
Full code (should the above gist be deleted):
def resize_gif(path, save_as=None, resize_to=None):
"""
Resizes the GIF to a given length:
Args:
path: the path to the GIF file
save_as (optional): Path of the resized gif. If not set, the original gif will be overwritten.
resize_to (optional): new size of the gif. Format: (int, int). If not set, the original GIF will be resized to
half of its size.
"""
all_frames = extract_and_resize_frames(path, resize_to)
if not save_as:
save_as = path
if len(all_frames) == 1:
print("Warning: only 1 frame found")
all_frames[0].save(save_as, optimize=True)
else:
all_frames[0].save(save_as, optimize=True, save_all=True, append_images=all_frames[1:], loop=1000)
def analyseImage(path):
"""
Pre-process pass over the image to determine the mode (full or additive).
Necessary as assessing single frames isn't reliable. Need to know the mode
before processing all frames.
"""
im = Image.open(path)
results = {
'size': im.size,
'mode': 'full',
}
try:
while True:
if im.tile:
tile = im.tile[0]
update_region = tile[1]
update_region_dimensions = update_region[2:]
if update_region_dimensions != im.size:
results['mode'] = 'partial'
break
im.seek(im.tell() + 1)
except EOFError:
pass
return results
def extract_and_resize_frames(path, resize_to=None):
"""
Iterate the GIF, extracting each frame and resizing them
Returns:
An array of all frames
"""
mode = analyseImage(path)['mode']
im = Image.open(path)
if not resize_to:
resize_to = (im.size[0] // 2, im.size[1] // 2)
i = 0
p = im.getpalette()
last_frame = im.convert('RGBA')
all_frames = []
try:
while True:
# print("saving %s (%s) frame %d, %s %s" % (path, mode, i, im.size, im.tile))
'''
If the GIF uses local colour tables, each frame will have its own palette.
If not, we need to apply the global palette to the new frame.
'''
if not im.getpalette():
im.putpalette(p)
new_frame = Image.new('RGBA', im.size)
'''
Is this file a "partial"-mode GIF where frames update a region of a different size to the entire image?
If so, we need to construct the new frame by pasting it on top of the preceding frames.
'''
if mode == 'partial':
new_frame.paste(last_frame)
new_frame.paste(im, (0, 0), im.convert('RGBA'))
new_frame.thumbnail(resize_to, Image.ANTIALIAS)
all_frames.append(new_frame)
i += 1
last_frame = new_frame
im.seek(im.tell() + 1)
except EOFError:
pass
return all_frames
这篇关于枕头 - 调整GIF大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!