76 lines
3.6 KiB
Python
76 lines
3.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Genera tests/fixtures_png.h con PNG producidos por una implementación
|
|
INDEPENDIENTE (Pillow) y los píxeles RGBA esperados, para comprobar que nuestro
|
|
decodificador entiende PNG reales y no solo los que escribe Tahgibu.
|
|
Uso: python3 tools/gen_png_fixtures.py > tests/fixtures_png.h"""
|
|
import io, struct, zlib
|
|
from PIL import Image
|
|
|
|
W, H = 4, 3
|
|
|
|
def png_bytes(img, **kw):
|
|
b = io.BytesIO(); img.save(b, "PNG", **kw); return b.getvalue()
|
|
|
|
def expected(img):
|
|
rgba = img.convert("RGBA")
|
|
out = []
|
|
for y in range(H):
|
|
for x in range(W):
|
|
r, g, b, a = rgba.getpixel((x, y))
|
|
if a == 0: r = g = b = 0 # forma canónica de Tahgibu
|
|
out += [r, g, b, a]
|
|
return out
|
|
|
|
def pat(f):
|
|
return [f(x, y) for y in range(H) for x in range(W)]
|
|
|
|
fixtures = []
|
|
# RGBA 8
|
|
im = Image.new("RGBA", (W, H)); im.putdata(pat(lambda x, y: (x * 60, y * 100, 200 - x * 10, 255 if (x + y) % 3 else (x + y) * 20)))
|
|
fixtures.append(("rgba8", png_bytes(im), expected(im)))
|
|
# RGB 8
|
|
im = Image.new("RGB", (W, H)); im.putdata(pat(lambda x, y: (x * 50, y * 90, 17 * (x + y))))
|
|
fixtures.append(("rgb8", png_bytes(im), expected(im)))
|
|
# Gris 8
|
|
im = Image.new("L", (W, H)); im.putdata(pat(lambda x, y: x * 40 + y * 10))
|
|
fixtures.append(("gray8", png_bytes(im), expected(im)))
|
|
# Gris + alfa
|
|
im = Image.new("LA", (W, H)); im.putdata(pat(lambda x, y: (x * 30 + 5, 255 - y * 100)))
|
|
fixtures.append(("graya8", png_bytes(im), expected(im)))
|
|
# Paleta con transparencia (tRNS)
|
|
im = Image.new("P", (W, H)); pal = []
|
|
for i in range(4): pal += [i * 60, 255 - i * 60, i * 20]
|
|
im.putpalette(pal + [0] * (768 - len(pal))); im.putdata(pat(lambda x, y: (x + y) % 4))
|
|
fixtures.append(("palette_trns", png_bytes(im, transparency=bytes([255, 128, 0, 255])), None))
|
|
pm = Image.open(io.BytesIO(fixtures[-1][1])).convert("RGBA")
|
|
fixtures[-1] = (fixtures[-1][0], fixtures[-1][1], [v for y in range(H) for x in range(W) for v in ((0,0,0,0) if pm.getpixel((x,y))[3]==0 else pm.getpixel((x,y)))])
|
|
# 1 bit
|
|
im = Image.new("1", (W, H)); im.putdata(pat(lambda x, y: 255 if (x + y) % 2 else 0))
|
|
fixtures.append(("bilevel", png_bytes(im), expected(im)))
|
|
# Paleta de 2 bits (4 colores) con filtros variados
|
|
im = Image.new("P", (W, H)); im.putpalette([255,0,0, 0,255,0, 0,0,255, 255,255,0] + [0]*756); im.putdata(pat(lambda x, y: (x * 2 + y) % 4))
|
|
fixtures.append(("palette2bit", png_bytes(im, bits=2), None))
|
|
pm = Image.open(io.BytesIO(fixtures[-1][1])).convert("RGBA")
|
|
fixtures[-1] = (fixtures[-1][0], fixtures[-1][1], [v for y in range(H) for x in range(W) for v in pm.getpixel((x,y))])
|
|
# Gris 16 bits
|
|
im = Image.new("I;16", (W, H)); im.putdata(pat(lambda x, y: x * 4000 + y * 9000))
|
|
data = png_bytes(im)
|
|
exp = []
|
|
for y in range(H):
|
|
for x in range(W):
|
|
v = (x * 4000 + y * 9000) >> 8
|
|
exp += [v, v, v, 255]
|
|
fixtures.append(("gray16", data, exp))
|
|
|
|
print("/* GENERADO por tools/gen_png_fixtures.py con Pillow: no editar a mano. */")
|
|
print("#ifndef TGB_FIXTURES_PNG_H\n#define TGB_FIXTURES_PNG_H\n#include <stddef.h>\n#include <stdint.h>")
|
|
print("#define FIX_W %d\n#define FIX_H %d" % (W, H))
|
|
for name, data, exp in fixtures:
|
|
print("static const uint8_t fix_%s[] = {%s};" % (name, ",".join(str(b) for b in data)))
|
|
print("static const uint8_t fix_%s_px[] = {%s};" % (name, ",".join(str(v) for v in exp)))
|
|
print("typedef struct { const char *name; const uint8_t *png; size_t len; const uint8_t *px; } png_fixture;")
|
|
print("static const png_fixture png_fixtures[] = {")
|
|
for name, data, exp in fixtures:
|
|
print(' {"%s", fix_%s, sizeof fix_%s, fix_%s_px},' % (name, name, name, name))
|
|
print("};\n#endif")
|