#!/usr/bin/env python3 """Turn a generated material picture into a texture for the furniture (props.rs): cropped, optionally turned into grey detail (the furniture's colours tint it in the game), brightened to a common mean and scaled to the high-res size and the pixel-art size. Usage: make_material.py raw.png out_prefix [--crop x0,y0,x1,y1] [--trim] [--color] [--mean 0.8] --crop fractions of the picture to keep --trim crop to the picture's object (everything that is not near-white background) --color keep the colours (else grey detail) --mean mean brightness of the result (0..1) Writes out_prefix-64.png and out_prefix-16.png. Needs Pillow. """ import argparse from PIL import Image, ImageOps, ImageStat def main(): ap = argparse.ArgumentParser() ap.add_argument("raw") ap.add_argument("out") ap.add_argument("--crop", default=None) ap.add_argument("--trim", action="store_true") ap.add_argument("--color", action="store_true") ap.add_argument("--mean", type=float, default=0.8) a = ap.parse_args() img = Image.open(a.raw).convert("RGB") if a.crop: f = [float(v) for v in a.crop.split(",")] img = img.crop((int(f[0] * img.width), int(f[1] * img.height), int(f[2] * img.width), int(f[3] * img.height))) if a.trim: # the object: everything darker than the white background, a few pixels in mask = img.convert("L").point(lambda v: 255 if v < 235 else 0) box = mask.getbbox() if box: img = img.crop((box[0] + 4, box[1] + 4, box[2] - 4, box[3] - 4)) if not a.color: img = ImageOps.grayscale(img).convert("RGB") mean = ImageStat.Stat(img.convert("L")).mean[0] / 255 k = a.mean / max(mean, 0.01) img = img.point(lambda v: min(255, int(v * k))) img.resize((64, 64), Image.LANCZOS).save(f"{a.out}-64.png") small = img.resize((16, 16), Image.BOX) small.quantize(colors=8, method=Image.Quantize.MEDIANCUT, dither=Image.Dither.NONE).convert("RGB").save(f"{a.out}-16.png") print(f"{a.out}-64.png, {a.out}-16.png") if __name__ == "__main__": main()