【问题标题】:Loss of data when extracting frames from GIF to PNG?将帧从 GIF 提取到 PNG 时丢失数据?
【发布时间】:2013-01-11 02:01:28
【问题描述】:

当我尝试使用 fraxel 的答案时

http://stackoverflow.com/questions/10269099/pil-convert-gif-frames-to-jpg

在图片上http://24.media.tumblr.com/fffcc2d8e980fbba4f87d51ed4916b87/tumblr_mh8uaqMo2I1rkp3avo2_250.gif

我得到了一些好的数据,但是对于一些我得到的数据看起来像这样,例如

正确

缺失

为了显示这些,我使用 imagemagick 的 display foo* ,然后使用空间来移动图像...是否可能 imagemagick 读错了?

编辑:

即使使用 convert 然后通过 display foo* 显示,我也会得到以下信息

那么这可能是 gif 的特征吗?

【问题讨论】:

  • 似乎每一帧都不包含与前一帧相比没有变化的数据,一种压缩,所以这不是bug,这是一个特性。
  • 来自 Imagemagick 网站:OptimizeTransparency 给定一个 GIF 动画,用透明度替换子帧叠加图像中的任何像素。给定一个 GIF 动画,用透明度替换子帧覆盖图像中的任何像素,如果它不会改变结果动画超过当前的 -fuzz 因子。这应该允许现有的帧优化 GIF 动画压缩成更小的文件大小,因为一种(透明)颜色的区域更大,而不是重复上一帧的当前已布置图像的多种颜色的图案。

标签: image-processing imagemagick python-imaging-library tumblr gif


【解决方案1】:

如果你能坚持使用 ImageMagick,那么解决这个问题就很简单了:

convert input.gif -coalesce output.png

否则,您将不得不考虑如何构建每个 GIF 帧的不同形式。对于这种特定类型的 GIF,以及您的其他问题中显示的另一种 GIF,以下代码有效(请注意,在您之前的问题中,接受的答案实际上并没有使所有拆分部分透明 - 至少在最新的发布PIL):

import sys
from PIL import Image, ImageSequence

img = Image.open(sys.argv[1])

pal = img.getpalette()
prev = img.convert('RGBA')
prev_dispose = True
for i, frame in enumerate(ImageSequence.Iterator(img)):
    dispose = frame.dispose

    if frame.tile:
        x0, y0, x1, y1 = frame.tile[0][1]
        if not frame.palette.dirty:
            frame.putpalette(pal)
        frame = frame.crop((x0, y0, x1, y1))
        bbox = (x0, y0, x1, y1)
    else:
        bbox = None

    if dispose is None:
        prev.paste(frame, bbox, frame.convert('RGBA'))
        prev.save('foo%02d.png' % i)
        prev_dispose = False
    else:
        if prev_dispose:
            prev = Image.new('RGBA', img.size, (0, 0, 0, 0))
        out = prev.copy()
        out.paste(frame, bbox, frame.convert('RGBA'))
        out.save('foo%02d.png' % i)

最终你将不得不重新创建 -coalesce 所做的事情,因为上面的代码可能不适用于某些 GIF 图像。

【讨论】:

    【解决方案2】:

    您应该尝试将帧的整个历史记录保留在“背景”中,而不是:

    background = Image.new("RGB", size, (255,255,255))
    background.paste( lastframe )
    background.paste( im2 )
    

    只需在循环之前创建一次“背景”,然后只在其上粘贴()框架,它应该可以工作。

    【讨论】:

    • 您能否详细说明 - 粘贴会覆盖我所看到的所有以前的数据,因为它将白色放在以前的数据之上...
    • 我不认为它是白色的,我认为它是透明的,所以它可以正确堆叠,生成新的图像堆叠只会在图像堆栈的顶部发生变化。
    • 所以粘贴 iirc 会覆盖所有以前的数据...为什么我要在上面粘贴东西...?
    • @EiyrioüvonKauyf 这里的想法对于呈现的单个 GIF 几乎是正确的,只是需要更加小心地使用 RGBA 帧作为蒙版。在这里使用paste 很好,你想覆盖可能透明的区域(见另一个答案)。
    • @mmgp 是的......这是怎么做到的。我了解其他答案是如何做到的……不确定我在这里遗漏了什么。能详细点吗?
    猜你喜欢
    • 2016-01-22
    • 2014-12-22
    • 2017-07-24
    • 2012-03-06
    • 2021-02-01
    • 2011-06-21
    • 1970-01-01
    • 2011-12-19
    • 1970-01-01
    相关资源
    最近更新 更多