Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Pillow to batch create animated GIFs

I am trying to use Python to batch edit .png files using the Pillow library. This is my first script using python and as such it is likely that there will be many errors and/or bad programming practise.

Here is my current code:

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

My aim is to make the inanimate egg image end up like the animated image shown below:

http://i.imgur.com/NACaqCI.pnghttp://imgur.com/a/xYAq9

The issues I have with my code are that firstly, the whole section between line 35 and line 47 results in the loss of transparancy (this is due to line 47). And I do not know how I would convert the list (image) into an animated GIF.

like image 314
kriNon Avatar asked Nov 09 '22 22:11

kriNon


1 Answers

Instead of using 'resize' as a reverse crop, I would suggest creating a new image, and pasting the original image on top of it. This solves the issue of the black new pixels.

When pasting, you can supply a mask - https://pillow.readthedocs.io/en/5.2.x/reference/Image.html#PIL.Image.Image.paste - which will mean that the original image is pasted only in the parts indicated by mask, rather than a simple rectangle.

For a few of the items in the next part, https://pillow.readthedocs.io/en/5.2.x/handbook/image-file-formats.html#saving explains further.

When saving, GIF uses the additional parameters 'transparency' and 'disposal'. Disposal is used to control how the next frame uses the previous one - is the new frame pasted on top of it? Does it ignore it?

As for creating an animated GIF, Pillow has the arguments 'save_all', to save a multiframe image, and 'append_images' to add the additional frames to the first image.

So, change the lower part of your code to this -

#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)
like image 149
radarhere Avatar answered Nov 14 '22 21:11

radarhere