mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-24 17:06:16 +03:00
Combined BMP RLE decoders
This commit is contained in:
parent
78430b9549
commit
6c8234bef3
|
@ -211,10 +211,8 @@ class BmpImageFile(ImageFile.ImageFile):
|
||||||
elif file_info["compression"] == self.RAW:
|
elif file_info["compression"] == self.RAW:
|
||||||
if file_info["bits"] == 32 and header == 22: # 32-bit .cur offset
|
if file_info["bits"] == 32 and header == 22: # 32-bit .cur offset
|
||||||
raw_mode, self.mode = "BGRA", "RGBA"
|
raw_mode, self.mode = "BGRA", "RGBA"
|
||||||
elif file_info["compression"] == self.RLE8:
|
elif file_info["compression"] in (self.RLE8, self.RLE4):
|
||||||
decoder_name = "bmp_rle8"
|
decoder_name = "bmp_rle"
|
||||||
elif file_info["compression"] == self.RLE4:
|
|
||||||
decoder_name = "bmp_rle4"
|
|
||||||
else:
|
else:
|
||||||
raise OSError(f"Unsupported BMP compression ({file_info['compression']})")
|
raise OSError(f"Unsupported BMP compression ({file_info['compression']})")
|
||||||
|
|
||||||
|
@ -252,16 +250,18 @@ class BmpImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
# ---------------------------- Finally set the tile data for the plugin
|
# ---------------------------- Finally set the tile data for the plugin
|
||||||
self.info["compression"] = file_info["compression"]
|
self.info["compression"] = file_info["compression"]
|
||||||
|
args = [raw_mode]
|
||||||
|
if decoder_name == "bmp_rle":
|
||||||
|
args.append(file_info["compression"] == self.RLE4)
|
||||||
|
else:
|
||||||
|
args.append(((file_info["width"] * file_info["bits"] + 31) >> 3) & (~3))
|
||||||
|
args.append(file_info["direction"])
|
||||||
self.tile = [
|
self.tile = [
|
||||||
(
|
(
|
||||||
decoder_name,
|
decoder_name,
|
||||||
(0, 0, file_info["width"], file_info["height"]),
|
(0, 0, file_info["width"], file_info["height"]),
|
||||||
offset or self.fp.tell(),
|
offset or self.fp.tell(),
|
||||||
(
|
tuple(args),
|
||||||
raw_mode,
|
|
||||||
((file_info["width"] * file_info["bits"] + 31) >> 3) & (~3),
|
|
||||||
file_info["direction"],
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -278,10 +278,11 @@ class BmpImageFile(ImageFile.ImageFile):
|
||||||
self._bitmap(offset=offset)
|
self._bitmap(offset=offset)
|
||||||
|
|
||||||
|
|
||||||
class BmpRle8Decoder(ImageFile.PyDecoder):
|
class BmpRleDecoder(ImageFile.PyDecoder):
|
||||||
_pulls_fd = True
|
_pulls_fd = True
|
||||||
|
|
||||||
def decode(self, buffer):
|
def decode(self, buffer):
|
||||||
|
rle4 = self.args[1]
|
||||||
data = bytearray()
|
data = bytearray()
|
||||||
x = 0
|
x = 0
|
||||||
while len(data) < self.state.xsize * self.state.ysize:
|
while len(data) < self.state.xsize * self.state.ysize:
|
||||||
|
@ -295,9 +296,19 @@ class BmpRle8Decoder(ImageFile.PyDecoder):
|
||||||
if x + num_pixels > self.state.xsize:
|
if x + num_pixels > self.state.xsize:
|
||||||
# Too much data for row
|
# Too much data for row
|
||||||
num_pixels = max(0, self.state.xsize - x)
|
num_pixels = max(0, self.state.xsize - x)
|
||||||
data += byte * num_pixels
|
if rle4:
|
||||||
|
first_pixel = o8(byte[0] >> 4)
|
||||||
|
second_pixel = o8(byte[0] & 0x0F)
|
||||||
|
for index in range(num_pixels):
|
||||||
|
if index % 2 == 0:
|
||||||
|
data += first_pixel
|
||||||
|
else:
|
||||||
|
data += second_pixel
|
||||||
|
else:
|
||||||
|
data += byte * num_pixels
|
||||||
x += num_pixels
|
x += num_pixels
|
||||||
else:
|
else:
|
||||||
|
# absolute mode
|
||||||
if byte[0] == 0:
|
if byte[0] == 0:
|
||||||
# end of line
|
# end of line
|
||||||
while len(data) % self.state.xsize != 0:
|
while len(data) % self.state.xsize != 0:
|
||||||
|
@ -315,73 +326,18 @@ class BmpRle8Decoder(ImageFile.PyDecoder):
|
||||||
data += b"\x00" * (right + up * self.state.xsize)
|
data += b"\x00" * (right + up * self.state.xsize)
|
||||||
x = len(data) % self.state.xsize
|
x = len(data) % self.state.xsize
|
||||||
else:
|
else:
|
||||||
# absolute mode
|
if rle4:
|
||||||
bytes_read = self.fd.read(byte[0])
|
# 2 pixels per byte
|
||||||
data += bytes_read
|
byte_count = byte[0] // 2
|
||||||
if len(bytes_read) < byte[0]:
|
bytes_read = self.fd.read(byte_count)
|
||||||
break
|
for byte_read in bytes_read:
|
||||||
x += byte[0]
|
data += o8(byte_read >> 4)
|
||||||
|
data += o8(byte_read & 0x0F)
|
||||||
# align to 16-bit word boundary
|
|
||||||
if self.fd.tell() % 2 != 0:
|
|
||||||
self.fd.seek(1, os.SEEK_CUR)
|
|
||||||
rawmode = "L" if self.mode == "L" else "P"
|
|
||||||
self.set_as_raw(bytes(data), (rawmode, 0, self.args[-1]))
|
|
||||||
return -1, 0
|
|
||||||
|
|
||||||
|
|
||||||
class BmpRle4Decoder(ImageFile.PyDecoder):
|
|
||||||
_pulls_fd = True
|
|
||||||
|
|
||||||
def decode(self, buffer):
|
|
||||||
data = bytearray()
|
|
||||||
x = 0
|
|
||||||
while len(data) < self.state.xsize * self.state.ysize:
|
|
||||||
pixels = self.fd.read(1)
|
|
||||||
byte = self.fd.read(1)
|
|
||||||
if not pixels or not byte:
|
|
||||||
break
|
|
||||||
num_pixels = pixels[0]
|
|
||||||
if num_pixels:
|
|
||||||
# encoded mode
|
|
||||||
if x + num_pixels > self.state.xsize:
|
|
||||||
# Too much data for row
|
|
||||||
num_pixels = max(0, self.state.xsize - x)
|
|
||||||
first_pixel = o8(byte[0] >> 4)
|
|
||||||
second_pixel = o8(byte[0] & 0x0F)
|
|
||||||
for index in range(num_pixels):
|
|
||||||
if index % 2 == 0:
|
|
||||||
data += first_pixel
|
|
||||||
else:
|
else:
|
||||||
data += second_pixel
|
byte_count = byte[0]
|
||||||
x += num_pixels
|
bytes_read = self.fd.read(byte_count)
|
||||||
else:
|
data += bytes_read
|
||||||
if byte[0] == 0:
|
if len(bytes_read) < byte_count:
|
||||||
# end of line
|
|
||||||
while len(data) % self.state.xsize != 0:
|
|
||||||
data += b"\x00"
|
|
||||||
x = 0
|
|
||||||
elif byte[0] == 1:
|
|
||||||
# end of bitmap
|
|
||||||
break
|
|
||||||
elif byte[0] == 2:
|
|
||||||
# delta
|
|
||||||
bytes_read = self.fd.read(2)
|
|
||||||
if len(bytes_read) < 2:
|
|
||||||
break
|
|
||||||
right, up = self.fd.read(2)
|
|
||||||
data += b"\x00" * (right + up * self.state.xsize)
|
|
||||||
x = len(data) % self.state.xsize
|
|
||||||
else:
|
|
||||||
# absolute mode (2 pixels per byte)
|
|
||||||
total_bytes_to_read = byte[0] // 2
|
|
||||||
bytes_read = self.fd.read(total_bytes_to_read)
|
|
||||||
for byte_read in bytes_read:
|
|
||||||
first_pixel = o8(byte_read >> 4)
|
|
||||||
data += first_pixel
|
|
||||||
second_pixel = o8(byte_read & 0x0F)
|
|
||||||
data += second_pixel
|
|
||||||
if len(bytes_read) < total_bytes_to_read:
|
|
||||||
break
|
break
|
||||||
x += byte[0]
|
x += byte[0]
|
||||||
|
|
||||||
|
@ -498,8 +454,7 @@ Image.register_extension(BmpImageFile.format, ".bmp")
|
||||||
|
|
||||||
Image.register_mime(BmpImageFile.format, "image/bmp")
|
Image.register_mime(BmpImageFile.format, "image/bmp")
|
||||||
|
|
||||||
Image.register_decoder("bmp_rle8", BmpRle8Decoder)
|
Image.register_decoder("bmp_rle", BmpRleDecoder)
|
||||||
Image.register_decoder("bmp_rle4", BmpRle4Decoder)
|
|
||||||
|
|
||||||
Image.register_open(DibImageFile.format, DibImageFile, _dib_accept)
|
Image.register_open(DibImageFile.format, DibImageFile, _dib_accept)
|
||||||
Image.register_save(DibImageFile.format, _dib_save)
|
Image.register_save(DibImageFile.format, _dib_save)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user