Both files are prepended with a 4 bytes large number; apparently the total size of the data that follows. I am ignoring it because the file sizes seem fixed. (Also, for the images the other important data, its width and height, are not stored in the file.)
Palette
The palette is a 5 bits per channel BGR, with the highest bit unused. The two bytes are stored in little-endian order. Converting to True Color RGB is therefore a matter of bit shifting; you end up with 16 RGB color triplets.
Image
The image is stored in 16 x 16 blocks, each 8 x 8 pixels, and every two consecutive pixels are packed into a single byte, right pixel first. Every pixel value ranges from 0..15 and maps immediately to the palette.
To unpack a single 8x8 block, all it takes is
for y in range(8):
for x in range(4):
print (img[4*y+x]])
which yields a series of 2-pixel data. I found it more convenient, below, to unpack each two nibbles immediately into 2 separate pixels; then it's a matter of looping over the right x and y axis to reassemble the entire image in a coherent, linear, 128x128 pixel bitmap.
The code below then stores the RGB values for each pixel in a True-color PNG image; alternatively, you could save it as a palettized PNG image as well (or really any other image format you'd like).
Python 3.x code
This code needs pypng
. Adjust the fixed part of the path to your folder structure -- it should end with a slash. Save as cookie2png.py
and call from a command line with
python cookie2png.py Rose/bu_strawberry_LZ.bin\bu_strawberry_anger
i.e., leave off the parts _pal.bin
and _spr.bin
so the script can find them on its own.
import sys,png
from struct import unpack
path = "/Sprites/Character files/"
# base = 'bu_strawberry2'
base = sys.argv[1]
with open (path+base+'_pal.bin', 'rb') as p:
pal = p.read()
pal = unpack('<I16H', pal)[1:]
pal = [bin(p)[2:].zfill(15) for p in pal]
rgb = [(int(p[10:15]+p[10:13],2),int(p[5:10]+p[5:8],2),int(p[0:5]+p[0:3],2)) for p in pal]
print ('rgb palette', *['%02x%02x%02x' % (r,g,b) for r,g,b in rgb])
with open (path+base+'_spr.bin', 'rb') as i:
img = i.read()
# Strip header
img = img[4:]
# Convert nibbles to bytes
img = [[b & 0x0f,b >> 4] for b in img]
# Unpack list
img = [b for a in img for b in a]
# Linearize image
target = []
for y in range(16):
for yy in range(8):
for x in range(16):
for xx in range(8):
target.append(rgb[img[16*64*y+64*x+8*yy+xx]])
# Convert from palettized into True color
target = [color for rgb in target for color in rgb]
# Split into rows, required by pypng
target = [target[i:i + 3*128] for i in range(0, len(target), 3*128)]
w = png.Writer(128, 128, greyscale=False, bitdepth=8)
with open(path+base+'.png', 'wb') as f:
w.write(f, target)
and the results are as expected. Here is your bu_strawberry
, and a smattering of interesting others:
