#!/usr/bin/env python3 """Turn a generated decal (a picture on a flat magenta background) into a transparent tile for the high-res atlas: magenta keyed out, scaled down without magenta fringes (premultiplied), the alpha made hard (pixels are either there or not, like the rest of the pixel art). Usage: make_decal.py raw.png out_prefix --size 128 [--gray] --gray neutral grey (a dark crack whose lines took on the magenta of the background) --strict key out only nearly pure magenta (for pink or red pictures) Writes out_prefix-.png and out_prefix--preview.png (on a grey floor, scaled up 3x). Needs Pillow. """ import argparse from PIL import Image def main(): ap = argparse.ArgumentParser() ap.add_argument("raw") ap.add_argument("out") ap.add_argument("--size", type=int, default=128) ap.add_argument("--gray", action="store_true") ap.add_argument("--strict", action="store_true") a = ap.parse_args() img = Image.open(a.raw).convert("RGBA") px = img.load() for y in range(img.height): for x in range(img.width): r, g, b, _ = px[x, y] if (r > 200 and b > 200 and g < 90) if a.strict else (r > g + 40 and b > g + 40): px[x, y] = (0, 0, 0, 0) # premultiplied scaling: transparent pixels add nothing to the colour small = img.resize((a.size, a.size), Image.BOX) sp = small.load() for y in range(a.size): for x in range(a.size): r, g, b, al = sp[x, y] if al < 110: sp[x, y] = (0, 0, 0, 0) else: k = 255 / al c = (min(255, int(r * k)), min(255, int(g * k)), min(255, int(b * k))) if a.gray: v = min(c) * 0.9 c = (int(v), int(v), int(v * 1.05)) sp[x, y] = c + (255,) # Pillow's BOX filter works on straight alpha; transparent pixels were black, so colours near # the edges come out darker, which suits the dark outlines small.save(f"{a.out}-{a.size}.png") prev = Image.new("RGBA", (a.size, a.size), (90, 86, 84, 255)) prev.alpha_composite(small) prev.resize((a.size * 3, a.size * 3), Image.NEAREST).save(f"{a.out}-{a.size}-preview.png") print(f"{a.out}-{a.size}.png") if __name__ == "__main__": main()