【问题标题】:How to read and write animated GIF with transparency如何读写具有透明度的动画 GIF
【发布时间】:2021-03-29 03:00:52
【问题描述】:

这是我手头的(理论上)简单的任务:

  1. 从磁盘(或缓冲区)加载透明动画 GIF
  2. 将所有单独的帧转换为 NumPy 数组。每一帧带有阿尔法通道
  3. 将 NumPy 数组保存回透明动画 GIF

输出文件大小无关紧要,我真正需要的是两个相同的 GIF - 原始输入图像和第 3 步中保存的图像。

什么对我来说很重要,尽管它的解码/编码速度因此不考虑纯 Python 解决方案(没有 C 绑定到底层成像库)。

附上(在最底部),您将找到我用于测试的示例 GIF。

我尝试了几乎所有想到的方法。生成的 GIF(第 3 步)要么被严重破坏,仅以灰度渲染,要么(充其量)失去透明度并保存在白色或黑色背景上。

这是我尝试过的:

枕着阅读:

from PIL import Image, ImageSequence

im = Image.open("animation.gif")

npArray = []

for frame in ImageSequence.Iterator(im):
    npArray.append(np.array(frame))

return npArray

使用 imageio 阅读:

import imageio

npArr = []

im = imageio.get_reader("animation.gif")

for frame in im:
    npArr.append(np.array(frame))

return npArr

使用 MoviePy 阅读:

from moviepy.editor import *

npArr = []

clip = VideoFileClip("animation.gif")

for frame in clip.iter_frames():
    npArr.append(np.array(frame))

return npArr

使用 PyVips 阅读:

vi = pyvips.Image.new_from_file("animation.gif", n=-1)

pageHeight = vi.get("page-height")
frameCount = int(vi.height / pageHeight)

npArr = []

for i in range(0, frameCount):
    vi = vi.crop(0, i * pageHeight + 0, vi.width, pageHeight).write_to_memory()

    frame = np.ndarray(
            buffer = vi,
            dtype = np.uint8,
            shape = [pageHeight, vi.width, 3]
    )

    npArr.append(frame)

return npArr

用枕头保存:

images = []

for frame in frames:
    im = Image.fromarray(frame)
    images.append(im)

images[0].save(
    "output.gif",
    format = "GIF",
    save_all = True,
    loop = 0,
    append_images = images,
    duration = 40,
    disposal = 3
)

【问题讨论】:

    标签: python numpy python-imaging-library


    【解决方案1】:

    我相信您遇到了问题,因为您没有保存与每个帧关联的调色板。将每个帧转换为数组时,生成的数组不包含任何指定帧中包含哪些颜色的调色板数据。因此,当您从每一帧构建新图像时,调色板不存在,并且 Pillow 不知道它应该为该帧使用什么调色板。

    另外,保存 GIF 时,您需要指定用于透明度的颜色,我们可以直接从原始图像中提取。

    这里有一些代码(希望)能产生你想要的结果:

    from PIL import Image, ImageSequence
    import numpy as np
    
    im = Image.open("ex.gif")
    
    frames = []
    # Each frame can have its own palette in a GIF, so we need to store
    # them individually
    fpalettes = []
    transparency = im.info['transparency']
    
    for frame in ImageSequence.Iterator(im):
        frames.append(np.array(frame))
        fpalettes.append(frame.getpalette())
    
    # ... Do something with the frames
    
    images = []
    
    for i, frame in enumerate(frames):
        im = Image.fromarray(frame)
        im.putpalette(fpalettes[i])
        images.append(im)
    
    images[0].save(
            "output.gif",
            format="GIF",
            save_all=True,
            loop=0,
            append_images=images,
            duration=40,
            disposal=2,
            transparency=transparency
    )
    

    【讨论】:

      猜你喜欢
      • 2015-12-21
      • 2023-03-23
      • 2021-03-19
      • 2012-12-26
      • 2012-05-07
      • 2019-08-28
      • 2014-06-10
      • 1970-01-01
      • 2013-02-15
      相关资源
      最近更新 更多