#!/usr/bin/env python3 """Emit the Kissaten palette in every format the art tools want. python3 tools/make_palettes.py .gpl GIMP / Inkscape / Krita / Aseprite .ase Affinity (Photo, Designer, Publisher), Illustrator .aco Affinity, Photoshop .act Photoshop indexed-colour tables .png 16x1 exact + a swatch strip, and a palette reference for generators Two sets are written: the full 16 (scene work) and the 11-colour portrait subset with the sky slots and the transparent index removed. """ import struct, os, sys sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from pixtool import PALETTE, write_png NAMES = ["transparent", "outline", "dark wood", "mid wood", "light wood", "lamp glow", "cream", "muted wall", "dusk deep", "dusk violet", "dusk rose", "horizon amber", "coffee", "coat blue", "skin", "warm white"] PORTRAIT_IDX = [1, 2, 3, 4, 5, 6, 7, 12, 13, 14, 15] OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "art") def gpl(path, cols, names, title): L = [f"GIMP Palette", f"Name: {title}", f"Columns: {len(cols)}", "#"] for c, n in zip(cols, names): L.append(f"{c[0]:3d} {c[1]:3d} {c[2]:3d}\t{n}") open(path, "w").write("\n".join(L) + "\n") def ase(path, cols, names): blocks = b"" for c, n in zip(cols, names): nm = n.encode("utf-16-be") + b"\x00\x00" body = (struct.pack(">H", len(n) + 1) + nm + b"RGB " + struct.pack(">fff", c[0] / 255, c[1] / 255, c[2] / 255) + struct.pack(">H", 2)) # 2 = normal colour blocks += struct.pack(">HI", 0x0001, len(body)) + body open(path, "wb").write(b"ASEF" + struct.pack(">HHI", 1, 0, len(cols)) + blocks) def aco(path, cols, names): # v1 then v2 concatenated — v1 for old readers, v2 carries the names v1 = struct.pack(">HH", 1, len(cols)) for c in cols: v1 += struct.pack(">HHHHH", 0, c[0] * 257, c[1] * 257, c[2] * 257, 0) v2 = struct.pack(">HH", 2, len(cols)) for c, n in zip(cols, names): v2 += struct.pack(">HHHHH", 0, c[0] * 257, c[1] * 257, c[2] * 257, 0) v2 += struct.pack(">I", len(n) + 1) + n.encode("utf-16-be") + b"\x00\x00" open(path, "wb").write(v1 + v2) def act(path, cols): d = bytearray() for c in cols: d += bytes(c) d += bytes(768 - len(d)) open(path, "wb").write(bytes(d)) def swatches(path, cols, sw=32, h=64): write_png(path, [[c for c in cols for _ in range(sw)]] * h) def emit(stem, idx, title): cols = [PALETTE[i] for i in idx] names = [NAMES[i] for i in idx] p = lambda ext: os.path.normpath(os.path.join(OUT, f"{stem}.{ext}")) gpl(p("gpl"), cols, names, title) ase(p("ase"), cols, names) aco(p("aco"), cols, names) act(p("act"), cols) swatches(p("png"), cols) print(f"{stem}: {len(cols)} colours -> .gpl .ase .aco .act .png") if __name__ == "__main__": emit("kissaten-full", list(range(16)), "Kissaten Yugure (full)") emit("kissaten-portrait", PORTRAIT_IDX, "Kissaten Yugure (portrait)") # exact 1px-per-entry image, for generators that take a palette image write_png(os.path.normpath(os.path.join(OUT, "palette.png")), [list(PALETTE)]) print("palette.png: 16x1 exact")