diff options
Diffstat (limited to 'tools/pokemontools/gfx.py')
-rw-r--r-- | tools/pokemontools/gfx.py | 938 |
1 files changed, 0 insertions, 938 deletions
diff --git a/tools/pokemontools/gfx.py b/tools/pokemontools/gfx.py deleted file mode 100644 index 2979b5a7..00000000 --- a/tools/pokemontools/gfx.py +++ /dev/null @@ -1,938 +0,0 @@ -# -*- coding: utf-8 -*- - -import os -import sys -import png -from math import sqrt, floor, ceil -import argparse -import operator - -from lz import Compressed, Decompressed - - -def split(list_, interval): - """ - Split a list by length. - """ - for i in xrange(0, len(list_), interval): - j = min(i + interval, len(list_)) - yield list_[i:j] - - -def hex_dump(data, length=0x10): - """ - just use hexdump -C - """ - margin = len('%x' % len(data)) - output = [] - address = 0 - for line in split(data, length): - output += [ - hex(address)[2:].zfill(margin) + - ' | ' + - ' '.join('%.2x' % byte for byte in line) - ] - address += length - return '\n'.join(output) - - -def get_tiles(image): - """ - Split a 2bpp image into 8x8 tiles. - """ - return list(split(image, 0x10)) - -def connect(tiles): - """ - Combine 8x8 tiles into a 2bpp image. - """ - return [byte for tile in tiles for byte in tile] - -def transpose(tiles, width=None): - """ - Transpose a tile arrangement along line y=-x. - - 00 01 02 03 04 05 00 06 0c 12 18 1e - 06 07 08 09 0a 0b 01 07 0d 13 19 1f - 0c 0d 0e 0f 10 11 <-> 02 08 0e 14 1a 20 - 12 13 14 15 16 17 03 09 0f 15 1b 21 - 18 19 1a 1b 1c 1d 04 0a 10 16 1c 22 - 1e 1f 20 21 22 23 05 0b 11 17 1d 23 - - 00 01 02 03 00 04 08 - 04 05 06 07 <-> 01 05 09 - 08 09 0a 0b 02 06 0a - 03 07 0b - """ - if width == None: - width = int(sqrt(len(tiles))) # assume square image - tiles = sorted(enumerate(tiles), key= lambda (i, tile): i % width) - return [tile for i, tile in tiles] - -def transpose_tiles(image, width=None): - return connect(transpose(get_tiles(image), width)) - -def interleave(tiles, width): - """ - 00 01 02 03 04 05 00 02 04 06 08 0a - 06 07 08 09 0a 0b 01 03 05 07 09 0b - 0c 0d 0e 0f 10 11 --> 0c 0e 10 12 14 16 - 12 13 14 15 16 17 0d 0f 11 13 15 17 - 18 19 1a 1b 1c 1d 18 1a 1c 1e 20 22 - 1e 1f 20 21 22 23 19 1b 1d 1f 21 23 - """ - interleaved = [] - left, right = split(tiles[::2], width), split(tiles[1::2], width) - for l, r in zip(left, right): - interleaved += l + r - return interleaved - -def deinterleave(tiles, width): - """ - 00 02 04 06 08 0a 00 01 02 03 04 05 - 01 03 05 07 09 0b 06 07 08 09 0a 0b - 0c 0e 10 12 14 16 --> 0c 0d 0e 0f 10 11 - 0d 0f 11 13 15 17 12 13 14 15 16 17 - 18 1a 1c 1e 20 22 18 19 1a 1b 1c 1d - 19 1b 1d 1f 21 23 1e 1f 20 21 22 23 - """ - deinterleaved = [] - rows = list(split(tiles, width)) - for left, right in zip(rows[::2], rows[1::2]): - for l, r in zip(left, right): - deinterleaved += [l, r] - return deinterleaved - -def interleave_tiles(image, width): - return connect(interleave(get_tiles(image), width)) - -def deinterleave_tiles(image, width): - return connect(deinterleave(get_tiles(image), width)) - - -def condense_image_to_map(image, pic=0): - """ - Reduce an image of adjacent frames to an image containing a base frame and any unrepeated tiles. - Returns the new image and the corresponding tilemap used to reconstruct the input image. - - If <pic> is 0, ignore the concept of frames. This behavior might be better off as another function. - """ - tiles = get_tiles(image) - new_tiles, tilemap = condense_tiles_to_map(tiles, pic) - new_image = connect(new_tiles) - return new_image, tilemap - -def condense_tiles_to_map(tiles, pic=0): - """ - Reduce a sequence of tiles representing adjacent frames to a base frame and any unrepeated tiles. - Returns the new tiles and the corresponding tilemap used to reconstruct the input tile sequence. - - If <pic> is 0, ignore the concept of frames. This behavior might be better off as another function. - """ - - # Leave the first frame intact for pics. - new_tiles = tiles[:pic] - tilemap = range(pic) - - for i, tile in enumerate(tiles[pic:]): - if tile not in new_tiles: - new_tiles.append(tile) - - if pic: - # Match the first frame exactly where possible. - # This reduces the space needed to replace tiles in pic animations. - # For example, if a tile is repeated twice in the first frame, - # but at the same relative index as the second tile, use the second index. - # When creating a bitmask later, the second index would not require a replacement, but the first index would have. - pic_i = i % pic - if tile == new_tiles[pic_i]: - tilemap.append(pic_i) - else: - tilemap.append(new_tiles.index(tile)) - else: - tilemap.append(new_tiles.index(tile)) - return new_tiles, tilemap - -def test_condense_tiles_to_map(): - test = condense_tiles_to_map(list('abcadbae')) - if test != (list('abcde'), [0, 1, 2, 0, 3, 1, 0, 4]): - raise Exception(test) - test = condense_tiles_to_map(list('abcadbae'), 2) - if test != (list('abcde'), [0, 1, 2, 0, 3, 1, 0, 4]): - raise Exception(test) - test = condense_tiles_to_map(list('abcadbae'), 4) - if test != (list('abcade'), [0, 1, 2, 3, 4, 1, 0, 5]): - raise Exception(test) - test = condense_tiles_to_map(list('abcadbea'), 4) - if test != (list('abcade'), [0, 1, 2, 3, 4, 1, 5, 3]): - raise Exception(test) - - -def to_file(filename, data): - """ - Apparently open(filename, 'wb').write(bytearray(data)) won't work. - """ - file = open(filename, 'wb') - for byte in data: - file.write('%c' % byte) - file.close() - - -def decompress_file(filein, fileout=None): - image = bytearray(open(filein).read()) - de = Decompressed(image) - - if fileout == None: - fileout = os.path.splitext(filein)[0] - to_file(fileout, de.output) - - -def compress_file(filein, fileout=None): - image = bytearray(open(filein).read()) - lz = Compressed(image) - - if fileout == None: - fileout = filein + '.lz' - to_file(fileout, lz.output) - - -def bin_to_rgb(word): - red = word & 0b11111 - word >>= 5 - green = word & 0b11111 - word >>= 5 - blue = word & 0b11111 - return (red, green, blue) - -def convert_binary_pal_to_text_by_filename(filename): - pal = bytearray(open(filename).read()) - return convert_binary_pal_to_text(pal) - -def convert_binary_pal_to_text(pal): - output = '' - words = [hi * 0x100 + lo for lo, hi in zip(pal[::2], pal[1::2])] - for word in words: - red, green, blue = ['%.2d' % c for c in bin_to_rgb(word)] - output += '\tRGB ' + ', '.join((red, green, blue)) - output += '\n' - return output - -def read_rgb_macros(lines): - colors = [] - for line in lines: - macro = line.split(" ")[0].strip() - if macro == 'RGB': - params = ' '.join(line.split(" ")[1:]).split(',') - red, green, blue = [int(v) for v in params] - colors += [[red, green, blue]] - return colors - - -def rewrite_binary_pals_to_text(filenames): - for filename in filenames: - pal_text = convert_binary_pal_to_text_by_filename(filename) - with open(filename, 'w') as out: - out.write(pal_text) - - -def flatten(planar): - """ - Flatten planar 2bpp image data into a quaternary pixel map. - """ - strips = [] - for bottom, top in split(planar, 2): - bottom = bottom - top = top - strip = [] - for i in xrange(7,-1,-1): - color = ( - (bottom >> i & 1) + - (top *2 >> i & 2) - ) - strip += [color] - strips += strip - return strips - -def to_lines(image, width): - """ - Convert a tiled quaternary pixel map to lines of quaternary pixels. - """ - tile_width = 8 - tile_height = 8 - num_columns = width / tile_width - height = len(image) / width - - lines = [] - for cur_line in xrange(height): - tile_row = cur_line / tile_height - line = [] - for column in xrange(num_columns): - anchor = ( - num_columns * tile_row * tile_width * tile_height + - column * tile_width * tile_height + - cur_line % tile_height * tile_width - ) - line += image[anchor : anchor + tile_width] - lines += [line] - return lines - - -def dmg2rgb(word): - """ - For PNGs. - """ - def shift(value): - while True: - yield value & (2**5 - 1) - value >>= 5 - word = shift(word) - # distribution is less even w/ << 3 - red, green, blue = [int(color * 8.25) for color in [word.next() for _ in xrange(3)]] - alpha = 255 - return (red, green, blue, alpha) - - -def rgb_to_dmg(color): - """ - For PNGs. - """ - word = (color['r'] / 8) - word += (color['g'] / 8) << 5 - word += (color['b'] / 8) << 10 - return word - - -def pal_to_png(filename): - """ - Interpret a .pal file as a png palette. - """ - with open(filename) as rgbs: - colors = read_rgb_macros(rgbs.readlines()) - a = 255 - palette = [] - for color in colors: - # even distribution over 000-255 - r, g, b = [int(hue * 8.25) for hue in color] - palette += [(r, g, b, a)] - white = (255,255,255,255) - black = (000,000,000,255) - if white not in palette and len(palette) < 4: - palette = [white] + palette - if black not in palette and len(palette) < 4: - palette = palette + [black] - return palette - - -def png_to_rgb(palette): - """ - Convert a png palette to rgb macros. - """ - output = '' - for color in palette: - r, g, b = [color[c] / 8 for c in 'rgb'] - output += '\tRGB ' + ', '.join(['%.2d' % hue for hue in (r, g, b)]) - output += '\n' - return output - - -def read_filename_arguments(filename): - """ - Infer graphics conversion arguments given a filename. - - Arguments are separated with '.'. - """ - parsed_arguments = {} - - int_arguments = { - 'w': 'width', - 'h': 'height', - 't': 'tile_padding', - } - arguments = os.path.splitext(filename)[0].lstrip('.').split('.')[1:] - for argument in arguments: - - # Check for integer arguments first (i.e. "w128"). - arg = argument[0] - param = argument[1:] - if param.isdigit(): - arg = int_arguments.get(arg, False) - if arg: - parsed_arguments[arg] = int(param) - - elif argument == 'arrange': - parsed_arguments['norepeat'] = True - parsed_arguments['tilemap'] = True - - # Pic dimensions (i.e. "6x6"). - elif 'x' in argument and any(map(str.isdigit, argument)): - w, h = argument.split('x') - if w.isdigit() and h.isdigit(): - parsed_arguments['pic_dimensions'] = (int(w), int(h)) - - else: - parsed_arguments[argument] = True - - return parsed_arguments - - -def export_2bpp_to_png(filein, fileout=None, pal_file=None, height=0, width=0, tile_padding=0, pic_dimensions=None, **kwargs): - - if fileout == None: - fileout = os.path.splitext(filein)[0] + '.png' - - image = open(filein, 'rb').read() - - arguments = { - 'width': width, - 'height': height, - 'pal_file': pal_file, - 'tile_padding': tile_padding, - 'pic_dimensions': pic_dimensions, - } - arguments.update(read_filename_arguments(filein)) - - if pal_file == None: - if os.path.exists(os.path.splitext(fileout)[0]+'.pal'): - arguments['pal_file'] = os.path.splitext(fileout)[0]+'.pal' - - result = convert_2bpp_to_png(image, **arguments) - width, height, palette, greyscale, bitdepth, px_map = result - - w = png.Writer( - width, - height, - palette=palette, - compression=9, - greyscale=greyscale, - bitdepth=bitdepth - ) - with open(fileout, 'wb') as f: - w.write(f, px_map) - - -def convert_2bpp_to_png(image, **kwargs): - """ - Convert a planar 2bpp graphic to png. - """ - - image = bytearray(image) - - pad_color = bytearray([0]) - - width = kwargs.get('width', 0) - height = kwargs.get('height', 0) - tile_padding = kwargs.get('tile_padding', 0) - pic_dimensions = kwargs.get('pic_dimensions', None) - pal_file = kwargs.get('pal_file', None) - interleave = kwargs.get('interleave', False) - - # Width must be specified to interleave. - if interleave and width: - image = interleave_tiles(image, width / 8) - - # Pad the image by a given number of tiles if asked. - image += pad_color * 0x10 * tile_padding - - # Some images are transposed in blocks. - if pic_dimensions: - w, h = pic_dimensions - if not width: width = w * 8 - - pic_length = w * h * 0x10 - - trailing = len(image) % pic_length - - pic = [] - for i in xrange(0, len(image) - trailing, pic_length): - pic += transpose_tiles(image[i:i+pic_length], h) - image = bytearray(pic) + image[len(image) - trailing:] - - # Pad out trailing lines. - image += pad_color * 0x10 * ((w - (len(image) / 0x10) % h) % w) - - def px_length(img): - return len(img) * 4 - def tile_length(img): - return len(img) * 4 / (8*8) - - if width and height: - tile_width = width / 8 - more_tile_padding = (tile_width - (tile_length(image) % tile_width or tile_width)) - image += pad_color * 0x10 * more_tile_padding - - elif width and not height: - tile_width = width / 8 - more_tile_padding = (tile_width - (tile_length(image) % tile_width or tile_width)) - image += pad_color * 0x10 * more_tile_padding - height = px_length(image) / width - - elif height and not width: - tile_height = height / 8 - more_tile_padding = (tile_height - (tile_length(image) % tile_height or tile_height)) - image += pad_color * 0x10 * more_tile_padding - width = px_length(image) / height - - # at least one dimension should be given - if width * height != px_length(image): - # look for possible combos of width/height that would form a rectangle - matches = [] - # Height need not be divisible by 8, but width must. - # See pokered gfx/minimize_pic.1bpp. - for w in range(8, px_length(image) / 2 + 1, 8): - h = px_length(image) / w - if w * h == px_length(image): - matches += [(w, h)] - # go for the most square image - if len(matches): - width, height = sorted(matches, key= lambda (w, h): (h % 8 != 0, w + h))[0] # favor height - else: - raise Exception, 'Image can\'t be divided into tiles (%d px)!' % (px_length(image)) - - # convert tiles to lines - lines = to_lines(flatten(image), width) - - if pal_file == None: - palette = None - greyscale = True - bitdepth = 2 - px_map = [[3 - pixel for pixel in line] for line in lines] - - else: # gbc color - palette = pal_to_png(pal_file) - greyscale = False - bitdepth = 8 - px_map = [[pixel for pixel in line] for line in lines] - - return width, height, palette, greyscale, bitdepth, px_map - - -def get_pic_animation(tmap, w, h): - """ - Generate pic animation data from a combined tilemap of each frame. - """ - frame_text = '' - bitmask_text = '' - - frames = list(split(tmap, w * h)) - base = frames.pop(0) - bitmasks = [] - - for i in xrange(len(frames)): - frame_text += '\tdw .frame{}\n'.format(i + 1) - - for i, frame in enumerate(frames): - bitmask = map(operator.ne, frame, base) - if bitmask not in bitmasks: - bitmasks.append(bitmask) - which_bitmask = bitmasks.index(bitmask) - - mask = iter(bitmask) - masked_frame = filter(lambda _: mask.next(), frame) - - frame_text += '.frame{}\n'.format(i + 1) - frame_text += '\tdb ${:02x} ; bitmask\n'.format(which_bitmask) - if masked_frame: - frame_text += '\tdb {}\n'.format(', '.join( - map('${:02x}'.format, masked_frame) - )) - - for i, bitmask in enumerate(bitmasks): - bitmask_text += '; {}\n'.format(i) - for byte in split(bitmask, 8): - byte = int(''.join(map(int.__repr__, reversed(byte))), 2) - bitmask_text += '\tdb %{:08b}\n'.format(byte) - - return frame_text, bitmask_text - - -def export_png_to_2bpp(filein, fileout=None, palout=None, **kwargs): - - arguments = { - 'tile_padding': 0, - 'pic_dimensions': None, - 'animate': False, - 'stupid_bitmask_hack': [], - } - arguments.update(kwargs) - arguments.update(read_filename_arguments(filein)) - - image, arguments = png_to_2bpp(filein, **arguments) - - if fileout == None: - fileout = os.path.splitext(filein)[0] + '.2bpp' - to_file(fileout, image) - - tmap = arguments.get('tmap') - - if tmap != None and arguments['animate'] and arguments['pic_dimensions']: - # Generate pic animation data. - frame_text, bitmask_text = get_pic_animation(tmap, *arguments['pic_dimensions']) - - frames_path = os.path.join(os.path.split(fileout)[0], 'frames.asm') - with open(frames_path, 'w') as out: - out.write(frame_text) - - bitmask_path = os.path.join(os.path.split(fileout)[0], 'bitmask.asm') - - # The following Pokemon have a bitmask dummied out. - for exception in arguments['stupid_bitmask_hack']: - if exception in bitmask_path: - bitmasks = bitmask_text.split(';') - bitmasks[-1] = bitmasks[-1].replace('1', '0') - bitmask_text = ';'.join(bitmasks) - - with open(bitmask_path, 'w') as out: - out.write(bitmask_text) - - elif tmap != None and arguments.get('tilemap', False): - tilemap_path = os.path.splitext(fileout)[0] + '.tilemap' - to_file(tilemap_path, tmap) - - palette = arguments.get('palette') - if palout == None: - palout = os.path.splitext(fileout)[0] + '.pal' - export_palette(palette, palout) - - -def get_image_padding(width, height, wstep=8, hstep=8): - - padding = { - 'left': 0, - 'right': 0, - 'top': 0, - 'bottom': 0, - } - - if width % wstep and width >= wstep: - pad = float(width % wstep) / 2 - padding['left'] = int(ceil(pad)) - padding['right'] = int(floor(pad)) - - if height % hstep and height >= hstep: - pad = float(height % hstep) / 2 - padding['top'] = int(ceil(pad)) - padding['bottom'] = int(floor(pad)) - - return padding - - -def png_to_2bpp(filein, **kwargs): - """ - Convert a png image to planar 2bpp. - """ - - arguments = { - 'tile_padding': 0, - 'pic_dimensions': False, - 'interleave': False, - 'norepeat': False, - 'tilemap': False, - } - arguments.update(kwargs) - - if type(filein) is str: - filein = open(filein) - - assert type(filein) is file - - width, height, rgba, info = png.Reader(filein).asRGBA8() - - # png.Reader returns flat pixel data. Nested is easier to work with - len_px = len('rgba') - image = [] - palette = [] - for line in rgba: - newline = [] - for px in xrange(0, len(line), len_px): - color = dict(zip('rgba', line[px:px+len_px])) - if color not in palette: - if len(palette) < 4: - palette += [color] - else: - # TODO Find the nearest match - print 'WARNING: %s: Color %s truncated to' % (filein, color), - color = sorted(palette, key=lambda x: sum(x.values()))[0] - print color - newline += [color] - image += [newline] - - assert len(palette) <= 4, '%s: palette should be 4 colors, is really %d (%s)' % (filein, len(palette), palette) - - # Pad out smaller palettes with greyscale colors - greyscale = { - 'black': { 'r': 0x00, 'g': 0x00, 'b': 0x00, 'a': 0xff }, - 'grey': { 'r': 0x55, 'g': 0x55, 'b': 0x55, 'a': 0xff }, - 'gray': { 'r': 0xaa, 'g': 0xaa, 'b': 0xaa, 'a': 0xff }, - 'white': { 'r': 0xff, 'g': 0xff, 'b': 0xff, 'a': 0xff }, - } - preference = 'white', 'black', 'grey', 'gray' - for hue in map(greyscale.get, preference): - if len(palette) >= 4: - break - if hue not in palette: - palette += [hue] - - palette.sort(key=lambda x: sum(x.values())) - - # Game Boy palette order - palette.reverse() - - # Map pixels to quaternary color ids - padding = get_image_padding(width, height) - width += padding['left'] + padding['right'] - height += padding['top'] + padding['bottom'] - pad = bytearray([0]) - - qmap = [] - qmap += pad * width * padding['top'] - for line in image: - qmap += pad * padding['left'] - for color in line: - qmap += [palette.index(color)] - qmap += pad * padding['right'] - qmap += pad * width * padding['bottom'] - - # Graphics are stored in tiles instead of lines - tile_width = 8 - tile_height = 8 - num_columns = max(width, tile_width) / tile_width - num_rows = max(height, tile_height) / tile_height - image = [] - - for row in xrange(num_rows): - for column in xrange(num_columns): - - # Split it up into strips to convert to planar data - for strip in xrange(min(tile_height, height)): - anchor = ( - row * num_columns * tile_width * tile_height + - column * tile_width + - strip * width - ) - line = qmap[anchor : anchor + tile_width] - bottom, top = 0, 0 - for bit, quad in enumerate(line): - bottom += (quad & 1) << (7 - bit) - top += (quad /2 & 1) << (7 - bit) - image += [bottom, top] - - dim = arguments['pic_dimensions'] - if dim: - if type(dim) in (tuple, list): - w, h = dim - else: - # infer dimensions based on width. - w = width / tile_width - h = height / tile_height - if h % w == 0: - h = w - - tiles = get_tiles(image) - pic_length = w * h - tile_width = width / 8 - trailing = len(tiles) % pic_length - new_image = [] - for block in xrange(len(tiles) / pic_length): - offset = (h * tile_width) * ((block * w) / tile_width) + ((block * w) % tile_width) - pic = [] - for row in xrange(h): - index = offset + (row * tile_width) - pic += tiles[index:index + w] - new_image += transpose(pic, w) - new_image += tiles[len(tiles) - trailing:] - image = connect(new_image) - - # Remove any tile padding used to make the png rectangular. - image = image[:len(image) - arguments['tile_padding'] * 0x10] - - tmap = None - - if arguments['interleave']: - image = deinterleave_tiles(image, num_columns) - - if arguments['pic_dimensions']: - image, tmap = condense_image_to_map(image, w * h) - elif arguments['norepeat']: - image, tmap = condense_image_to_map(image) - if not arguments['tilemap']: - tmap = None - - arguments.update({ 'palette': palette, 'tmap': tmap, }) - - return image, arguments - - -def export_palette(palette, filename): - """ - Export a palette from png to rgb macros in a .pal file. - """ - - if os.path.exists(filename): - - # Pic palettes are 2 colors (black/white are added later). - with open(filename) as rgbs: - colors = read_rgb_macros(rgbs.readlines()) - - if len(colors) == 2: - palette = palette[1:3] - - text = png_to_rgb(palette) - with open(filename, 'w') as out: - out.write(text) - - -def png_to_lz(filein): - - name = os.path.splitext(filein)[0] - - export_png_to_2bpp(filein) - image = open(name+'.2bpp', 'rb').read() - to_file(name+'.2bpp'+'.lz', Compressed(image).output) - - -def convert_2bpp_to_1bpp(data): - """ - Convert planar 2bpp image data to 1bpp. Assume images are two colors. - """ - return data[::2] - -def convert_1bpp_to_2bpp(data): - """ - Convert 1bpp image data to planar 2bpp (black/white). - """ - output = [] - for i in data: - output += [i, i] - return output - - -def export_2bpp_to_1bpp(filename): - name, extension = os.path.splitext(filename) - image = open(filename, 'rb').read() - image = convert_2bpp_to_1bpp(image) - to_file(name + '.1bpp', image) - -def export_1bpp_to_2bpp(filename): - name, extension = os.path.splitext(filename) - image = open(filename, 'rb').read() - image = convert_1bpp_to_2bpp(image) - to_file(name + '.2bpp', image) - - -def export_1bpp_to_png(filename, fileout=None): - - if fileout == None: - fileout = os.path.splitext(filename)[0] + '.png' - - arguments = read_filename_arguments(filename) - - image = open(filename, 'rb').read() - image = convert_1bpp_to_2bpp(image) - - result = convert_2bpp_to_png(image, **arguments) - width, height, palette, greyscale, bitdepth, px_map = result - - w = png.Writer(width, height, palette=palette, compression=9, greyscale=greyscale, bitdepth=bitdepth) - with open(fileout, 'wb') as f: - w.write(f, px_map) - - -def export_png_to_1bpp(filename, fileout=None): - - if fileout == None: - fileout = os.path.splitext(filename)[0] + '.1bpp' - - arguments = read_filename_arguments(filename) - image = png_to_1bpp(filename, **arguments) - - to_file(fileout, image) - -def png_to_1bpp(filename, **kwargs): - image, kwargs = png_to_2bpp(filename, **kwargs) - return convert_2bpp_to_1bpp(image) - - -def convert_to_2bpp(filenames=[]): - for filename in filenames: - filename, name, extension = try_decompress(filename) - if extension == '.1bpp': - export_1bpp_to_2bpp(filename) - elif extension == '.2bpp': - pass - elif extension == '.png': - export_png_to_2bpp(filename) - else: - raise Exception, "Don't know how to convert {} to 2bpp!".format(filename) - -def convert_to_1bpp(filenames=[]): - for filename in filenames: - filename, name, extension = try_decompress(filename) - if extension == '.1bpp': - pass - elif extension == '.2bpp': - export_2bpp_to_1bpp(filename) - elif extension == '.png': - export_png_to_1bpp(filename) - else: - raise Exception, "Don't know how to convert {} to 1bpp!".format(filename) - -def convert_to_png(filenames=[]): - for filename in filenames: - filename, name, extension = try_decompress(filename) - if extension == '.1bpp': - export_1bpp_to_png(filename) - elif extension == '.2bpp': - export_2bpp_to_png(filename) - elif extension == '.png': - pass - else: - raise Exception, "Don't know how to convert {} to png!".format(filename) - -def compress(filenames=[]): - for filename in filenames: - data = open(filename, 'rb').read() - lz_data = Compressed(data).output - to_file(filename + '.lz', lz_data) - -def decompress(filenames=[]): - for filename in filenames: - name, extension = os.path.splitext(filename) - lz_data = open(filename, 'rb').read() - data = Decompressed(lz_data).output - to_file(name, data) - -def try_decompress(filename): - """ - Try to decompress a graphic when determining the filetype. - This skips the manual unlz step when attempting - to convert lz-compressed graphics to png. - """ - name, extension = os.path.splitext(filename) - if extension == '.lz': - decompress([filename]) - filename = name - name, extension = os.path.splitext(filename) - return filename, name, extension - - -def main(): - ap = argparse.ArgumentParser() - ap.add_argument('mode') - ap.add_argument('filenames', nargs='*') - args = ap.parse_args() - - method = { - '2bpp': convert_to_2bpp, - '1bpp': convert_to_1bpp, - 'png': convert_to_png, - 'lz': compress, - 'unlz': decompress, - }.get(args.mode, None) - - if method == None: - raise Exception, "Unknown conversion method!" - - method(args.filenames) - -if __name__ == "__main__": - main() |