Last active
August 21, 2024 10:14
-
-
Save nm004/10426f5c0b8eb2cb887b3aeb5ae99f1a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import argparse | |
def vlc_lzw_compress(data, nbit=8): | |
assert 1 < nbit < 9, 'nbit must satisfies, 1 < nbit < 9' | |
# LZW encoding | |
CLR = 1<<nbit | |
END = CLR+1 | |
d = {} | |
n = nbit+1 | |
x = END+1 | |
y = 1 << n | |
O = [(CLR, n)] | |
k = (data[0],) | |
for i in data[1:]: | |
k = (k[0],i) | |
if k in d: | |
k = (d[k],) | |
else: | |
d[k] = x | |
O.append((k[0], n)) | |
if x == y: | |
n += 1 | |
y <<= 1 | |
x += 1 | |
if x == 0x1000: | |
O.append((CLR, n)) | |
d = {} | |
n = nbit+1 | |
x = END+1 | |
y = 1 << n | |
k = (k[1],) | |
O.append((k[0], n)) | |
O.append((END, n)) | |
# 8-bit string encoding | |
b = bytearray() | |
x = 0 | |
y = 0 | |
for i, j in O: | |
x |= (i << y) | |
y += j | |
while y >= 8: | |
b.append(x & 0xff) | |
x >>= 8 | |
y -= 8 | |
if y: | |
b.append(x) | |
return bytes(b) | |
def main(): | |
usage = '''wad3texture_to_gif < wad > gif''' | |
parser = argparse.ArgumentParser(usage=usage) | |
args = parser.parse_args() | |
# read wad file | |
wad = sys.stdin.buffer.read() | |
# parsing wad and get texture | |
num_dirs = int.from_bytes(wad[0x4:0xc], 'little') | |
dir_offset = int.from_bytes(wad[0x8:0xc], 'little') | |
o = dir_offset | |
entry_offset = int.from_bytes(wad[o+0:o+4], 'little') | |
disk_size = int.from_bytes(wad[o+4:o+8], 'little') | |
o0 = entry_offset | |
o1 = o0 + disk_size | |
entry = wad[o0:o1] | |
width = int.from_bytes(entry[0x10:0x14], 'little') | |
height = int.from_bytes(entry[0x14:0x18], 'little') | |
mip0_offset = int.from_bytes(entry[0x18:0x1c], 'little') | |
o0 = mip0_offset | |
o1 = o0 + width * height | |
mip0 = entry[o0:o1] | |
mip4_offset = int.from_bytes(entry[0x24:0x28], 'little') | |
o = mip4_offset + width * height // 64 | |
colors_used = int.from_bytes(entry[o:o+2], 'little') | |
o0 = mip4_offset + width * height // 64 + 0x2 | |
o1 = o0 + colors_used * 3 | |
pallet = entry[o0:o1] | |
mip0_compressed = vlc_lzw_compress(mip0) | |
#width = height = 3 | |
#mip0_compressed = vlc_lzw_compress(b'\x00\x00\x00\xff\x00\xff\xff\x00\xff') | |
b = ( | |
# Header | |
# Magic | |
b'GIF' | |
# Version | |
+ b'89a' | |
# Logical Screen Width | |
+ width.to_bytes(2, 'little') | |
# Logical Screen Height | |
+ height.to_bytes(2, 'little') | |
# Global Color Table Flag = true | |
# Color Resolution = 7 | |
# Sort Flag = false | |
# Size of Global Color Table = 0 | |
+ b'\xf7' | |
# Background Color Index | |
+ b'\xff' | |
# Pixel Aspect Ratio | |
+ b'\x00' | |
# Global Color Table | |
+ pallet | |
# Graphic Control Extension | |
# Extension Introducer | |
+ b'\x21' | |
# Graphic Control Label | |
+ b'\xf9' | |
# Block Size | |
+ b'\x04' | |
# Reserved = 0 | |
# Disposal Method = 0 | |
# User Input Flag = false | |
# Transparent Color Flag = true | |
+ b'\x01' | |
# Delay Time | |
+ b'\x00\x00' | |
# Transparent Color Index | |
+ b'\xff' | |
# Block Terminator | |
+ b'\x00' | |
# Image Descriptor | |
# Image Separator | |
+ b'\x2c' | |
# Image Left Position | |
+ b'\x00\x00' | |
# Image Top Position | |
+ b'\x00\x00' | |
# Image Width | |
+ width.to_bytes(2, 'little') | |
# Image Height | |
+ height.to_bytes(2, 'little') | |
# Local Color Table Flag = true | |
# Interlace Flag = false | |
# Sort Flag = false | |
# Reserved = 0 | |
# Size of Local Color Table = 0 | |
+ b'\x00' | |
# Local Color Table | |
+ b'' | |
# LZW Minimum Code Size | |
+ b'\x08' | |
+ b''.join( | |
# Block Size | |
len(mip0_compressed[i:i+0xff]).to_bytes(1) | |
# Image Data | |
+ mip0_compressed[i:i+0xff] | |
for i in range(0, len(mip0_compressed), 0xff) | |
) | |
# Block Terminator | |
+ b'\x00' | |
# Trailer | |
+ b'\x3b') | |
# write gif file | |
sys.stdout.buffer.write(b) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment