diff options
-rw-r--r-- | pokemontools/pic.py | 72 |
1 files changed, 50 insertions, 22 deletions
diff --git a/pokemontools/pic.py b/pokemontools/pic.py index a10208f..4d5c84b 100644 --- a/pokemontools/pic.py +++ b/pokemontools/pic.py @@ -250,20 +250,36 @@ class Compressor: def compress(self): """ - Compress the image six times (twice for each mode) and use the smallest one. - - TODO: Better tiebreaking for same-size pics. + Compress the image five times (twice for each mode, except 0) + and use the smallest one (in bits). """ rams = [[],[]] datas = [] + for mode in xrange(3): - # Note: order is redundant for mode 0. + + # Order is redundant for mode 0. + + # While this seems like an optimization, + # it's actually required for 1:1 compression + # to the original compressed pics. + + # This appears to be the algorithm + # that Game Freak's compressor used. + + # Using order 0 instead of 1 breaks this feature. + for order in xrange(2): - rams[0] = self.image[0::2] - rams[1] = self.image[1::2] + if mode == 0 and order == 0: + continue + for i in xrange(2): + rams[i] = self.image[i::2] self._interpret_compress(rams, mode, order) - datas += [self.data[:]] - self.data = sorted(datas, key=len)[0] + datas += [(self.data[:], int(self.which_bit))] + + # Pick the smallest pic, measured in bits. + datas = sorted(datas, key=lambda (data, bit): (len(data), -bit)) + self.data, self.which_bit = datas[0] def _interpret_compress(self, rams, mode, order): self.data = [] @@ -418,6 +434,30 @@ def compress(f): comp.compress() return comp.data + +def decompress_file(filename): + """ + Decompress a pic given a filename. + Export the resulting planar 2bpp image to + """ + pic = open(filename, 'rb') + image = decompress(pic) + image = transpose_tiles(image) + image = bytearray(image) + output_filename = os.path.splitext(filename)[0] + '.2bpp' + with open(output_filename, 'wb') as out: + out.write(image) + +def compress_file(filename): + image = open(filename, 'rb').read() + image = transpose_tiles(image) + pic = compress(image) + pic = bytearray(pic) + output_filename = os.path.splitext(filename)[0] + '.pic' + with open(output_filename, 'wb') as out: + out.write(pic) + + def main(): ap = argparse.ArgumentParser() ap.add_argument('mode') @@ -426,21 +466,9 @@ def main(): for filename in args.filenames: if args.mode == 'decompress': - pic = open(filename, 'rb') - image = decompress(pic) - image = transpose_tiles(image) - image = bytearray(image) - output_filename = os.path.splitext(filename)[0] + '.2bpp' - with open(output_filename, 'wb') as out: - out.write(image) + decompress_file(filename) elif args.mode == 'compress': - image = open(filename, 'rb').read() - image = transpose_tiles(image) - pic = compress(image) - pic = bytearray(pic) - output_filename = os.path.splitext(filename)[0] + '.pic' - with open(output_filename, 'wb') as out: - out.write(pic) + compress_file(filename) if __name__ == '__main__': main() |