Skip to content

Instantly share code, notes, and snippets.

@celsowm
Created September 28, 2025 03:34
Show Gist options
  • Select an option

  • Save celsowm/b76222c8649e49f5e305b1e77bdb85a3 to your computer and use it in GitHub Desktop.

Select an option

Save celsowm/b76222c8649e49f5e305b1e77bdb85a3 to your computer and use it in GitHub Desktop.
tga_inspector.py for Sega Saturn Jo Engine
#!/usr/bin/env python3
# tga_inspect.py
import sys, struct, collections
IMG_TYPES = {
0: "No image data",
1: "Uncompressed, color-mapped",
2: "Uncompressed, true-color",
3: "Uncompressed, grayscale",
9: "RLE, color-mapped",
10:"RLE, true-color",
11:"RLE, grayscale",
}
def read_tga_header(f):
hdr = f.read(18)
if len(hdr) != 18:
raise ValueError("Arquivo muito curto para ser TGA.")
(id_len, cmap_type, img_type,
cmap_first, cmap_len, cmap_entry_bits,
x_origin, y_origin, width, height,
pixel_depth, img_desc) = struct.unpack("<BBBHHBHHHHBB", hdr)
return {
"id_len": id_len,
"cmap_type": cmap_type,
"img_type": img_type,
"cmap_first": cmap_first,
"cmap_len": cmap_len,
"cmap_entry_bits": cmap_entry_bits,
"x_origin": x_origin,
"y_origin": y_origin,
"width": width,
"height": height,
"pixel_depth": pixel_depth,
"img_desc": img_desc,
"origin_top": bool(img_desc & 0x20),
"origin_left": not bool(img_desc & 0x10), # 0 = left-to-right
"alpha_bits": img_desc & 0x0F,
}
def main(path):
with open(path, "rb") as f:
H = read_tga_header(f)
# pula ID + (eventual) paleta para checagens simples de conteúdo
f.seek(18 + H["id_len"])
cmap_bytes = (H["cmap_len"] * H["cmap_entry_bits"] + 7) // 8
palette = f.read(cmap_bytes) if H["cmap_type"] == 1 else b""
print(f"Arquivo: {path}")
print(f"Dimensões: {H['width']}x{H['height']}")
print(f"BPP (pixel_depth): {H['pixel_depth']}")
print(f"Tipo de imagem: {H['img_type']} ({IMG_TYPES.get(H['img_type'], 'desconhecido')})")
print(f"ColorMap: type={H['cmap_type']} len={H['cmap_len']} first={H['cmap_first']} entry_bits={H['cmap_entry_bits']}")
print(f"Origem: {'TOP' if H['origin_top'] else 'BOTTOM'}-{'LEFT' if H['origin_left'] else 'RIGHT'}")
print(f"Alpha bits (desc): {H['alpha_bits']}")
if palette:
print(f"Paleta: {len(palette)} bytes (esperado ~ len*entry_bits/8)")
# Mostra 3 primeiras entradas (assumindo 24 ou 32 bits por entrada, BGR(A))
eb = H['cmap_entry_bits'] // 8
for i in range(min(H["cmap_len"], 3)):
entry = palette[i*eb:(i+1)*eb]
if len(entry) == 3:
b,g,r = entry
print(f" pal[{i:03}]=R{r} G{g} B{b}")
elif len(entry) == 4:
b,g,r,a = entry
print(f" pal[{i:03}]=R{r} G{g} B{b} A{a}")
# Regras que interessam ao jo/VDP2
problems = []
if H["pixel_depth"] != 8:
problems.append("Não é 8bpp (indexed).")
if H["cmap_type"] != 1 or H["cmap_len"] == 0:
problems.append("Sem paleta válida (cmap).")
if H["img_type"] not in (1, 9):
problems.append("Tipo não é color-mapped (1) nem RLE color-mapped (9).")
if H["img_type"] == 9:
problems.append("RLE habilitado — alguns loaders 8bpp não suportam.")
if not H["origin_top"]:
problems.append("Origem BOTTOM — experimente exportar com origem TOP (ou inverter vertical).")
if H["cmap_entry_bits"] not in (24, 32):
problems.append("Tamanho de entrada da paleta incomum (≠24/32 bits).")
if H["width"] & (H["width"]-1) or H["height"] & (H["height"]-1):
problems.append("Dimensões não potência-de-2 (pode causar problemas em planos/backgrounds).")
if problems:
print("\n⚠️ Possíveis problemas para o Saturn/jo:")
for p in problems: print(" -", p)
else:
print("\n✓ Header parece compatível para VDP2 8bpp com paleta.")
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Uso: python tga_inspect.py FLR.TGA")
sys.exit(1)
main(sys.argv[1])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment