Created
January 20, 2025 03:58
-
-
Save deadjakk/6eb5cfde7319f0cb068b341270fdf553 to your computer and use it in GitHub Desktop.
gif-2-spritesheet
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# forked from https://github.com/JingShing/GIF-To-SpriteSheet | |
from argparse import ArgumentParser | |
from pathlib import Path | |
from PIL import Image, ImageSequence | |
import os, sys | |
def select_folder(title): | |
folder = filedialog.askdirectory(title=title) | |
return folder | |
def convert_gif_to_spritesheet(gif_path, output_folder, columns="auto"): | |
if os.path.exists(gif_path) is False: | |
print(f"error: {gif_path} does not exist") | |
exit(1) | |
if gif_path.lower().endswith('.gif') is False: | |
print(f"error: {gif_path} is not a gif") | |
exit(1) | |
with Image.open(gif_path) as gif: | |
frames = [frame.copy() for frame in ImageSequence.Iterator(gif)] | |
if frames: | |
if columns == "auto": | |
columns = len(frames) | |
else: | |
columns = int(columns) | |
frame_width, frame_height = frames[0].size | |
rows = (len(frames) + columns - 1) // columns | |
sheet_width = columns * frame_width | |
sheet_height = rows * frame_height | |
spritesheet = Image.new('RGBA', (sheet_width, sheet_height)) | |
for i, frame in enumerate(frames): | |
x = (i % columns) * frame_width | |
y = (i // columns) * frame_height | |
spritesheet.paste(frame, (x, y)) | |
if not output_folder: | |
output_folder = os.path.dirname(gif_path) | |
dirname = os.path.dirname(gif_path) | |
basename = os.path.basename(gif_path).replace(".gif",".png") | |
output_path = os.path.join(dirname, basename) | |
print(f"output path:{output_folder}") | |
spritesheet.save(output_path) | |
print(f"Saved: {output_path}") | |
def convert_gif_to_spritesheet_dir(source_folder, output_folder=None, columns="auto"): | |
for filename in os.listdir(source_folder): | |
if filename.lower().endswith('.gif') is False: | |
print(f"{filename} is not a gif, skipping...") | |
continue | |
gif_path = os.path.join(source_folder, filename) | |
convert_gif_to_spritesheet(gif_path, output_folder, columns) | |
# GUI Setup | |
def main(): | |
try: | |
from tkinter import filedialog | |
import tkinter as tk | |
except: | |
print("tkinter library is not installed, unfortunately the GUI cannot load. try passing the -i arg to bypass the GUI", file=sys.stderr) | |
exit(1) | |
root = tk.Tk() | |
root.title("GIF to SpriteSheet Converter") | |
root.geometry("500x300") | |
source_folder = None | |
output_folder = None | |
def select_source_folder(): | |
nonlocal source_folder | |
source_folder = select_folder("Select Source Folder") | |
if source_folder: | |
lbl_source.config(text=f"Source Folder: {source_folder}") | |
def select_output_folder(): | |
nonlocal output_folder | |
output_folder = select_folder("Select Output Folder") | |
if output_folder: | |
lbl_output.config(text=f"Output Folder: {output_folder}") | |
def process_conversion(): | |
columns = entry_columns.get() | |
if not columns: | |
columns = "auto" | |
if not columns.isdigit() or int(columns) < 1 or columns != "auto": | |
print("Please enter a valid number of columns or 'auto' to use the number of present frames instead.") | |
return | |
columns = int(columns) if columns != "auto" else "auto" | |
if not source_folder: | |
print("Please make sure all inputs are set.") | |
return | |
convert_gif_to_spritesheet_dir(source_folder, output_folder, columns) | |
print("Conversion completed!") | |
tk.Button(root, text="Select Source Folder", command=select_source_folder).pack(pady=5) | |
lbl_source = tk.Label(root, text="Source Folder: Not selected") | |
lbl_source.pack() | |
tk.Button(root, text="Select Output Folder", command=select_output_folder).pack(pady=5) | |
lbl_output = tk.Label(root, text="Output Folder: Not selected") | |
lbl_output.pack() | |
tk.Label(root, text="Enter number of columns (or auto to use number of GIF frames found):").pack(pady=5) | |
entry_columns = tk.Entry(root) | |
entry_columns.pack() | |
btn_convert = tk.Button(root, text="Start Conversion", command=process_conversion) | |
btn_convert.pack(pady=20) | |
root.mainloop() | |
if __name__ == "__main__": | |
parser = ArgumentParser() | |
parser.add_argument("-i", help="input GIF or directory containing GIFs to process, if this is not specified, the GUI will run") | |
parser.add_argument("-c", help="number of columns for the spritesheet, enter 'auto' to use the number of frames present in the GIF(s) (optional, you probably don't need this)", default="auto") | |
args = parser.parse_args() | |
if args.i: | |
if os.path.isdir(args.i): | |
convert_gif_to_spritesheet_dir(args.i, args.i, columns=args.c) | |
else: | |
output_folder = str(Path(args.i).resolve()) | |
convert_gif_to_spritesheet(args.i, output_folder, columns=args.c) | |
else: | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment