Skip to content

Instantly share code, notes, and snippets.

@uyjulian
Created October 25, 2025 02:42
Show Gist options
  • Select an option

  • Save uyjulian/7ddb2553c5c69360e69728eb17c7bd71 to your computer and use it in GitHub Desktop.

Select an option

Save uyjulian/7ddb2553c5c69360e69728eb17c7bd71 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
# Converts uncompressed headered OSDSYS textures to PNG
import sys
import struct
dat = b""
with open(sys.argv[1], "rb") as f:
dat = f.read()
hdr_magic, hdr_type, hdr_size = struct.unpack("<III", dat[0:12])
if hdr_magic != 0x00000010:
raise Exception("invalid header magic")
effective_offset = 0
effective_palette_size = 0
image_bpp = 0
effective_stride = 0
image_width = 0
image_height = 0
effective_total_size = 0
effective_gsfmt = None
xhdr_type = hdr_type & 7
if xhdr_type == 0:
effective_offset = 64
effective_palette_size = 32
image_bpp = 4
effective_gsfmt = 20 # PSMT4
effective_stride = int.from_bytes(dat[60:62], byteorder="little")
image_width = 4 * effective_stride
image_height = int.from_bytes(dat[62:64], byteorder="little")
effective_total_size = image_width * image_height
elif xhdr_type == 1:
effective_offset = 544
effective_palette_size = 512
image_bpp = 8
effective_gsfmt = 19 # PSMT8
effective_stride = int.from_bytes(dat[540:542], byteorder="little")
image_width = 2 * effective_stride
image_height = int.from_bytes(dat[542:544], byteorder="little")
effective_total_size = image_width * image_height
elif xhdr_type == 2: # used
image_bpp = 16
effective_gsfmt = 2 # PSMCT16
effective_offset = 20
effective_stride = int.from_bytes(dat[16:18], byteorder="little")
image_width = effective_stride
image_height = int.from_bytes(dat[18:20], byteorder="little")
effective_total_size = 2 * image_width * image_height
elif xhdr_type == 3:
image_bpp = 24
effective_gsfmt = 1 # PSMCT24
effective_offset = 20
effective_stride = int.from_bytes(dat[16:18], byteorder="little")
image_width = 2 * effective_stride // 3
image_height = int.from_bytes(dat[18:20], byteorder="little")
effective_total_size = 3 * image_width * image_height
elif xhdr_type == 4: # used
image_bpp = 32
effective_gsfmt = 0 # PSMCT32
effective_offset = 20
effective_stride = int.from_bytes(dat[16:18], byteorder="little")
image_width = effective_stride >> 1
image_height = int.from_bytes(dat[18:20], byteorder="little")
effective_total_size = 4 * image_width * image_height
else:
raise Exception("invalid texture format in header")
if effective_offset + 4 + effective_total_size != len(dat):
raise Exception("dimensions does not agree with size")
if image_width == 0 or image_height == 0:
raise Exception("empty image")
image_data = None
image_data_segm = dat[effective_offset:effective_offset + effective_total_size]
if effective_gsfmt == 0:
# fix alpha
image_data = bytearray(image_data_segm)
for i in range(0, len(image_data), 4):
image_data[i + 3] = 0xFF if (image_data[i + 3] & 0x80) != 0 else (image_data[i + 3] << 1)
elif effective_gsfmt == 1:
pass
elif effective_gsfmt == 2:
# convert 1555 to 8888
image_bpp = 32
effective_gsfmt = 0
effective_total_size = 4 * image_width * image_height
image_data = bytearray(effective_total_size)
for i in range(image_width * image_height):
pixel = image_data_segm[i * 2] | (image_data_segm[(i * 2) + 1] << 8)
image_data[(i * 4) + 3] = (((pixel >> 15) & 0x01) * 0xFF) & 0xFF
image_data[(i * 4) + 2] = (((pixel >> 0) & 0x1F) * 0xFF // 0x1F) & 0xFF
image_data[(i * 4) + 1] = (((pixel >> 5) & 0x1F) * 0xFF // 0x1F) & 0xFF
image_data[(i * 4) + 0] = (((pixel >> 10) & 0x1F) * 0xFF // 0x1F) & 0xFF
else:
raise Exception("unhandled type")
if effective_gsfmt == 0:
found_nonzero_alpha = False
for i in range(0, len(image_data), 4):
if image_data[i + 3] != 0:
found_nonzero_alpha = True
break
if not found_nonzero_alpha:
# convert 8888 to 888
image_bpp = 24
effective_gsfmt = 1
effective_total_size = 3 * image_width * image_height
old_image_data = image_data
image_data = bytearray(effective_total_size)
for i in range(image_width * image_height):
image_data[i * 3:(i + 1) * 3] = old_image_data[i * 4:(i * 4) + 3]
if True:
with open(sys.argv[2], "wb") as wf:
import io
import zlib
wf.write(b"\x89PNG\r\n\x1a\n")
def write_png_chunk(wf, ident, d):
wf.write(len(d).to_bytes(4, byteorder="big"))
wf.write(ident[0:4])
wf.write(d)
wf.write((zlib.crc32(d, zlib.crc32(ident[0:4]))).to_bytes(4, byteorder="big"))
ihdr_depth = 8
ihdr_color_type = None
if effective_gsfmt == 0:
ihdr_color_type = 6
elif effective_gsfmt == 1:
ihdr_color_type = 2
if ihdr_color_type == None:
raise Exception("invalid color type")
# Width, Height, Depth, Color type, Compression, Filter, Interlace
ihdr_str = struct.pack(">IIBBBBB", image_width, image_height, ihdr_depth, ihdr_color_type, 0, 0, 0)
write_png_chunk(wf, b"IHDR", ihdr_str)
row_stride = ((image_bpp * image_width) // 8)
cbio = io.BytesIO()
cobj = zlib.compressobj(level=1)
for row in range(image_height):
cbio.write(cobj.compress(b"\x00"))
out_offset = row * row_stride
cbio.write(cobj.compress(image_data[out_offset:out_offset + row_stride]))
cbio.write(cobj.flush())
write_png_chunk(wf, b"IDAT", cbio.getbuffer())
write_png_chunk(wf, b"IEND", b"")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment