mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-12 10:16:17 +03:00
Merge pull request #7925 from radarhere/qoi
This commit is contained in:
commit
1d733f498f
|
@ -341,7 +341,7 @@ class BLP1Decoder(_BLPBaseDecoder):
|
||||||
if self._blp_encoding in (4, 5):
|
if self._blp_encoding in (4, 5):
|
||||||
palette = self._read_palette()
|
palette = self._read_palette()
|
||||||
data = self._read_bgra(palette)
|
data = self._read_bgra(palette)
|
||||||
self.set_as_raw(bytes(data))
|
self.set_as_raw(data)
|
||||||
else:
|
else:
|
||||||
msg = f"Unsupported BLP encoding {repr(self._blp_encoding)}"
|
msg = f"Unsupported BLP encoding {repr(self._blp_encoding)}"
|
||||||
raise BLPFormatError(msg)
|
raise BLPFormatError(msg)
|
||||||
|
@ -412,7 +412,7 @@ class BLP2Decoder(_BLPBaseDecoder):
|
||||||
msg = f"Unknown BLP compression {repr(self._blp_compression)}"
|
msg = f"Unknown BLP compression {repr(self._blp_compression)}"
|
||||||
raise BLPFormatError(msg)
|
raise BLPFormatError(msg)
|
||||||
|
|
||||||
self.set_as_raw(bytes(data))
|
self.set_as_raw(data)
|
||||||
|
|
||||||
|
|
||||||
class BLPEncoder(ImageFile.PyEncoder):
|
class BLPEncoder(ImageFile.PyEncoder):
|
||||||
|
|
|
@ -291,7 +291,8 @@ class BmpRleDecoder(ImageFile.PyDecoder):
|
||||||
rle4 = self.args[1]
|
rle4 = self.args[1]
|
||||||
data = bytearray()
|
data = bytearray()
|
||||||
x = 0
|
x = 0
|
||||||
while len(data) < self.state.xsize * self.state.ysize:
|
dest_length = self.state.xsize * self.state.ysize
|
||||||
|
while len(data) < dest_length:
|
||||||
pixels = self.fd.read(1)
|
pixels = self.fd.read(1)
|
||||||
byte = self.fd.read(1)
|
byte = self.fd.read(1)
|
||||||
if not pixels or not byte:
|
if not pixels or not byte:
|
||||||
|
|
|
@ -497,7 +497,8 @@ class DdsRgbDecoder(ImageFile.PyDecoder):
|
||||||
|
|
||||||
data = bytearray()
|
data = bytearray()
|
||||||
bytecount = bitcount // 8
|
bytecount = bitcount // 8
|
||||||
while len(data) < self.state.xsize * self.state.ysize * len(masks):
|
dest_length = self.state.xsize * self.state.ysize * len(masks)
|
||||||
|
while len(data) < dest_length:
|
||||||
value = int.from_bytes(self.fd.read(bytecount), "little")
|
value = int.from_bytes(self.fd.read(bytecount), "little")
|
||||||
for i, mask in enumerate(masks):
|
for i, mask in enumerate(masks):
|
||||||
masked_value = value & mask
|
masked_value = value & mask
|
||||||
|
@ -505,7 +506,7 @@ class DdsRgbDecoder(ImageFile.PyDecoder):
|
||||||
data += o8(
|
data += o8(
|
||||||
int(((masked_value >> mask_offsets[i]) / mask_totals[i]) * 255)
|
int(((masked_value >> mask_offsets[i]) / mask_totals[i]) * 255)
|
||||||
)
|
)
|
||||||
self.set_as_raw(bytes(data))
|
self.set_as_raw(data)
|
||||||
return -1, 0
|
return -1, 0
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -307,7 +307,8 @@ class PpmDecoder(ImageFile.PyDecoder):
|
||||||
out_byte_count = 4 if self.mode == "I" else 1
|
out_byte_count = 4 if self.mode == "I" else 1
|
||||||
out_max = 65535 if self.mode == "I" else 255
|
out_max = 65535 if self.mode == "I" else 255
|
||||||
bands = Image.getmodebands(self.mode)
|
bands = Image.getmodebands(self.mode)
|
||||||
while len(data) < self.state.xsize * self.state.ysize * bands * out_byte_count:
|
dest_length = self.state.xsize * self.state.ysize * bands * out_byte_count
|
||||||
|
while len(data) < dest_length:
|
||||||
pixels = self.fd.read(in_byte_count * bands)
|
pixels = self.fd.read(in_byte_count * bands)
|
||||||
if len(pixels) < in_byte_count * bands:
|
if len(pixels) < in_byte_count * bands:
|
||||||
# eof
|
# eof
|
||||||
|
|
|
@ -11,7 +11,6 @@ import os
|
||||||
|
|
||||||
from . import Image, ImageFile
|
from . import Image, ImageFile
|
||||||
from ._binary import i32be as i32
|
from ._binary import i32be as i32
|
||||||
from ._binary import o8
|
|
||||||
|
|
||||||
|
|
||||||
def _accept(prefix):
|
def _accept(prefix):
|
||||||
|
@ -49,41 +48,48 @@ class QoiDecoder(ImageFile.PyDecoder):
|
||||||
def decode(self, buffer):
|
def decode(self, buffer):
|
||||||
self._previously_seen_pixels = {}
|
self._previously_seen_pixels = {}
|
||||||
self._previous_pixel = None
|
self._previous_pixel = None
|
||||||
self._add_to_previous_pixels(b"".join(o8(i) for i in (0, 0, 0, 255)))
|
self._add_to_previous_pixels(bytearray((0, 0, 0, 255)))
|
||||||
|
|
||||||
data = bytearray()
|
data = bytearray()
|
||||||
bands = Image.getmodebands(self.mode)
|
bands = Image.getmodebands(self.mode)
|
||||||
while len(data) < self.state.xsize * self.state.ysize * bands:
|
dest_length = self.state.xsize * self.state.ysize * bands
|
||||||
|
while len(data) < dest_length:
|
||||||
byte = self.fd.read(1)[0]
|
byte = self.fd.read(1)[0]
|
||||||
if byte == 0b11111110: # QOI_OP_RGB
|
if byte == 0b11111110: # QOI_OP_RGB
|
||||||
value = self.fd.read(3) + self._previous_pixel[3:]
|
value = bytearray(self.fd.read(3)) + self._previous_pixel[3:]
|
||||||
elif byte == 0b11111111: # QOI_OP_RGBA
|
elif byte == 0b11111111: # QOI_OP_RGBA
|
||||||
value = self.fd.read(4)
|
value = self.fd.read(4)
|
||||||
else:
|
else:
|
||||||
op = byte >> 6
|
op = byte >> 6
|
||||||
if op == 0: # QOI_OP_INDEX
|
if op == 0: # QOI_OP_INDEX
|
||||||
op_index = byte & 0b00111111
|
op_index = byte & 0b00111111
|
||||||
value = self._previously_seen_pixels.get(op_index, (0, 0, 0, 0))
|
value = self._previously_seen_pixels.get(
|
||||||
elif op == 1: # QOI_OP_DIFF
|
op_index, bytearray((0, 0, 0, 0))
|
||||||
value = (
|
)
|
||||||
(self._previous_pixel[0] + ((byte & 0b00110000) >> 4) - 2)
|
elif op == 1: # QOI_OP_DIFF
|
||||||
% 256,
|
value = bytearray(
|
||||||
(self._previous_pixel[1] + ((byte & 0b00001100) >> 2) - 2)
|
(
|
||||||
% 256,
|
(self._previous_pixel[0] + ((byte & 0b00110000) >> 4) - 2)
|
||||||
(self._previous_pixel[2] + (byte & 0b00000011) - 2) % 256,
|
% 256,
|
||||||
|
(self._previous_pixel[1] + ((byte & 0b00001100) >> 2) - 2)
|
||||||
|
% 256,
|
||||||
|
(self._previous_pixel[2] + (byte & 0b00000011) - 2) % 256,
|
||||||
|
self._previous_pixel[3],
|
||||||
|
)
|
||||||
)
|
)
|
||||||
value += (self._previous_pixel[3],)
|
|
||||||
elif op == 2: # QOI_OP_LUMA
|
elif op == 2: # QOI_OP_LUMA
|
||||||
second_byte = self.fd.read(1)[0]
|
second_byte = self.fd.read(1)[0]
|
||||||
diff_green = (byte & 0b00111111) - 32
|
diff_green = (byte & 0b00111111) - 32
|
||||||
diff_red = ((second_byte & 0b11110000) >> 4) - 8
|
diff_red = ((second_byte & 0b11110000) >> 4) - 8
|
||||||
diff_blue = (second_byte & 0b00001111) - 8
|
diff_blue = (second_byte & 0b00001111) - 8
|
||||||
|
|
||||||
value = tuple(
|
value = bytearray(
|
||||||
(self._previous_pixel[i] + diff_green + diff) % 256
|
tuple(
|
||||||
for i, diff in enumerate((diff_red, 0, diff_blue))
|
(self._previous_pixel[i] + diff_green + diff) % 256
|
||||||
|
for i, diff in enumerate((diff_red, 0, diff_blue))
|
||||||
|
)
|
||||||
)
|
)
|
||||||
value += (self._previous_pixel[3],)
|
value += self._previous_pixel[3:]
|
||||||
elif op == 3: # QOI_OP_RUN
|
elif op == 3: # QOI_OP_RUN
|
||||||
run_length = (byte & 0b00111111) + 1
|
run_length = (byte & 0b00111111) + 1
|
||||||
value = self._previous_pixel
|
value = self._previous_pixel
|
||||||
|
@ -91,13 +97,12 @@ class QoiDecoder(ImageFile.PyDecoder):
|
||||||
value = value[:3]
|
value = value[:3]
|
||||||
data += value * run_length
|
data += value * run_length
|
||||||
continue
|
continue
|
||||||
value = b"".join(o8(i) for i in value)
|
|
||||||
self._add_to_previous_pixels(value)
|
self._add_to_previous_pixels(value)
|
||||||
|
|
||||||
if bands == 3:
|
if bands == 3:
|
||||||
value = value[:3]
|
value = value[:3]
|
||||||
data += value
|
data += value
|
||||||
self.set_as_raw(bytes(data))
|
self.set_as_raw(data)
|
||||||
return -1, 0
|
return -1, 0
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user