Skip to content

Instantly share code, notes, and snippets.

@illnyang
Created May 4, 2025 19:49
Show Gist options
  • Save illnyang/77da6dc1d4021e6a935e6b7b5f14ebd0 to your computer and use it in GitHub Desktop.
Save illnyang/77da6dc1d4021e6a935e6b7b5f14ebd0 to your computer and use it in GitHub Desktop.
script for converting neighbours from hell targa textures
#!/usr/bin/env python
import struct
from PIL import Image
class TGAHeader:
def __init__(self):
self.idlength = 0
self.colourmaptype = 0
self.datatypecode = 0
self.colourmaporigin = 0
self.colourmaplength = 0
self.colourmapdepth = 0
self.x_origin = 0
self.y_origin = 0
self.width = 0
self.height = 0
self.bitsperpixel = 0
self.imagedescriptor = 0
class TGAFooter:
def __init__(self):
self.extensionoffset = 0
self.developeroffset = 0
self.signature = b''
self.p = 0
self.n = 0
def convert(input_path, output_path):
with open(input_path, 'rb') as fd:
header = TGAHeader()
header.idlength = struct.unpack('B', fd.read(1))[0]
header.colourmaptype = struct.unpack('B', fd.read(1))[0]
header.datatypecode = struct.unpack('B', fd.read(1))[0]
header.colourmaporigin = struct.unpack('<h', fd.read(2))[0]
header.colourmaplength = struct.unpack('<h', fd.read(2))[0]
header.colourmapdepth = struct.unpack('B', fd.read(1))[0]
header.x_origin = struct.unpack('<h', fd.read(2))[0]
header.y_origin = struct.unpack('<h', fd.read(2))[0]
header.width = struct.unpack('<h', fd.read(2))[0]
header.height = struct.unpack('<h', fd.read(2))[0]
header.bitsperpixel = struct.unpack('B', fd.read(1))[0]
header.imagedescriptor = struct.unpack('B', fd.read(1))[0]
tga_pixel_size = header.bitsperpixel // 8
tga_data_size = header.width * header.height * tga_pixel_size
tga_data = fd.read(tga_data_size)
fd.seek(-26, 2)
footer = TGAFooter()
footer.extensionoffset = struct.unpack('<i', fd.read(4))[0]
footer.developeroffset = struct.unpack('<i', fd.read(4))[0]
footer.signature = fd.read(16)
footer.p = struct.unpack('B', fd.read(1))[0]
footer.n = struct.unpack('B', fd.read(1))[0]
# RGBA4444
if header.imagedescriptor == 36:
buffer = bytearray(header.width * header.height * 4)
j = 0
for i in range(0, len(tga_data), tga_pixel_size):
buffer[j + 0] = (tga_data[i + 1] & 0x0F) << 4
buffer[j + 1] = (tga_data[i] & 0xF0)
buffer[j + 2] = (tga_data[i] & 0x0F) << 4
buffer[j + 3] = (tga_data[i + 1] & 0xF0)
j += 4
img = Image.frombytes('RGBA', (header.width, header.height), bytes(buffer))
img.save(output_path)
# RGBA5650
elif header.imagedescriptor == 32:
buffer = bytearray(header.width * header.height * 3)
j = 0
for i in range(0, len(tga_data), tga_pixel_size):
buffer[j + 0] = tga_data[i + 1] & 0xf8
buffer[j + 1] = ((tga_data[i + 1] & 7) << 5) | ((tga_data[i] >> 3) & 0x1c)
buffer[j + 2] = (tga_data[i] & 0x1f) << 3
j += 3
img = Image.frombytes('RGB', (header.width, header.height), bytes(buffer))
img.save(output_path)
if __name__ == '__main__':
import sys
if len(sys.argv) != 3:
print(f"Usage:\n\t {sys.argv[0]} <input> <output>")
sys.exit(1)
input_file = sys.argv[1]
output_file = sys.argv[2]
convert(input_file, output_file)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment