I'm trying to programmatically convert the largest mipmap of a 32x32 DXT5-compressed VTF file to a PNG. Here is what the image should look like after conversion:
And here is what mine looks like:
Obviously, something is wrong. Here is my code:
import texture2ddecoder, numpy
from PIL import Image
# 16x16 because VTF is 32x32
# and since we divide by 2 to get mipmap sizes
# largest mipmap would be 32/2 by 32/2 or 16 by 16
img_width = 16
img_height = 16
# ring_dot.vtf contains just the last 256 bytes of the original VTF
# My logic behind keeping just the last 256 bytes:
# Mipmap height = 16 px
# Mipmap width = 16 px
# Mipmap area (px) = 16*16 = 256 px
# 1 px = 8 bits (this is because of how DXT5 compression works)
# Mipmap area (bits) = 256 * 8 = 2048 bits
# 8 bits = 1 byte
# Mipmap area (bytes) = 2048 / 8 = 256 bytes
# 1 row (in hex editor) = 16 bytes
# Mipmap area (rows) = 256 / 16 = 16 rows
encoded_binary = open('ring_dot.vtf','rb').read()
#decompressing dxt5 to get actual pixel colors, returns BGRA bytes
decoded_binary = texture2ddecoder.decode_bc3(encoded_binary, img_width, img_height)
#creating RGBA PNG, converting from BGRA
dec_img = Image.frombytes("RGBA", (img_width, img_height), decoded_binary, 'raw', ("BGRA"))
dec_img.show()
dec_img.save('ringDot.png')
I tried changing img_width
and img_height
to higher values like 32x32, 48x48, and 64x64 but to no avail. I suspect I'm determining the size of the largest mipmap (and therefore which bytes represent it in the binary) incorrectly, but the calculations make sense to me and if the largest mipmap really does come last, I don't see why it wouldn't be the last 256 bytes in this case. What am I doing wrong here?