| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677 |
- #!/usr/bin/env python3
- import argparse
- import io
- import logging
- import os
- import struct
- from PIL import Image, ImageOps
- # XBM flipper sprite (.fxbm) is 1-bit depth, width-padded to 8 bits
- # file format:
- # uint32 size of the rest of the file in bytes
- # uint32 width in px
- # uint32 height in px
- # uint8[] pixel data, every row is padded to 8 bits (like XBM)
- def image2xbm(input_file_path):
- with Image.open(input_file_path) as im:
- with io.BytesIO() as output:
- bw = im.convert("1")
- bw = ImageOps.invert(bw)
- bw.save(output, format="XBM")
- return output.getvalue()
- def xbm2fxbm(data):
- # hell as it is, but it works
- f = io.StringIO(data.decode().strip())
- width = int(f.readline().strip().split(" ")[2])
- height = int(f.readline().strip().split(" ")[2])
- data = f.read().strip().replace("\n", "").replace(" ", "").split("=")[1][:-1]
- data_str = data[1:-1].replace(",", " ").replace("0x", "")
- image_bin = bytearray.fromhex(data_str)
- output = struct.pack("<I", len(image_bin) + 8)
- output += struct.pack("<II", width, height)
- output += image_bin
- return output
- def process_sprites(input_dir, output_dir):
- for root, dirs, files in os.walk(input_dir):
- for file in files:
- input_file_path = os.path.join(root, file)
- rel_path = os.path.relpath(input_file_path, input_dir)
- new_rel_path = os.path.splitext(rel_path)[0] + ".fxbm"
- output_file_path = os.path.join(output_dir, new_rel_path)
- os.makedirs(os.path.dirname(output_file_path), exist_ok=True)
- print(f"Converting '{rel_path}' to '{new_rel_path}'")
- with open(output_file_path, "wb") as f:
- xbm = image2xbm(input_file_path)
- f.write(xbm2fxbm(xbm))
- def clear_directory(directory):
- for root, dirs, files in os.walk(directory, topdown=False):
- for name in files:
- os.remove(os.path.join(root, name))
- for name in dirs:
- os.rmdir(os.path.join(root, name))
- def main():
- parser = argparse.ArgumentParser()
- parser.add_argument("source", help="Source directory")
- parser.add_argument("target", help="Target directory")
- args = parser.parse_args()
- logging.basicConfig(level=logging.ERROR)
- logger = logging.getLogger(__name__)
- logger.debug(f"Building sprites from {args.source} to {args.target}")
- clear_directory(args.target)
- process_sprites(args.source, args.target)
- return 0
- if __name__ == "__main__":
- main()
|