Image Extraction from Sprite Sheets
Introduction
My middle school students needed a quick way to extract sprites from sprite sheets to use in their Pygame Zero projects.
Code
I made a simple GUI allowing students to easily extract sprites from a spritesheet. Each of the sprites need to be the same size.
With the Pygame Zero Helper library, the students can now easily add animations to their projects.
I encourage the students to make the code more user friendly and add any features they think might be helpful.
import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageDraw, ImageTk
from os import mkdir, path
filename = "No File Selected"
def choose_file():
global filename
filename = filedialog.askopenfilename(
filetypes=[
('PNG files', '*.png *.PNG')
]
)
file_selected['text'] = path.basename(filename)
show_grid(filename)
def extract_images(file):
if file != "No File Selected":
sheet = Image.open(file)
image_prefix = prefix.get()
size = scale.get()
directory = "extracted sprites"
if not path.exists(f"{path.dirname(file)}/{directory}"):
mkdir(f"{path.dirname(file)}/{directory}")
count = 1
width, height = sheet.size
for y in range(0, height + 1, size):
for x in range(0, width + 1, size):
image = sheet.crop((x, y, x+size, y+size))
alpha_range = image.getextrema()[-1]
if alpha_range != (0, 0):
image.save(
f"{path.dirname(file)}/{directory}/{image_prefix}_{str(count).zfill(3)}.png")
count += 1
status_label['text'] = "Done!"
def show_grid(file):
if file != "No File Selected":
sheet = Image.open(file)
width, height = sheet.size
step = scale.get()
draw = ImageDraw.Draw(sheet)
for y in range(0, height + 1, step):
draw.line((0, y, width, y), fill=(255, 0, 0), width=1)
draw.line((0, height-1, width, height-1), fill=(255, 0, 0), width=1)
for x in range(0, width + 1, step):
draw.line((x, 0, x, height), fill=(255, 0, 0), width=1)
draw.line((width-1, 0, width-1, height), fill=(255, 0, 0), width=1)
sprite_images = ImageTk.PhotoImage(sheet)
spritesheet.config(image=sprite_images)
spritesheet.image = sprite_images
root = tk.Tk()
root.title('Sprite Image Extraction')
root.geometry('+50+50')
controls = tk.Frame(root, borderwidth=1, relief='solid')
controls.grid(row=1, column=2, padx=(20, 20), pady=(0, 20), sticky=tk.E)
scale = tk.IntVar(value=32)
prefix = tk.StringVar(value="sprite")
title = tk.Label(root,
text="Select Spritesheet",
font="Arial 16 bold",)
title.grid(row=0, column=0, columnspan=3, pady=(10, 20))
file_selected = tk.Label(controls,
text="No Sprite Sheet Selected",
font="Arial 11 normal",
fg='black')
file_selected.grid(row=1, column=0, columnspan=2, pady=(0, 20))
grid_size = tk.Scale(controls,
variable=scale,
from_=8,
to=104,
resolution=2,
length=300,
width=20,
orient=tk.HORIZONTAL,
tickinterval=8,
command=lambda scale: show_grid(filename))
grid_size.grid(row=5, column=0, columnspan=2, padx=20, pady=(5, 0))
select_file_button = tk.Button(
controls,
text="Select File",
command=choose_file,
font="Arial 11 normal")
select_file_button.grid(row=0, column=0, columnspan=2,
pady=(20, 5), padx=20, sticky=tk.NW)
prefix_label = tk.Label(controls, text="Enter Prefix:",
font="Arial 11 normal")
prefix_label.grid(row=2, column=0, padx=(20, 0))
prefix_entry = tk.Entry(controls, width=30, textvariable=prefix,
font="Arial 11 normal")
prefix_entry.grid(row=2, column=1, pady=20, padx=(0, 20))
status_label = tk.Label(controls, text="", fg='blue', font="Arial 11 normal")
status_label.grid(row=6, column=0, sticky=tk.SW, padx=20, pady=20)
extract = tk.Button(controls, text="Extract Images",
font="Arial 11 normal",
command=lambda: extract_images(filename))
extract.grid(row=6, column=1, sticky=tk.SE, columnspan=2, padx=20, pady=20)
spritesheet = tk.Label(root,
text="No Sprite Sheet Selected",
font=("Arial 11 normal"),
fg='red')
spritesheet.grid(row=1, column=0, columnspan=2,
rowspan=7, padx=(20, 0), pady=(0, 20))
root.mainloop()