python - 用 Pillow 阅读的 Gif 有黑色边框

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

我正在使用 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

resulting frames

问题:
  • 为什么 rgba gif 失去了透明度?背景颜色从哪里来
  • 为什么到处都是黑边?我从使用 GIMP 中了解到可以组合或替换前一个 gif 帧,这是否解释了我所看到的内容还是其他内容? (在这个话题上,Pillow 是否自己处理合并/替换帧 gif?)
  • 不确定图像大小发生了什么,explorer.exe 说 68x104,但 Pillow 保存的帧都是 85x112(查看输入的 gif 文件时,firefox 也说 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

    这似乎也表明 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')
    

    PeepoCreepo frames almost perfect

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

    PeepoCreepo gif frames in gimp

    编辑3:

    Opened an issue on Github

    最佳答案

    这是 PIL 中的一个已知错误,至少可以追溯到 2018 年 2 月,因此我不希望在可预见的 future 有任何修复。
    一种可能的解决方案是使用外部 GIF 库 such as mine .

    关于python - 用 Pillow 阅读的 Gif 有黑色边框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61958291/

    相关文章:

    python - 如何在 Pillow Image.quantize 中使用 kmeans 参数?

    python - Raspberry RFSniffer 使用 python 读取输出

    python - Flask-sqlalchemy 属性错误 : 'function' object has no attribute 'query'

    python - 如何获取MySQL分组内的计数

    python - Django RegexValidator 在空字符串上失败

    python - PIL , im.getdata() 返回整数而不是元组

    python-3.x - Ubuntu Tkinter 安装不包括 PyImagingPhoto

    java - 调整动画 GIF 的大小,同时使用 java 保持它的动画

    decode - 如何解码GIF的应用程序扩展 block ?

    terminal - Mac Terminal-从png文件创建动画gif