#!/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 \n#include ") 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")