sotn-decomp/tools/png2bin.py

47 lines
1.3 KiB
Python
Raw Normal View History

Python virtualenv Support (#1620) Ubuntu/Debian and Python recommend using virtual environments for project-specific Python dependencies and as of Ubuntu 24 this is lightly enforced when installing packages via pip. This is due to pip and the system package manager installing files to the same location which may cause either's internal state to no longer reflect what is actually installed. This updates the project to use a Python `virtualenv` for project dependencies and updates internal scripts to support both global and virtualenvs, but favors virtualenvs for new workspaces. All tools that hardcode `/usr/bin/python3` now use `env(1)` to find the first `python3` in the path. For those with a virtualenv configured, this will be the Python managed there. For everyone else, this should be the system Python or whatever other scheme they may have used previously (assuming `python3` already existed in their `PATH`). The `Makefile` has been updated to prepend `.venv/bin` to the `PATH` and use `python3` from there if it exists and has been configured. It also has a new `python-dependencies` target which will configure the venv and install all python dependnecies there. The `Dockerfile` has been updated to create an external `.venv` outside of the project directory. Python's `virtualenv`s are not relocatable and may hardcode paths which are mounted differently in the container and host. To deal with differences in paths between the container (which mounts the host's project directory to `/sotn`) host which may be at an arbitarary directory the `VENV_PATH` environment variable is used to override paths in the `Makefile`. GitHub workflows have been updated to use `.venv`.
2024-09-18 06:19:20 +00:00
#!/usr/bin/env python3
import argparse
import png
def get_encoded_image(file_name: str) -> bytearray:
img = png.Reader(file_name).read()
width = img[0]
height = img[1]
rows = img[2]
info = img[3]
palette = info["palette"]
if width != 256:
return f"'{file_name}' width must be 256 but found {width} instead"
if height != 128:
return f"'{file_name}' height must be 128 but found {height} instead"
if info["planes"] != 1 or info["bitdepth"] != 8:
return f"'{file_name}' must be an indexed image"
if len(palette) != 16:
return f"'{file_name}' palette must be of 16 colors but found {len(palette)} colors instead"
data = bytearray((width * height) >> 1)
idx = 0
nibble = False
for row in rows:
for ch in row:
if nibble == False:
nibble = True
data[idx] = ch
else:
nibble = False
data[idx] |= ch << 4
idx += 1
return data
parser = argparse.ArgumentParser(description="convert 4bpp PNGs into binary")
parser.add_argument("input")
parser.add_argument("output")
if __name__ == "__main__":
args = parser.parse_args()
data = get_encoded_image(args.input)
with open(args.output, "wb") as f_out:
f_out.write(data)