Convert BlpImagePlugin to use Pydecoder framework

This commit is contained in:
wiredfool 2018-03-04 20:23:13 +00:00 committed by Jerome Leclanche
parent 31409bc83d
commit 3a77758d9a

View File

@ -246,26 +246,21 @@ class BlpImageFile(ImageFile.ImageFile):
format_description = "Blizzard Mipmap Format"
def _open(self):
self.tile = []
self.magic = self.fp.read(4)
self._read_blp_header()
if self.magic == b"BLP1":
self._open_blp1()
decoder = "BLP1"
self.mode = "RGB"
elif self.magic == b"BLP2":
self._open_blp2()
decoder = "BLP2"
self.mode = "RGBA" if self._blp_alpha_depth else "RGB"
else:
raise BLPFormatError("Bad BLP magic %r" % (self.magic))
def _read_palette(self):
ret = []
for i in range(256):
try:
b, g, r, a = struct.unpack("<4B", self.fp.read(4))
except struct.error:
break
ret.append((b, g, r, a))
return ret
self.tile = [
(decoder, (0, 0) + self.size, 0, (self.mode, 0, 1))
]
def _read_blp_header(self):
self._blp_compression, = struct.unpack("<i", self.fp.read(4))
@ -285,9 +280,52 @@ class BlpImageFile(ImageFile.ImageFile):
self._blp_offsets = struct.unpack("<16I", self.fp.read(16 * 4))
self._blp_lengths = struct.unpack("<16I", self.fp.read(16 * 4))
def _open_blp1(self):
self.mode = "RGB"
class _BLPBaseDecoder(ImageFile.PyDecoder):
_pulls_fd = True
def decode(self, buffer):
try:
self.fd.seek(0)
self.magic = self.fd.read(4)
self._read_blp_header()
self._load()
except struct.error:
raise IOError("Truncated Blp file")
return 0, 0
def _read_palette(self):
ret = []
for i in range(256):
try:
b, g, r, a = struct.unpack("<4B", self.fd.read(4))
except struct.error:
break
ret.append((b, g, r, a))
return ret
def _read_blp_header(self):
self._blp_compression, = struct.unpack("<i", self.fd.read(4))
self._blp_encoding, = struct.unpack("<b", self.fd.read(1))
self._blp_alpha_depth, = struct.unpack("<b", self.fd.read(1))
self._blp_alpha_encoding, = struct.unpack("<b", self.fd.read(1))
self._blp_mips, = struct.unpack("<b", self.fd.read(1))
self.size = struct.unpack("<II", self.fd.read(8))
if self.magic == b"BLP1":
# Only present for BLP1
self._blp_encoding, = struct.unpack("<i", self.fd.read(4))
self._blp_subtype, = struct.unpack("<i", self.fd.read(4))
self._blp_offsets = struct.unpack("<16I", self.fd.read(16 * 4))
self._blp_lengths = struct.unpack("<16I", self.fd.read(16 * 4))
class BLP1Decoder(_BLPBaseDecoder):
def _load(self):
if self._blp_compression == BLP_FORMAT_JPEG:
self._decode_jpeg_stream()
@ -295,7 +333,7 @@ class BlpImageFile(ImageFile.ImageFile):
if self._blp_encoding in (4, 5):
data = bytearray()
palette = self._read_palette()
_data = BytesIO(self.fp.read(self._blp_lengths[0]))
_data = BytesIO(self.fd.read(self._blp_lengths[0]))
while True:
try:
offset, = struct.unpack("<B", _data.read(1))
@ -304,8 +342,7 @@ class BlpImageFile(ImageFile.ImageFile):
b, g, r, a = palette[offset]
data.extend([r, g, b])
self.im = Image.core.new(self.mode, self.size)
self.frombytes(bytes(data))
self.set_as_raw(bytes(data))
else:
raise BLPFormatError(
"Unsupported BLP encoding %r" % (self._blp_encoding)
@ -318,30 +355,31 @@ class BlpImageFile(ImageFile.ImageFile):
def _decode_jpeg_stream(self):
from PIL.JpegImagePlugin import JpegImageFile
jpeg_header_size, = struct.unpack("<I", self.fp.read(4))
jpeg_header = self.fp.read(jpeg_header_size)
self.fp.read(self._blp_offsets[0] - self.fp.tell()) # What IS this?
data = self.fp.read(self._blp_lengths[0])
jpeg_header_size, = struct.unpack("<I", self.fd.read(4))
jpeg_header = self.fd.read(jpeg_header_size)
self.fd.read(self._blp_offsets[0] - self.fd.tell()) # What IS this?
data = self.fd.read(self._blp_lengths[0])
data = jpeg_header + data
data = BytesIO(data)
image = JpegImageFile(data)
image.show()
self.tile = image.tile # :/
self.fp = image.fp
self.fd = image.fp
self.mode = image.mode
def _open_blp2(self):
class BLP2Decoder(_BLPBaseDecoder):
def _load(self):
palette = self._read_palette()
self.mode = "RGBA" if self._blp_alpha_depth else "RGB"
data = bytearray()
self.fp.seek(self._blp_offsets[0])
self.fd.seek(self._blp_offsets[0])
if self._blp_compression == 1:
# Uncompressed or DirectX compression
if self._blp_encoding == BLP_ENCODING_UNCOMPRESSED:
_data = BytesIO(self.fp.read(self._blp_lengths[0]))
_data = BytesIO(self.fd.read(self._blp_lengths[0]))
while True:
try:
offset, = struct.unpack("<B", _data.read(1))
@ -355,7 +393,7 @@ class BlpImageFile(ImageFile.ImageFile):
linesize = (self.size[0] + 3) // 4 * 8
for yb in range((self.size[1] + 3) // 4):
for d in decode_dxt1(
self.fp.read(linesize),
self.fd.read(linesize),
alpha=bool(self._blp_alpha_depth)
):
data += d
@ -363,13 +401,13 @@ class BlpImageFile(ImageFile.ImageFile):
elif self._blp_alpha_encoding == BLP_ALPHA_ENCODING_DXT3:
linesize = (self.size[0] + 3) // 4 * 16
for yb in range((self.size[1] + 3) // 4):
for d in decode_dxt3(self.fp.read(linesize)):
for d in decode_dxt3(self.fd.read(linesize)):
data += d
elif self._blp_alpha_encoding == BLP_ALPHA_ENCODING_DXT5:
linesize = (self.size[0] + 3) // 4 * 16
for yb in range((self.size[1] + 3) // 4):
for d in decode_dxt5(self.fp.read(linesize)):
for d in decode_dxt5(self.fd.read(linesize)):
data += d
else:
raise BLPFormatError("Unsupported alpha encoding %r" % (
@ -385,11 +423,13 @@ class BlpImageFile(ImageFile.ImageFile):
"Unknown BLP compression %r" % (self._blp_compression)
)
self.im = Image.core.new(self.mode, self.size)
self.frombytes(bytes(data))
self.set_as_raw(bytes(data))
Image.register_open(
BlpImageFile.format, BlpImageFile, lambda p: p[:4] in (b"BLP1", b"BLP2")
)
Image.register_extension(BlpImageFile.format, ".blp")
Image.register_decoder("BLP1", BLP1Decoder)
Image.register_decoder("BLP2", BLP2Decoder)