Increase use of bytearrays to improve loading speed

This commit is contained in:
Andrew Murray 2024-04-01 15:31:44 +11:00
parent badc92079d
commit b7d0908dc5

View File

@ -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,7 +48,7 @@ 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)
@ -57,34 +56,40 @@ class QoiDecoder(ImageFile.PyDecoder):
while len(data) < dest_length: 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(
op_index, bytearray((0, 0, 0, 0))
)
elif op == 1: # QOI_OP_DIFF elif op == 1: # QOI_OP_DIFF
value = ( value = bytearray(
(
(self._previous_pixel[0] + ((byte & 0b00110000) >> 4) - 2) (self._previous_pixel[0] + ((byte & 0b00110000) >> 4) - 2)
% 256, % 256,
(self._previous_pixel[1] + ((byte & 0b00001100) >> 2) - 2) (self._previous_pixel[1] + ((byte & 0b00001100) >> 2) - 2)
% 256, % 256,
(self._previous_pixel[2] + (byte & 0b00000011) - 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(
tuple(
(self._previous_pixel[i] + diff_green + diff) % 256 (self._previous_pixel[i] + diff_green + diff) % 256
for i, diff in enumerate((diff_red, 0, diff_blue)) 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
@ -92,7 +97,6 @@ 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: