使用Pillow批量创建动态GIF

5
我将使用Python和Pillow库批量编辑.png文件。这是我第一个用Python编写脚本,因此很可能存在许多错误和/或不良编程实践。
以下是我的当前代码:
from PIL import Image
from PIL import ImageDraw
from os.path import basename
import os, sys

path = "D:\Pokemon Game\Pokemon Eggs\Import"
dirs = os.listdir( path )
box = (2,1,30,31)
moveup = (0, -3, -7, -11, -15, -19, -15, -9, -5, 2, 12, 14, 16, 17, 12, 8, 4, 0, -7, -13, -19, -11, -7, -5, -3)
topspace = (36, 38, 42, 46, 50, 55, 50, 44, 40, 34, 24, 22, 20, 18, 24, 28, 32, 36, 42, 48, 55, 46, 42, 40, 38)
bottomspace = (0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 6, 10, 14, 17, 12, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0)
Imagesizes = ((56, 60), (56, 58), (56, 54), (56, 50), (56, 46), (56, 41), (56, 46), (56, 52), (56, 56), (56, 60), (56, 66), (56, 64), (56, 62), (56, 60), (56, 60), (56, 60), (56, 60), (56, 60), (56, 54), (56, 48), (56, 41), (56, 50), (56, 54), (56, 56), (56, 58))

for file in dirs:
    #Pick an image file you have in the working directory
    egg = Image.open("D:\Pokemon Game\Pokemon Eggs\Import\%s" % str(file))

    #Crops white out of image
    egg = egg.crop(box)

    #Resizes image
    egg = egg.resize((56, 60), Image.NEAREST)

    #Stretch individual images
    frames = []
    for size in Imagesizes:
        frames.append(egg.resize(size, Image.NEAREST))

    #Resize canvas for each individual image - make sure it is clear
    for i,image in enumerate(frames):
        canvassize = (-20, -36 + moveup[i], 76, 60 + moveup[i])
        frames[i]=image.crop(canvassize)

    #Fix transparency
    for i,image in enumerate(frames):
        transparent_area1 = (0,0,20,96)
        transparent_area2 = (76,0,96,96)
        transparent_area3 = (0,0,96,(topspace[i]))
        transparent_area4 = (0,(96-bottomspace[i]), 96, 96)
        image.convert('RGBA')
        mask=Image.new("1", (96, 96), color=255)
        draw=ImageDraw.Draw(mask) 
        draw.rectangle(transparent_area1, fill=0)
        draw.rectangle(transparent_area2, fill=0)
        draw.rectangle(transparent_area3, fill=0)
        draw.rectangle(transparent_area4, fill=0)
        image.putalpha(mask)

    #Convert to GIF

我的目标是使无生命的蛋图像最终像下面显示的动画图像一样: http://i.imgur.com/NACaqCI.png http://imgur.com/a/xYAq9 我代码中的问题首先在于,从第35行到第47行的整个部分导致透明度丢失(这是由于第47行造成的)。而我不知道如何将列表(图像)转换为动态GIF。

GIF 透明和普通 alpha 透明是完全不同的东西,我不确定 Pillow 是否能够处理这些转换 - 我从未测试过。根据我之前使用 PIL 的经验,我猜测它会完全搞砸。 - Mark Ransom
@MarkRansom 我的代码无法生成GIF,我在增加画布大小时遇到了困难,因为当我调整画布大小使其更大时,任何新像素都会变成黑色。为了解决这个问题,我尝试在掩膜对象中绘制透明矩形,然后使用原始图像与掩膜,但是现在任何原始透明像素都变成了白色,只有来自透明矩形的像素保持透明。 - kriNon
1个回答

1

不建议使用'resize'作为反向裁剪,建议创建一个新的图像,并将原始图像粘贴在其上。这解决了黑色新像素的问题。

在粘贴时,您可以提供一个掩码 - https://pillow.readthedocs.io/en/5.2.x/reference/Image.html#PIL.Image.Image.paste - 这意味着原始图像仅粘贴在掩码指示的部分,而不是简单的矩形。

对于下一部分中的几个项目,https://pillow.readthedocs.io/en/5.2.x/handbook/image-file-formats.html#saving 进行了进一步的解释。

在保存时,GIF 使用额外的参数“透明度”和“处理”。处理用于控制下一帧如何使用前一帧——新帧是否粘贴在其上?它是否忽略它?

关于创建动画GIF,Pillow库有两个参数可用:'save_all' 用于保存多帧图像,'append_images' 用于将附加帧添加到第一帧图像中。
因此,请将您代码的下半部分更改为以下内容 -
#Resize canvas for each individual image - make sure it is clear
for i,image in enumerate(frames):
    frame = Image.new('RGBA', (76 + 20, 60 + moveup[i] - (-36 + moveup[i])), '#fff')
    image = image.convert('RGBA')
    frame.paste(image, (20, 36 - moveup[i]), image)
    frames[i] = frame

#Convert to GIF
frames[0].save('out.gif', save_all=True, append_images=frames[1:], transparency=0, disposal=2)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接