How to split gif into single images and distribute exe app

Split into frames one gif

This is a fully functional app with a distributable exe file, just one exe file, to make a simple thing, split the frames of a gif and save them as individual png, using a minimalistic Graphic User Interface made with the built in module tkinter.

When you launch the app you will get this GUI with just one button.

The GUI when the app is launched

After you choose your file, you will see it into the GUI.

You see the image you selected

Now you push the button at the buttom of the GUI and you will get these images in the folder.

The images from the gif’s frames generated by the app

Let’s make the exe file

Now you can use both pyinstaller of auto-py-to-exe to make it. Here is what you need to do, using auto-py-to-exe. It makes the work really easy.

Hands on the code

This is the script

import tkinter as tk
from PIL import Image, ImageTk
from PIL import Image, ImageSequence
from tkinter import filedialog
import os
import sys



def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    base_path = getattr(
        sys,
        '_MEIPASS',
        os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(base_path, relative_path)


def unpack_gif(src):
    "If disposal == 2 (unclomplete) it copies it on the previous"
    image = Image.open(src)
    frames = []
    disposal = []
    for gifFrame in ImageSequence.Iterator(image):
        disposal.append(gifFrame.disposal_method)
        frames.append(gifFrame.convert('P'))
    output = []
    lastFrame = None
    thisFrame = None
    for i, loadedFrame in enumerate(frames):
        thisFrame = loadedFrame
        if disposal[i] == 2:
            if i != 0:
                lastFrame.paste(thisFrame, mask=thisFrame.convert('RGBA'))
                output.append(lastFrame)
            else:
                output.append(thisFrame)
        elif disposal[i] == 1 or disposal[i] == 0:
            output.append(thisFrame)
        else:
            raise ValueError('Disposal Methods other than 2:Restore to Background,\
             1:Do Not Dispose, and 0:No Disposal are supported at this time')
        lastFrame = loadedFrame
    return output


def save_all_frames(file):
    "Saves all the frames of the gif as numbered png files"
    name = os.path.splitext(file[0])[0]
    im = unpack_gif(file[0])
    for n, i in enumerate(im):
        if n<10:
            zero = "0"
        else:
            zero = ""
        i.save(f"{name}{zero}{n}.png")
    print(im)


# root.withdraw()
def getfile():
    global filename
    try:
        filename = filedialog.askopenfilenames(
            parent=root,
            initialdir=".",
            initialfile='tmp',
            filetypes=[("GIF", "*.gif"),
                    ("All files", "*")]
            )
        print(filename)
        img = Image.open(resource_path(filename[0]))
        img = img.resize((150, 150))
        img = ImageTk.PhotoImage(img)
        getfile.image = img
        label["image"] = img
        button2.pack()
    except:
        pass

filename = ""
root = tk.Tk()
img2 = tk.PhotoImage(file=resource_path("gif_split.png"))
label1 = tk.Label(master=root,
    image=img2)
label1.pack()
button = tk.Button(
    master=root,
    bg="pink",
    text="Open Gif",
    command=getfile)
button.pack()
# Label with the image of the gif (after you choose it)

img3 = ImageTk.PhotoImage(file=resource_path("arrowup.png"))
label = tk.Label(master=root,
    image=img3,
    )
label.pack()
button2 = tk.Button(
    master=root,
    bg="gold",
    text="Save png files out of the gif",
    command=lambda: save_all_frames(filename))
# button2.pack()

root.mainloop()
# save_all_frames(filename)

Published by pythonprogramming

Started with basic on the spectrum, loved javascript in the 90ies and python in the 2000, now I am back with python, still making some javascript stuff when needed.