【问题标题】:How to open optimized GIF without bugs?如何打开没有错误的优化 GIF?
【发布时间】:2021-09-22 23:34:48
【问题描述】:

所以这个 GIF 在打开之前看起来非常好:

但是,当使用 Pillow 打开时使用

imageObject = Image.open(path.join(petGifs, f"{pokemonName}.gif"))

它出错了,添加了各种颜色与源图像相似的框。这是一个示例帧,但几乎每一帧都是不同的,并且根据 GIF,它位于不同的位置:

唯一能解决这个问题的是 ezgif 的 unoptimize 选项(在他们的 optimize page 中找到)。但是,我需要在每个 GIF 上都这样做,而且数量很多。

我需要一种批量取消优化的方法,或者一种在 Python 中打开 GIF 的新方法(目前使用 Pillow)来处理这个问题。

【问题讨论】:

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


    【解决方案1】:

    至少对于提取正确的单帧可能有解决方案。

    所有帧(第一帧除外)的disposal方法设置为2,即“恢复背景色”。

    浏览 Pillow 的源代码,你会找到对应的line where the disposal method 2 is considered,并且,在下面,你会发现:

    # by convention, attempt to use transparency first
    color = (
        frame_transparency
        if frame_transparency is not None
        else self.info.get("background", 0)
    )
    self.dispose = Image.core.fill("P", dispose_size, color)
    

    如果您检查有缺陷的框架,您会注意到不需要框的深绿色位于调色板的位置0。因此,似乎选择了错误的颜色进行处置,因为 - 我不知道为什么 - 上面的 else 案例被选择而不是使用透明度信息 - 会在那里!

    所以,让我们覆盖可能有问题的东西:

    from PIL import Image, ImageSequence
    
    # Open GIF
    gif = Image.open('223vK.gif')
    
    # Initialize list of extracted frames
    frames = []
    
    for frame in ImageSequence.Iterator(gif):
    
        # If dispose is set, and color is set to 0, use transparency information
        if frame.dispose is not None and frame.dispose[0] == 0:
            frame.dispose = Image.core.fill('P', frame.dispose.size,
                                            frame.info['transparency'])
    
        # Convert frame to RGBA
        frames.append(frame.convert('RGBA'))
    
    # Visualization overhead
    import matplotlib.pyplot as plt
    plt.figure(figsize=(8, 8))
    for i, f in enumerate(frames, start=1):
        plt.subplot(8, 8, i), plt.imshow(f), plt.axis('off')
    plt.tight_layout(), plt.show()
    

    提取的帧如下所示:

    我觉得这很好。

    如果碰巧将透明度信息实际设置为0,则此处不应造成任何损害,因为我们(重新)设置了仍然正确的透明度信息。

    我不知道,(重新)保存到 GIF 是否可行,因为帧现在处于 RGBA 模式,从那里保存到 GIF 也很棘手。

    ----------------------------------------
    System information
    ----------------------------------------
    Platform:      Windows-10-10.0.19041-SP0
    Python:        3.9.1
    PyCharm:       2021.1.3
    Matplotlib:    3.4.2
    Pillow:        8.3.1
    ----------------------------------------
    

    【讨论】:

    • 我回家试试这个
    • 终于回家测试了,效果很好,非常感谢!
    【解决方案2】:

    你可以尝试使用:

    from PIL import Image, ImageSequence
    
    im = Image.open(f"{pokemonName}.gif")
    
    index = 1
    for frame in ImageSequence.Iterator(im):
        frame.save("frame%d.png" % index)
        index += 1
    

    【讨论】:

    • 然后您将获得问题中所述的确切工件。那么,这有什么帮助呢?
    • 是的,这就是我目前所做的[基本上]。我稍后会尝试这个,因为它略有不同[我使用 .seek() iirc],但我怀疑它实际上是否有区别。
    【解决方案3】:

    我找到了一个我喜欢的解决方案,用于对您可能有用的未优化 gif。

    它使用gifsicle 库,这是一个用于处理 gif 的命令行工具。至关重要的是,gifsicle 可以让你取消优化像你这样的 gif(我认为优化被称为“累积层”)。

    使用您选择的包管理器安装它后,您可以通过 Python 的 subprocess 库在代码中调用它,也可以从命令行自行使用。

    您特别提到了一种批量取消优化的方法,您可以通过以下方式使用 gifsicle 非常轻松地做到这一点:

    gifsicle -U -b *.gif
    

    这将同时用未优化的版本覆盖工作目录中的每个 gif。如果您想保留优化的副本,请进行备份。有关如何使用 gifsicle 的更多信息,请参阅manual page

    一旦gif未优化,python应该可以正常打开。

    【讨论】:

      猜你喜欢
      • 2016-04-02
      • 1970-01-01
      • 2011-04-23
      • 2014-05-12
      • 2011-06-15
      • 1970-01-01
      • 1970-01-01
      • 2019-05-12
      • 2014-06-25
      相关资源
      最近更新 更多