Skip to content

Instantly share code, notes, and snippets.

@sjlongland
Last active December 19, 2015 23:43
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 sjlongland/8a0b90d850fc857610e7 to your computer and use it in GitHub Desktop.
Save sjlongland/8a0b90d850fc857610e7 to your computer and use it in GitHub Desktop.
import gd
import argparse
from sys import stdout
parser = argparse.ArgumentParser(
description='Extract bits from the border colour of each tile',
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('--image', help='Image file to parse')
parser.add_argument('--invert', help='Invert the bits',
action='store_const', default=False, const=True)
parser.add_argument('--binary', help='Write binary',
action='store_const', default=False, const=True)
parser.add_argument('--bits', help='Number of bits per grouping',
type=int, default=8)
parser.add_argument('--output', help='Output file')
parser.add_argument('--tile-w', type=int, default=12,
help='Width of FEZ tile')
parser.add_argument('--tile-h', type=int, default=12,
help='Height of FEZ tile')
parser.add_argument('--offset-x', type=int, default=1,
help='X co-ordinate of first tile')
parser.add_argument('--offset-y', type=int, default=1,
help='Y co-ordinate of first tile')
parser.add_argument('--direction', default='rd',
help='''Order of traversal, one of:
- rd ("right then down": Start top-left, scan to bottom-right,
horizontally)
- ld ("left then down": Start top-right, scan to bottom-left,
horizontally)
- ru ("right then up": Start bottom-left, scan to top-right,
horizontally)
- lu ("left then up": Start bottom-right, scan to top-left,
horizontally)
- dr ("down then right": Start top-left, scan to bottom-right,
vertically)
- dl ("down then left": Start top-right, scan to bottom-left,
vertically)
- ur ("up then right": Start bottom-left, scan to top-right,
vertically)
- ul ("up then left": Start bottom-right, scan to top-left,
vertically)''')
args = parser.parse_args()
img = gd.image(args.image)
if args.output is not None:
out = file(args.output,'w')
else:
out = stdout
# Compute number of tiles
(p_width, p_height) = img.size()
width = (p_width - args.offset_x) // args.tile_w
height = (p_height - args.offset_y) // args.tile_h
tile_pos = lambda x, y : (((x*args.tile_w) + args.offset_x), \
((y*args.tile_h) + args.offset_y))
# Enumerate a list of co-ordinates to read.
if args.direction[0] in ('d','u'):
v_dir = args.direction[0]
h_dir = args.direction[1]
hv_dir = 'v'
elif args.direction[0] in ('l','r'):
h_dir = args.direction[0]
v_dir = args.direction[1]
hv_dir = 'h'
else:
raise ValueError('Invalid direction %r' % args.direction)
x_posn = range(0, width)
y_posn = range(0, height)
if h_dir == 'l':
x_posn.reverse()
if v_dir == 'u':
y_posn.reverse()
if hv_dir == 'v':
coordinates = [tile_pos(x,y) for x in x_posn for y in y_posn]
else:
coordinates = [tile_pos(x,y) for y in y_posn for x in x_posn]
# Inversion logic
if args.invert:
read_bit = lambda p : not bool(p)
else:
read_bit = lambda p : bool(p)
# Traverse the image, collect bits.
bits = args.bits
byte = 0
for c in coordinates:
p = img.getPixel(c)
bit = read_bit(img.getPixel(c))
if args.binary:
byte <<= 1
if bit:
byte |= 1
else:
if bit:
out.write('1')
else:
out.write('0')
bits -= 1
if bits <= 0:
bits = args.bits
if args.binary:
out.write(chr(byte))
byte = 0
else:
out.write('\n')
if bits != args.bits:
if args.binary:
out.write(chr(byte))
else:
out.write('\n')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment