from pathlib import Path
from io import BytesIO, BufferedReader
from lz4.block import decompress as decLz4Block
from PIL.Image import Image, frombuffer as imgfb
from numpy import frombuffer as npfb, stack as npst, uint8, uint16
class SctToPng:
Sign: bytes = b'SCT\x01'
SignLen: int = len(Sign)
@classmethod
def Cov(cls, stream: BytesIO|BufferedReader) -> Image:
if stream.read(cls.SignLen) != cls.Sign:
raise ValueError('Sign 错误')
texType = stream.read(1)[0]
width = int.from_bytes(stream.read(2), 'little')
height = int.from_bytes(stream.read(2), 'little')
decLen = int.from_bytes(stream.read(4), 'little')
comLen = int.from_bytes(stream.read(4), 'little')
data = decLz4Block(stream.read(comLen), uncompressed_size=decLen)
if texType == 2:
return imgfb('RGBA', (width, height), data[:width*height*4], 'raw')
elif texType == 4:
start = width * height * 2
rgb = npfb(data[:start], dtype=uint16).reshape((height, width))
a = npfb(data[start:start+(width*height)], dtype=uint8).reshape((height, width))
r = (((((rgb >> 11) & 0x1F) * 527) + 23) >> 6).astype(uint8)
g = (((((rgb >> 5) & 0x3F) * 259) + 33) >> 6).astype(uint8)
b = ((((rgb & 0x1F) * 527) + 23) >> 6).astype(uint8)
return imgfb('RGBA', (width, height), npst([r, g, b, a], axis=-1).tobytes(), 'raw')
else:
raise ValueError('贴图格式 错误')
@classmethod
def Read(cls, file: bytes|bytearray|str|Path|BytesIO|BufferedReader) -> Image:
if isinstance(file, str|Path):
with open(file, 'rb') as f:
return cls.Cov(f)
elif isinstance(file, (bytes, bytearray)):
return cls.Cov(BytesIO(file))
else:
return cls.Cov(file)
def batch(datPath: str = '', subfolder: bool = False):
path = Path(datPath) if datPath else Path.cwd()
need = [i for i in (path.rglob('*.sct') if subfolder else path.glob('*.sct')) if i.is_file()]
for i in need:
try:
img = SctToPng.Read(i)
except Exception as e:
print(f'转换错误 --- {i.as_posix()} --- {e}')
continue
img.save(f'{i.as_posix()[:-3]}png')
if __name__ == '__main__':
path = r'' # sct文件所在的路径
subfolder = False # 是否查找字文件夹内的文件
batch(path, subfolder)
3 个赞