用枕头读取的Gif带有黑色边框

时间:2020-05-22 15:19:59

标签: python python-imaging-library gif animated-gif

我正在用Pillow读取gif文件,此代码将gif文件和.png中的每个帧都输出为.gif和.png,无论是否转换为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

resulting frames

问题:

  1. 为什么rgba gif失去透明度?以及背景颜色来自哪里

  2. 为什么到处都有黑色边框?通过使用GIMP,我知道gif帧可以组合或替换以前的gif帧,这是否解释了我所看到的还是其他内容? (在本主题上,枕头是否可以自行组合/替换帧gif?)

  3. 不确定图像大小如何,explorer.exe表示68x104,但Pillow保存的帧都是85x112(firefox在查看输入的gif文件时也表示85x112)

找到PepePls.gif here

我对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,但我真的不确定

new results

这似乎也表明枕头根本不喜欢透明的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')

PeepoCreepo frames almost perfect

我仍然看到的一个问题是,如果放大f2.png,可以看到眼睛中的一些黑色缺失了。这不是gif文件的问题,因为gimp可以打开并正确显示每一帧:

PeepoCreepo gif frames in gimp

EDIT3:

Opened an issue on Github

1 个答案:

答案 0 :(得分:0)

这是PIL的已知错误,至少可以追溯到2018年2月,因此我不希望在可预见的将来进行任何修复。

可能的解决方案之一是使用外部GIF库such as mine