Skip to content

Instantly share code, notes, and snippets.

@magical
Created September 16, 2010 17:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save magical/582756 to your computer and use it in GitHub Desktop.
Save magical/582756 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
from struct import pack, unpack
import sys
def main(args):
if not args:
print("Usage: python3 ndsicon.py file.nds | pnmtopng > icon.png")
print("Extract the game icon from a ROM dump.")
return 1
else:
f = open(args[0], "rb")
icon = extract_icon(f)
write_ppm(icon)
return 0
return 0
def extract_icon(f):
f.seek(0x68)
icon_offset = unpack("<L", f.read(4))[0]
f.seek(icon_offset)
#print(hex(icon_offset))
assert f.read(2) == b"\x01\x00"
f.read(0x1e)
bitmap = f.read(0x200)
palette = f.read(0x20)
bitmap = untile(bitmap, 8, 8, 4, 4)
palette = unpalette(palette)
# first palette entry is transparent
palette[0] = (0,0,0,0)
return (bitmap, palette)
def write_ppm(icon):
bitmap, palette = icon
def write(bs):
sys.stdout.buffer.write(bs)
#Write the image
print("P6")
print("32 32")
print("31")
sys.stdout.flush()
for pentry in bitmap:
rgb = palette[pentry]
write(pack("BBB", *(rgb[:3])))
#write the transparency bitmap
print("P4")
print("32 32")
sys.stdout.flush()
for pentry in bitmap:
rgb = palette[pentry]
write(pack("B", bool(rgb[3])))
#Tile Width, TileHeight, image Width (in tiles), image Height (in tiles)
def untile(bitmap, tw, th, w, h):
pixels = [0] * tw*w * th*h
for ti, tile in enumerate(chunk(unpack_pixels(bitmap), tw*th)):
start = ((ti // w) * th * tw*w) + ((ti % w) * tw)
for x, row in enumerate(chunk(tile, tw)):
x = start + x * tw*w
pixels[x:x+tw] = row
return pixels
def unpalette(palette):
return [rgb16_to_rgba(unpack("<H", p)[0]) for p in chunk(palette, 2)]
def chunk(seq, length):
try:
len(seq)
except TypeError:
seq = list(seq)
for i in range(0, len(seq), length):
yield seq[i:i+length]
def unpack_pixels(bs):
for b in bs:
yield b & 0xf
yield (b >> 4) & 0xf
def rgb16_to_rgba(color):
return ((color & 0x1f),
(color >> 5) & 0x1f,
(color >> 10) & 0x1f,
255)
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment