【发布时间】:2020-09-09 11:41:32
【问题描述】:
我正在使用 Pillow 读取 gif,此代码将 gif 文件中的每一帧输出为 .gif 和 .png 转换为 RGBA 和不转换为 RGBA。
我会在展示结果后讨论下面的问题
from PIL import Image
# Download link below
image = Image.open('PepePls.gif')
loop = []
frames = []
durations = []
try:
while True:
loop.append(image.info.get('loop', None))
frame = image.copy()
frames.append(frame)
durations.append(image.info.get('duration', None))
image.seek(image.tell() + 1)
except EOFError:
pass
for i in range(len(frames)):
print(f'#{i} loop = {loop[i]} duration = {durations[i]} mode = {frames[i].mode}')
frames[i].save(f'gif_f{i}.gif')
frames[i].save(f'png_f{i}.png')
frames[i].convert(mode='RGBA').save(f'rgba_gif_f{i}.gif')
frames[i].convert(mode='RGBA').save(f'rgba_png_f{i}.png')
结果,控制台输出然后 explorer.exe 截图:
#0 loop = 0 duration = 70 mode = P
#1 loop = None duration = 70 mode = P
#2 loop = None duration = 70 mode = P
#3 loop = None duration = 70 mode = P
#4 loop = None duration = 70 mode = P
#5 loop = None duration = 70 mode = P
#6 loop = None duration = 70 mode = P
#7 loop = None duration = 70 mode = P
#8 loop = None duration = 70 mode = P
#9 loop = None duration = 70 mode = P
#10 loop = None duration = 70 mode = P
#11 loop = None duration = 70 mode = P
#12 loop = None duration = 70 mode = P
#13 loop = None duration = 70 mode = P
#14 loop = None duration = 70 mode = P
#15 loop = None duration = 70 mode = P
#16 loop = None duration = 70 mode = P
#17 loop = None duration = 70 mode = P
#18 loop = None duration = 70 mode = P
#19 loop = None duration = 70 mode = P
#20 loop = None duration = 70 mode = P
问题:
-
为什么 rgba gif 会失去透明度?而背景色是从哪里来的
-
为什么到处都是黑边?我从使用 GIMP 中了解到 gif 帧可以组合或替换之前的帧,这是否解释了我所看到的内容或其他内容? (在这个话题上,Pillow 自己处理合并/替换帧 gif 吗?)
-
不确定图像大小发生了什么,explorer.exe 显示为 68x104,但 Pillow 保存的帧均为 85x112(firefox 在查看输入 gif 文件时也显示为 85x112)
this one too 有类似的问题
编辑:
经过大量研究和阅读 Pillow 源代码https://github.com/python-pillow/Pillow/blob/master/src/PIL/GifImagePlugin.py,我很确定黑色边框是一个错误,它必须与每一帧都绘制在不合适颜色的背景上(可能根本不检查调色板/颜色/透明度索引)
这是我在上面的代码中将frame = image.copy()替换为
frame = Image.new('RGBA', (85, 112), color=(255,0,0,0))
frame.paste(image.crop(image.dispose_extent), box=(image.dispose_extent[0],image.dispose_extent[1]))
可能想使用image.tile[0][1] 而不是image.dispose_extent,但我真的不确定
这似乎也表明 Pillow 根本不喜欢透明的 GIF
编辑 2:
我修复了黑色边框并使用以下方法组合/替换框架:
from PIL import Image
gif = 'PeepoCreepo.gif'
#gif = 'PepePls.gif'
image = Image.open(gif)
frames = []
disposal_method_last = 0
try:
while True:
disposal_method = disposal_method_last
disposal_method_last = image.__dict__.get('disposal_method', 0)
if disposal_method == 2 or (disposal_method == 1 and frames == []):
frame = Image.new('RGBA', image.size, color=(255,0,0,0))
frame.paste(image.crop(image.dispose_extent), box=(image.dispose_extent[0],image.dispose_extent[1]))
elif disposal_method == 1:
newStuff = image.crop(image.dispose_extent)
frame = frames[-1].copy()
frame.paste(newStuff, image.dispose_extent, newStuff.convert("RGBA"))
else:
frame = image.copy()
frames.append(frame)
image.seek(image.tell() + 1)
except EOFError:
pass
for i in range(len(frames)):
frames[i].convert(mode='RGBA').save(f'f{i}.png')
我仍然看到的一个问题是,如果您放大 f2.png,您会发现眼睛中的一些黑色消失了。这不是 gif 文件的问题,因为 gimp 可以正确打开并显示每一帧:
EDIT3:
EDIT4:
Github 问题已被标记为已修复!
【问题讨论】:
-
检查每个单独帧的大小。您可能会发现有些只是部分更新,帧的其余部分需要从以前的帧中向前复制。
-
frames[i].size 总是 (85,112),但我不认为它可能是它,因为第一帧也有黑色边框
标签: python python-imaging-library gif animated-gif