Skip to content

Instantly share code, notes, and snippets.

@NWPlayer123
Created September 1, 2017 22:29
Show Gist options
  • Save NWPlayer123/14cca1d1f2a02b3f3cdf2085e9cc6cab to your computer and use it in GitHub Desktop.
Save NWPlayer123/14cca1d1f2a02b3f3cdf2085e9cc6cab to your computer and use it in GitHub Desktop.
Sonic Mania Sprite Extractor (WIP, breaks on some stuff)
from struct import unpack
from binascii import hexlify, unhexlify
from os import getcwd, mkdir
from os.path import exists
from PIL import Image
import sys
#sys.argv.append("Sonic.bin")
do_extract = 1
with open(sys.argv[1], "rb") as f:
base = "/".join(getcwd().split("\\")).split("/")
base = "/".join(base[:base.index("Data") + 1])
base = base + "/Sprites/" #for data
assert f.read(4) == b"SPR\x00" #magic
sprite_id = unpack("<I", f.read(4))[0] #???
sources = []
for i in range(ord(f.read(1))):
size = ord(f.read(1))
name = f.read(size)[:-1]
sources.append(name)
#print(name)
#print
inputs = []
for source in sources:
path = base + ".".join(source.split(".")[:-1])
if not exists(path): mkdir(path)
if do_extract:
inputs.append(Image.open(base + source))
assert f.read(1) == "\x00"
data_count = unpack("<H", f.read(2))[0]
for i in range(data_count):
size = ord(f.read(1))
name = f.read(size)[:-1]
print(name)
data = unpack("<3H", f.read(6))
for j in range(data[0]):
info = unpack("<B8H", f.read(17))
if do_extract:
path = base + ".".join(sources[info[0]].split(".")[:-1])
out = Image.new("RGB", (info[5], info[6]))
w = info[5]
h = info[6]
x = info[3]
y = info[4]
if w != 0 and h != 0:
out.paste(inputs[info[0]].crop((x, y, x + w, y + h)))
out.save(path + "/" + name + "%02d.png" % j)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment