Art: SVG -> 48x48 portrait converter, and it works

Magnific's SVG export is flat-shaded vector (~550 solid-fill paths, 6
gradients), which converts to pixel art cleanly. tools/svg2portrait.py
rasterises at 16x the target via qlmanage, then takes the most common
colour per 16x16 block — a true pixelate with no blending — and maps to
the 11-colour portrait palette.

Measured on Aki: 19 colours after pixelate, 10 after palette, visually
near-identical. So the portrait palette is sufficient for this art.

Contrast with the bitmap route this replaces: a 48x48 PNG resized in
Photoshop had 1330 unique colours in 2304 pixels, because bicubic
resampling turns flat regions into gradients. Quantising that speckled
badly across the blazer and background.

Also adds tools/pixtool.py — dependency-free PNG decode/encode (no Pillow
on this machine) plus the palette table shared with kissaten.c.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-29 20:46:12 +02:00
co-authored by Claude Opus 5
parent 1c0d2d9a88
commit db7de024de
8 changed files with 793 additions and 4 deletions
+27 -4
View File
@@ -1,9 +1,32 @@
# Kissaten Yūgure — Art brief
Pipeline: **you generate in PixelLab from the prompts below, drop the PNGs in
`art/`, and I convert them to SCREEN 5 data.** I'll write the converter
(`tools/convert_art.py`) once the first real images land — there's working
precedent in `projects/mazegame/convert_screens.py`.
## Pipeline — export SVG, not PNG
**Generate at high resolution, export as SVG, drop it in `art/`, and run:**
```
python3 tools/svg2portrait.py art/aki-neutral.svg
```
That writes `art/aki-neutral-48.png` (the real asset) and
`art/aki-neutral-48-x6.png` (a 6× preview for judging).
**Export SVG, never a resized bitmap.** This was learned the hard way. A
48×48 PNG produced by resizing in Photoshop came back with **1330 unique
colours** in 2304 pixels — bicubic resampling turns every flat region into a
gradient, and reducing *that* to 11 colours speckles horribly, worst on large
flat areas like the blazer and background.
The SVG from Magnific is flat-shaded vector: ~550 paths, solid fills, a
handful of gradients. The converter rasterises it at 768×768 (16× the target)
via `qlmanage`, then takes the **most common colour in each 16×16 block**
a true pixelate with no blending at all. Measured on Aki: 19 colours after
the pixelate, 10 after the palette reduction, and the two are nearly
indistinguishable. **The 11-colour portrait palette is sufficient for this
art** — that was the open question and it's settled.
If you must work from bitmaps, the same logic applies: resize only by exact
integer factors with nearest-neighbour, never bicubic.
---