From 6017481d736fd3ae7aa8b1055913e873c0d514c6 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Fri, 4 Oct 2024 23:53:16 +0200 Subject: implement png2pc --- experiments/conv/consts.py | 38 ++++++++++++++++++------------- experiments/conv/makefile | 2 ++ experiments/conv/pc2png | 26 +++------------------ experiments/conv/png2pc | 56 ++++++++++++++++++++++++++++++++++++++++++++++ experiments/conv/shared.py | 19 ++++++++++++++++ 5 files changed, 102 insertions(+), 39 deletions(-) create mode 100644 experiments/conv/makefile create mode 100755 experiments/conv/png2pc create mode 100644 experiments/conv/shared.py diff --git a/experiments/conv/consts.py b/experiments/conv/consts.py index 898bd3d..e50c51a 100644 --- a/experiments/conv/consts.py +++ b/experiments/conv/consts.py @@ -1,18 +1,24 @@ +DS_TILE_SIZE = 8 +TILE_BYTES = 32 # tiles are stored in 32 bytes chunks + +TILES_HORIZONTAL = 32 + PICTOCHAT_PALETTE = ( - (0xff, 0xff, 0xff), - (0x00, 0x00, 0x00), - (0xd3, 0xcb, 0xc3), - (0xeb, 0x00, 0xeb), - (0xfb, 0x00, 0x8a), - (0xfb, 0x00, 0x28), - (0xfb, 0x49, 0x00), - (0xfb, 0xa2, 0x00), - (0xe3, 0xf3, 0x00), - (0x82, 0xfb, 0x00), - (0x10, 0xfb, 0x20), - (0x00, 0xfb, 0xba), - (0x00, 0xc3, 0xfb), - (0x00, 0x79, 0xfb), - (0x00, 0x30, 0xfb), - (0x28, 0x00, 0xfb), + (0xff, 0xff, 0xff), + (0x00, 0x00, 0x00), + (0xd3, 0xcb, 0xc3), + (0xeb, 0x00, 0xeb), + (0xfb, 0x00, 0x8a), + (0xfb, 0x00, 0x28), + (0xfb, 0x49, 0x00), + (0xfb, 0xa2, 0x00), + (0xe3, 0xf3, 0x00), + (0x82, 0xfb, 0x00), + (0x10, 0xfb, 0x20), + (0x00, 0xfb, 0xba), + (0x00, 0xc3, 0xfb), + (0x00, 0x79, 0xfb), + (0x00, 0x30, 0xfb), + (0x28, 0x00, 0xfb), ) + diff --git a/experiments/conv/makefile b/experiments/conv/makefile new file mode 100644 index 0000000..f4f3cd5 --- /dev/null +++ b/experiments/conv/makefile @@ -0,0 +1,2 @@ +%.png: %.bin + ./pc2png $< diff --git a/experiments/conv/pc2png b/experiments/conv/pc2png index 4fa7a1a..c7f131a 100755 --- a/experiments/conv/pc2png +++ b/experiments/conv/pc2png @@ -1,18 +1,10 @@ #!/bin/python3 - -import sys -import re import math import io - from PIL import Image -from consts import PICTOCHAT_PALETTE - -DS_TILE_SIZE = 8 -TILE_BYTES = 32 # tiles are stored in 32 bytes chunks - -TILES_HORIZONTAL = 32 +from consts import * +from shared import main # convert a single DS tile (8x8) from packed palette index format to RGB colors def convert_chunk(img, chunk, offset): @@ -53,18 +45,6 @@ def pc2png(data): img.save(output, format='PNG') return output.getvalue() -def convert_file(input_filename, output_filename): - with open(input_filename, 'rb') as input_file: - content = input_file.read() - output = pc2png(content) - with open(output_filename, 'wb+') as output_file: - output_file.write(output) - if __name__ == "__main__": - del sys.argv[0] - for input_filename in sys.argv: - output_filename = re.sub('.bin$', '.png', input_filename) - if not output_filename.endswith('.png'): - output_filename += '.png' - convert_file(input_filename, output_filename) + main("bin", "png", pc2png) diff --git a/experiments/conv/png2pc b/experiments/conv/png2pc new file mode 100755 index 0000000..d1eaab8 --- /dev/null +++ b/experiments/conv/png2pc @@ -0,0 +1,56 @@ +#!/bin/python3 +import itertools +import io +from PIL import Image + +from consts import * +from shared import main + +palette_img = Image.new('P', (1, 1)) +palette_img.putpalette(list(itertools.chain.from_iterable([ + *PICTOCHAT_PALETTE, + *[PICTOCHAT_PALETTE[0] for x in range(256 - len(PICTOCHAT_PALETTE))], +]))) + +def convert_chunk(img, offset): + palette_indices = [] + for y in range(DS_TILE_SIZE): + for x in range(DS_TILE_SIZE): + palette_indices.append(img.getpixel((x + offset[0], y + offset[1]))) + + bytes = bytearray() + for i in range(0, len(palette_indices), 2): + bytes.append((palette_indices[i+0] << 0) | (palette_indices[i+1] << 4)) + + return bytes + +def png2pc(data): + img = Image.open(io.BytesIO(data)) + if img.width != TILES_HORIZONTAL * DS_TILE_SIZE: + print(f"error: input image is not {TILES_HORIZONTAL * DS_TILE_SIZE} pixels wide") + exit(1) + if img.height % DS_TILE_SIZE != 0: + print(f"error: input image height not a muliple of {DS_TILE_SIZE}") + exit(1) + tile_count = (img.width * img.height) // (DS_TILE_SIZE ** 2) + + img = img.convert('RGB') + img = img.quantize(palette=palette_img) + + output = b"" + for tile_idx in range(tile_count): + tile = ( + tile_idx % TILES_HORIZONTAL, + tile_idx // TILES_HORIZONTAL, + ) + offset = ( + tile[0] * DS_TILE_SIZE, + tile[1] * DS_TILE_SIZE, + ) + output += convert_chunk(img, offset) + + return output + +if __name__ == "__main__": + main("png", "bin", png2pc) + diff --git a/experiments/conv/shared.py b/experiments/conv/shared.py new file mode 100644 index 0000000..be883be --- /dev/null +++ b/experiments/conv/shared.py @@ -0,0 +1,19 @@ +import sys + +def convert_file(input_filename, output_filename, converter): + with open(input_filename, 'rb') as input_file: + content = input_file.read() + output = converter(content) + with open(output_filename, 'wb+') as output_file: + output_file.write(output) + +def main(from_ext, to_ext, converter): + del sys.argv[0] + if len(sys.argv) == 0: + print("error: no input files!", file=sys.stderr) + exit(1) + + for input_filename in sys.argv: + output_filename = input_filename.removesuffix(f".{from_ext}") + f".{to_ext}" + convert_file(input_filename, output_filename, converter) + -- cgit v1.2.3