mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-07-15 10:42:19 +03:00
Do not reread start of header in decoder
This commit is contained in:
parent
b89cc09944
commit
6b75e06875
|
@ -259,24 +259,36 @@ class BlpImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
def _open(self) -> None:
|
def _open(self) -> None:
|
||||||
self.magic = self.fp.read(4)
|
self.magic = self.fp.read(4)
|
||||||
|
if not _accept(self.magic):
|
||||||
if self.magic == b"BLP1":
|
|
||||||
self.fp.seek(4, os.SEEK_CUR)
|
|
||||||
(self._blp_alpha_depth,) = struct.unpack("<I", self.fp.read(4))
|
|
||||||
elif self.magic == b"BLP2":
|
|
||||||
self.fp.seek(5, os.SEEK_CUR)
|
|
||||||
(self._blp_alpha_depth,) = struct.unpack("<b", self.fp.read(1))
|
|
||||||
self.fp.seek(2, os.SEEK_CUR)
|
|
||||||
else:
|
|
||||||
msg = f"Bad BLP magic {repr(self.magic)}"
|
msg = f"Bad BLP magic {repr(self.magic)}"
|
||||||
raise BLPFormatError(msg)
|
raise BLPFormatError(msg)
|
||||||
|
|
||||||
|
compression = struct.unpack("<i", self.fp.read(4))[0]
|
||||||
|
if self.magic == b"BLP1":
|
||||||
|
alpha = struct.unpack("<I", self.fp.read(4))[0] != 0
|
||||||
|
else:
|
||||||
|
encoding = struct.unpack("<b", self.fp.read(1))[0]
|
||||||
|
alpha = struct.unpack("<b", self.fp.read(1))[0] != 0
|
||||||
|
alpha_encoding = struct.unpack("<b", self.fp.read(1))[0]
|
||||||
|
self.fp.seek(1, os.SEEK_CUR) # mips
|
||||||
|
|
||||||
self._size = struct.unpack("<II", self.fp.read(8))
|
self._size = struct.unpack("<II", self.fp.read(8))
|
||||||
|
|
||||||
|
args: tuple[int, int, bool] | tuple[int, int, bool, int]
|
||||||
|
if self.magic == b"BLP1":
|
||||||
|
encoding = struct.unpack("<i", self.fp.read(4))[0]
|
||||||
|
self.fp.seek(4, os.SEEK_CUR) # subtype
|
||||||
|
|
||||||
|
args = (compression, encoding, alpha)
|
||||||
|
offset = 28
|
||||||
|
else:
|
||||||
|
args = (compression, encoding, alpha, alpha_encoding)
|
||||||
|
offset = 20
|
||||||
|
|
||||||
decoder = self.magic.decode()
|
decoder = self.magic.decode()
|
||||||
|
|
||||||
self._mode = "RGBA" if self._blp_alpha_depth else "RGB"
|
self._mode = "RGBA" if alpha else "RGB"
|
||||||
self.tile = [ImageFile._Tile(decoder, (0, 0) + self.size, 0, self.mode)]
|
self.tile = [ImageFile._Tile(decoder, (0, 0) + self.size, offset, args)]
|
||||||
|
|
||||||
|
|
||||||
class _BLPBaseDecoder(ImageFile.PyDecoder):
|
class _BLPBaseDecoder(ImageFile.PyDecoder):
|
||||||
|
@ -284,7 +296,7 @@ class _BLPBaseDecoder(ImageFile.PyDecoder):
|
||||||
|
|
||||||
def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
|
def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]:
|
||||||
try:
|
try:
|
||||||
self._read_blp_header()
|
self._read_header()
|
||||||
self._load()
|
self._load()
|
||||||
except struct.error as e:
|
except struct.error as e:
|
||||||
msg = "Truncated BLP file"
|
msg = "Truncated BLP file"
|
||||||
|
@ -295,28 +307,9 @@ class _BLPBaseDecoder(ImageFile.PyDecoder):
|
||||||
def _load(self) -> None:
|
def _load(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def _read_blp_header(self) -> None:
|
def _read_header(self) -> None:
|
||||||
assert self.fd is not None
|
self._offsets = struct.unpack("<16I", self._safe_read(16 * 4))
|
||||||
self.fd.seek(4)
|
self._lengths = struct.unpack("<16I", self._safe_read(16 * 4))
|
||||||
(self._blp_compression,) = struct.unpack("<i", self._safe_read(4))
|
|
||||||
|
|
||||||
if isinstance(self, BLP1Decoder):
|
|
||||||
(self._blp_alpha_depth,) = struct.unpack("<I", self._safe_read(4))
|
|
||||||
else:
|
|
||||||
(self._blp_encoding,) = struct.unpack("<b", self._safe_read(1))
|
|
||||||
(self._blp_alpha_depth,) = struct.unpack("<b", self._safe_read(1))
|
|
||||||
(self._blp_alpha_encoding,) = struct.unpack("<b", self._safe_read(1))
|
|
||||||
self.fd.seek(1, os.SEEK_CUR) # mips
|
|
||||||
|
|
||||||
self.size = struct.unpack("<II", self._safe_read(8))
|
|
||||||
|
|
||||||
if isinstance(self, BLP1Decoder):
|
|
||||||
# Only present for BLP1
|
|
||||||
(self._blp_encoding,) = struct.unpack("<i", self._safe_read(4))
|
|
||||||
self.fd.seek(4, os.SEEK_CUR) # subtype
|
|
||||||
|
|
||||||
self._blp_offsets = struct.unpack("<16I", self._safe_read(16 * 4))
|
|
||||||
self._blp_lengths = struct.unpack("<16I", self._safe_read(16 * 4))
|
|
||||||
|
|
||||||
def _safe_read(self, length: int) -> bytes:
|
def _safe_read(self, length: int) -> bytes:
|
||||||
assert self.fd is not None
|
assert self.fd is not None
|
||||||
|
@ -332,9 +325,11 @@ class _BLPBaseDecoder(ImageFile.PyDecoder):
|
||||||
ret.append((b, g, r, a))
|
ret.append((b, g, r, a))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def _read_bgra(self, palette: list[tuple[int, int, int, int]]) -> bytearray:
|
def _read_bgra(
|
||||||
|
self, palette: list[tuple[int, int, int, int]], alpha: bool
|
||||||
|
) -> bytearray:
|
||||||
data = bytearray()
|
data = bytearray()
|
||||||
_data = BytesIO(self._safe_read(self._blp_lengths[0]))
|
_data = BytesIO(self._safe_read(self._lengths[0]))
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
(offset,) = struct.unpack("<B", _data.read(1))
|
(offset,) = struct.unpack("<B", _data.read(1))
|
||||||
|
@ -342,7 +337,7 @@ class _BLPBaseDecoder(ImageFile.PyDecoder):
|
||||||
break
|
break
|
||||||
b, g, r, a = palette[offset]
|
b, g, r, a = palette[offset]
|
||||||
d: tuple[int, ...] = (r, g, b)
|
d: tuple[int, ...] = (r, g, b)
|
||||||
if self._blp_alpha_depth:
|
if alpha:
|
||||||
d += (a,)
|
d += (a,)
|
||||||
data.extend(d)
|
data.extend(d)
|
||||||
return data
|
return data
|
||||||
|
@ -350,19 +345,21 @@ class _BLPBaseDecoder(ImageFile.PyDecoder):
|
||||||
|
|
||||||
class BLP1Decoder(_BLPBaseDecoder):
|
class BLP1Decoder(_BLPBaseDecoder):
|
||||||
def _load(self) -> None:
|
def _load(self) -> None:
|
||||||
if self._blp_compression == Format.JPEG:
|
self._compression, self._encoding, alpha = self.args
|
||||||
|
|
||||||
|
if self._compression == Format.JPEG:
|
||||||
self._decode_jpeg_stream()
|
self._decode_jpeg_stream()
|
||||||
|
|
||||||
elif self._blp_compression == 1:
|
elif self._compression == 1:
|
||||||
if self._blp_encoding in (4, 5):
|
if self._encoding in (4, 5):
|
||||||
palette = self._read_palette()
|
palette = self._read_palette()
|
||||||
data = self._read_bgra(palette)
|
data = self._read_bgra(palette, alpha)
|
||||||
self.set_as_raw(data)
|
self.set_as_raw(data)
|
||||||
else:
|
else:
|
||||||
msg = f"Unsupported BLP encoding {repr(self._blp_encoding)}"
|
msg = f"Unsupported BLP encoding {repr(self._encoding)}"
|
||||||
raise BLPFormatError(msg)
|
raise BLPFormatError(msg)
|
||||||
else:
|
else:
|
||||||
msg = f"Unsupported BLP compression {repr(self._blp_encoding)}"
|
msg = f"Unsupported BLP compression {repr(self._encoding)}"
|
||||||
raise BLPFormatError(msg)
|
raise BLPFormatError(msg)
|
||||||
|
|
||||||
def _decode_jpeg_stream(self) -> None:
|
def _decode_jpeg_stream(self) -> None:
|
||||||
|
@ -371,8 +368,8 @@ class BLP1Decoder(_BLPBaseDecoder):
|
||||||
(jpeg_header_size,) = struct.unpack("<I", self._safe_read(4))
|
(jpeg_header_size,) = struct.unpack("<I", self._safe_read(4))
|
||||||
jpeg_header = self._safe_read(jpeg_header_size)
|
jpeg_header = self._safe_read(jpeg_header_size)
|
||||||
assert self.fd is not None
|
assert self.fd is not None
|
||||||
self._safe_read(self._blp_offsets[0] - self.fd.tell()) # What IS this?
|
self._safe_read(self._offsets[0] - self.fd.tell()) # What IS this?
|
||||||
data = self._safe_read(self._blp_lengths[0])
|
data = self._safe_read(self._lengths[0])
|
||||||
data = jpeg_header + data
|
data = jpeg_header + data
|
||||||
image = JpegImageFile(BytesIO(data))
|
image = JpegImageFile(BytesIO(data))
|
||||||
Image._decompression_bomb_check(image.size)
|
Image._decompression_bomb_check(image.size)
|
||||||
|
@ -389,47 +386,47 @@ class BLP1Decoder(_BLPBaseDecoder):
|
||||||
|
|
||||||
class BLP2Decoder(_BLPBaseDecoder):
|
class BLP2Decoder(_BLPBaseDecoder):
|
||||||
def _load(self) -> None:
|
def _load(self) -> None:
|
||||||
|
self._compression, self._encoding, alpha, self._alpha_encoding = self.args
|
||||||
|
|
||||||
palette = self._read_palette()
|
palette = self._read_palette()
|
||||||
|
|
||||||
assert self.fd is not None
|
assert self.fd is not None
|
||||||
self.fd.seek(self._blp_offsets[0])
|
self.fd.seek(self._offsets[0])
|
||||||
|
|
||||||
if self._blp_compression == 1:
|
if self._compression == 1:
|
||||||
# Uncompressed or DirectX compression
|
# Uncompressed or DirectX compression
|
||||||
|
|
||||||
if self._blp_encoding == Encoding.UNCOMPRESSED:
|
if self._encoding == Encoding.UNCOMPRESSED:
|
||||||
data = self._read_bgra(palette)
|
data = self._read_bgra(palette, alpha)
|
||||||
|
|
||||||
elif self._blp_encoding == Encoding.DXT:
|
elif self._encoding == Encoding.DXT:
|
||||||
data = bytearray()
|
data = bytearray()
|
||||||
if self._blp_alpha_encoding == AlphaEncoding.DXT1:
|
if self._alpha_encoding == AlphaEncoding.DXT1:
|
||||||
linesize = (self.size[0] + 3) // 4 * 8
|
linesize = (self.state.xsize + 3) // 4 * 8
|
||||||
for yb in range((self.size[1] + 3) // 4):
|
for yb in range((self.state.ysize + 3) // 4):
|
||||||
for d in decode_dxt1(
|
for d in decode_dxt1(self._safe_read(linesize), alpha):
|
||||||
self._safe_read(linesize), alpha=bool(self._blp_alpha_depth)
|
|
||||||
):
|
|
||||||
data += d
|
data += d
|
||||||
|
|
||||||
elif self._blp_alpha_encoding == AlphaEncoding.DXT3:
|
elif self._alpha_encoding == AlphaEncoding.DXT3:
|
||||||
linesize = (self.size[0] + 3) // 4 * 16
|
linesize = (self.state.xsize + 3) // 4 * 16
|
||||||
for yb in range((self.size[1] + 3) // 4):
|
for yb in range((self.state.ysize + 3) // 4):
|
||||||
for d in decode_dxt3(self._safe_read(linesize)):
|
for d in decode_dxt3(self._safe_read(linesize)):
|
||||||
data += d
|
data += d
|
||||||
|
|
||||||
elif self._blp_alpha_encoding == AlphaEncoding.DXT5:
|
elif self._alpha_encoding == AlphaEncoding.DXT5:
|
||||||
linesize = (self.size[0] + 3) // 4 * 16
|
linesize = (self.state.xsize + 3) // 4 * 16
|
||||||
for yb in range((self.size[1] + 3) // 4):
|
for yb in range((self.state.ysize + 3) // 4):
|
||||||
for d in decode_dxt5(self._safe_read(linesize)):
|
for d in decode_dxt5(self._safe_read(linesize)):
|
||||||
data += d
|
data += d
|
||||||
else:
|
else:
|
||||||
msg = f"Unsupported alpha encoding {repr(self._blp_alpha_encoding)}"
|
msg = f"Unsupported alpha encoding {repr(self._alpha_encoding)}"
|
||||||
raise BLPFormatError(msg)
|
raise BLPFormatError(msg)
|
||||||
else:
|
else:
|
||||||
msg = f"Unknown BLP encoding {repr(self._blp_encoding)}"
|
msg = f"Unknown BLP encoding {repr(self._encoding)}"
|
||||||
raise BLPFormatError(msg)
|
raise BLPFormatError(msg)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
msg = f"Unknown BLP compression {repr(self._blp_compression)}"
|
msg = f"Unknown BLP compression {repr(self._compression)}"
|
||||||
raise BLPFormatError(msg)
|
raise BLPFormatError(msg)
|
||||||
|
|
||||||
self.set_as_raw(data)
|
self.set_as_raw(data)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user