add dds header parsing and info tool

main
Andrew Cassidy 3 years ago
parent e410f0c15c
commit cdea4674f8

@ -1,33 +1,139 @@
import subprocess
import os
import typing
import struct
import re
import io
import enum
if os.name == 'nt':
convertcmd = "convert.exe"
compresscmd = "nvcompress.exe"
decompresscmd = "nvdecompress.exe"
infocmd = "nvddsinfo.exe"
else:
convertcmd = "convert"
compresscmd = "nvcompress"
decompresscmd = "nvdecompress"
infocmd = "nvddsinfo"
def alpha(file):
result = subprocess.run([convertcmd, file, "-resize", "1x1", "-format", "%[fx:int(255*a+.5)]", "info:-"], capture_output=True)
result = subprocess.run([convertcmd, file, "-resize", "1x1",
"-format", "%[fx:int(255*a+.5)]", "info:-"], capture_output=True)
result.check_returncode()
return int(result.stdout)
def flip(file, output):
result = subprocess.run([convertcmd, '-flip', file, output], capture_output=True)
result = subprocess.run(
[convertcmd, '-flip', file, output], capture_output=True)
result.check_returncode()
def nvcompress(format, file, output, mips = True):
def nvcompress(format, file, output, mips=True):
args = [format]
if not mips:
args.append('-nomips')
result = subprocess.run([compresscmd] + args + [file, output], capture_output=True)
result = subprocess.run([compresscmd] + args +
[file, output], capture_output=True)
result.check_returncode()
def nvdecompress(file, output):
result = subprocess.run([decompresscmd, file, output], capture_output=True)
result.check_returncode()
def nvinfo(file):
result = subprocess.run([infocmd, file], capture_output=True)
result.check_returncode()
info = {
"format": re.search(r"FourCC: '(.{4})'", str(result.stdout)).group(1)
}
return info
return info
class DDSFlags(enum.IntFlag):
CAPS = 0x1
HEIGHT = 0x2
WIDTH = 0x4
PITCH = 0x8
PIXEL_FORMAT = 0x1000
MIPMAPCOUNT = 0x20000
LINEAR_SIZE = 0x80000
DEPTH = 0x800000
class DDSPixelFlags(enum.IntFlag):
ALPHAPIXELS = 0x1
ALPHA = 0x2
FOURCC = 0x4
RGB = 0x40
YUV = 0x200
LUMINANCE = 0x20000
class DDSHeader:
def __init__(self, f):
self.read(f)
def read(self, f):
if f.read(4).decode() != "DDS ":
raise ValueError(
"File is not a valid DDS f: Incorrect magic bytes")
dwords = struct.unpack('20I4s10I', f.read(124))
# check constants
if dwords[0] != 124:
raise ValueError(
"File is not a valid DDS file: Incorrect header size")
if dwords[18] != 32:
raise ValueError(
"File is not a valid DDS file: Incorrect pixelformat size")
# read basic info
self.flags = DDSFlags(dwords[1])
self.height, self.width = dwords[2:4]
if DDSFlags.PITCH in self.flags:
self.pitch = dwords[4]
else:
self.linear_size = dwords[4]
if DDSFlags.DEPTH in self.flags:
self.depth = dwords[5]
if DDSFlags.MIPMAPCOUNT in self.flags:
self.mipmapcount = dwords[6]
# read pixelformat
self.pixel_flags = DDSPixelFlags(dwords[19])
if DDSPixelFlags.ALPHAPIXELS in self.pixel_flags:
# texture has alpha data
self.a_bitmask = dwords[25]
if DDSPixelFlags.FOURCC in self.pixel_flags:
# texture is compressed, four_cc contains the format
self.format = dwords[20].decode()
else:
self.format = 'uncompressed'
if (DDSPixelFlags.RGB | DDSPixelFlags.YUV) & self.pixel_flags:
# uncompressed RGB texture
self.rgb_bit_count, self.r_bitmask, self.g_bitmask, self.b_bitmask = dwords[21:25]
elif DDSPixelFlags.ALPHA in self.pixel_flags:
# uncompressed alpha-only texture
self.rgb_bit_count = dwords[21]
self.a_bitmask = dwords[25]
elif DDSPixelFlags.LUMINANCE in self.pixel_flags:
# uncompressed luminance-only texture
self.rgb_bit_count = dwords[21]
self.r_bitmask = dwords[22]
# read caps
self.dw_caps, self.dw_caps2, self.dw_caps3, self.dw_caps4 = dwords[26:30] # read dwCaps flags
if self.format == 'DX10':
dwords = f.read(20)
#TODO: actually read the DX10 data
Loading…
Cancel
Save