1

I am currently trying to rip the sprites from an Nintendo DS game called Cookie Shop - Create Your Dream Shop but they are all in _LZ.bin files.

When I've unpacked its compression, I could see lots of files titles spr.bin and pal.bin Figure 1: The file list after unpacking the _LZ.bin

I know that these files are the sprites as well as their corresponding palettes but I had zero idea to open them.

I tried using CrystalTile2, but all it came out was garbled mess, both the palette and sprite.

Here are the hexadecimals for the palettes and sprites respectively. Figure 2: Palette hex Figure 3(1): Sprite hex Figure 3(2): Sprite hex (continued)

Now this is what the sprite and pallete looked like in NO$GBA. Figure 4: Output sprite Figure 5: Output palette

Pallette table OBP C (from left to right, RGB Format) 001010 0F0604 130B09 191311 1D1816 1A0C10 1C1013 1F1518 1F1C1D 1F1F1F 0F1808 151E0D 130508 1A0A0F 1D0F12 000000 (not used)

Also, the max color hex is 1F, not FF. 001010 is used as a transparency filter if I assume.

I also found sprites that were never used in the game, and I went to change the names of the characters, but it ended up freezing the game after I pressed continue.

Is it possible to extract the sprites? Because I want to use it to create a sprite sheet, as well as creating a story using these characters.

3
  • 1
    Provide a download link for a small sample of these files.
    – Jongware
    Apr 18, 2020 at 10:47
  • 1
    mega.nz/file/…
    – COR3Z
    Apr 18, 2020 at 13:20
  • Can you upload the cookie shop sprites in PNG file
    – Super451
    Aug 9, 2022 at 7:28

2 Answers 2

3

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:

bu_strawberry bu_bitter bu_crunchy bu_maccha bu_opera

2
  • Well, I am amazed! Thank you so much! P.S. 2 of those images aren’t even used in the game!
    – COR3Z
    Apr 22, 2020 at 11:45
  • I have found some sprites that require 8bpp formatting, and have a 256x192 resolution. how is it possible to extract it by changing this code?
    – COR3Z
    Apr 23, 2020 at 15:39
0

The .bin files hold the data for the sprite in bytes. You can easily dump each .bin file and interpret it as sprite data.

Back when I was writing my NES emulator, it had an extremely outdated way of handling sprites. It had a "left side" of the full list of sprites in the cartridge, which lies in 0x0000-0x1000 and then a "right side", which respectively lies in 0x1000-0x1FFF

Example being in range 0x0000-0x0010 there would respectively lie the left side of some sprite (each side was 16-bytes long). You would combine those bytes in that portion with 0x1000-0x1010 which would be the right side of the sprite.

Anyways, enough off-topic chatter. I just figured that would be interesting to you due to the similarities in structure.

You'll want to extract each byte inside of each .bin file and store each one in a separate std::uint8_t array. Then you can use something like SFML to render the pixels as raw data. I used sf::Texture::loadFromMemory to go about doing this.

If you want to raw rip the textures to image files. You'll have to convert the bytes in each .bin to a texture then output that texture as a .bmp file.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.