Skip to content

Commit

Permalink
Merge pull request #7925 from radarhere/qoi
Browse files Browse the repository at this point in the history
  • Loading branch information
hugovk committed Apr 1, 2024
2 parents d31148b + b7d0908 commit 1d733f4
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 24 deletions.
4 changes: 2 additions & 2 deletions src/PIL/BlpImagePlugin.py
Expand Up @@ -341,7 +341,7 @@ def _load(self):
if self._blp_encoding in (4, 5):
palette = self._read_palette()
data = self._read_bgra(palette)
self.set_as_raw(bytes(data))
self.set_as_raw(data)
else:
msg = f"Unsupported BLP encoding {repr(self._blp_encoding)}"
raise BLPFormatError(msg)
Expand Down Expand Up @@ -412,7 +412,7 @@ def _load(self):
msg = f"Unknown BLP compression {repr(self._blp_compression)}"
raise BLPFormatError(msg)

self.set_as_raw(bytes(data))
self.set_as_raw(data)


class BLPEncoder(ImageFile.PyEncoder):
Expand Down
3 changes: 2 additions & 1 deletion src/PIL/BmpImagePlugin.py
Expand Up @@ -291,7 +291,8 @@ def decode(self, buffer):
rle4 = self.args[1]
data = bytearray()
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)
byte = self.fd.read(1)
if not pixels or not byte:
Expand Down
5 changes: 3 additions & 2 deletions src/PIL/DdsImagePlugin.py
Expand Up @@ -497,15 +497,16 @@ def decode(self, buffer):

data = bytearray()
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")
for i, mask in enumerate(masks):
masked_value = value & mask
# Remove the zero padding, and scale it to 8 bits
data += o8(
int(((masked_value >> mask_offsets[i]) / mask_totals[i]) * 255)
)
self.set_as_raw(bytes(data))
self.set_as_raw(data)
return -1, 0


Expand Down
3 changes: 2 additions & 1 deletion src/PIL/PpmImagePlugin.py
Expand Up @@ -307,7 +307,8 @@ def decode(self, buffer: bytes) -> tuple[int, int]:
out_byte_count = 4 if self.mode == "I" else 1
out_max = 65535 if self.mode == "I" else 255
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)
if len(pixels) < in_byte_count * bands:
# eof
Expand Down
41 changes: 23 additions & 18 deletions src/PIL/QoiImagePlugin.py
Expand Up @@ -11,7 +11,6 @@

from . import Image, ImageFile
from ._binary import i32be as i32
from ._binary import o8


def _accept(prefix):
Expand Down Expand Up @@ -49,55 +48,61 @@ def _add_to_previous_pixels(self, value):
def decode(self, buffer):
self._previously_seen_pixels = {}
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()
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]
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
value = self.fd.read(4)
else:
op = byte >> 6
if op == 0: # QOI_OP_INDEX
op_index = byte & 0b00111111
value = self._previously_seen_pixels.get(op_index, (0, 0, 0, 0))
value = self._previously_seen_pixels.get(
op_index, bytearray((0, 0, 0, 0))
)
elif op == 1: # QOI_OP_DIFF
value = (
(self._previous_pixel[0] + ((byte & 0b00110000) >> 4) - 2)
% 256,
(self._previous_pixel[1] + ((byte & 0b00001100) >> 2) - 2)
% 256,
(self._previous_pixel[2] + (byte & 0b00000011) - 2) % 256,
value = bytearray(
(
(self._previous_pixel[0] + ((byte & 0b00110000) >> 4) - 2)
% 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
second_byte = self.fd.read(1)[0]
diff_green = (byte & 0b00111111) - 32
diff_red = ((second_byte & 0b11110000) >> 4) - 8
diff_blue = (second_byte & 0b00001111) - 8

value = tuple(
(self._previous_pixel[i] + diff_green + diff) % 256
for i, diff in enumerate((diff_red, 0, diff_blue))
value = bytearray(
tuple(
(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
run_length = (byte & 0b00111111) + 1
value = self._previous_pixel
if bands == 3:
value = value[:3]
data += value * run_length
continue
value = b"".join(o8(i) for i in value)
self._add_to_previous_pixels(value)

if bands == 3:
value = value[:3]
data += value
self.set_as_raw(bytes(data))
self.set_as_raw(data)
return -1, 0


Expand Down

0 comments on commit 1d733f4

Please sign in to comment.