+ if (self._absolute_transform.dx < 0) != flip_x:
+ x_shift = area.x2 - overlap.x2
+ else:
+ x_shift = overlap.x1 - area.x1
+ if (self._absolute_transform.dy < 0) != flip_y:
+ y_shift = area.y2 - overlap.y2
+ else:
+ y_shift = overlap.y1 - area.y1
+
+ if self._transpose_xy != self._absolute_transform.transpose_xy:
+ x_stride, y_stride = y_stride, x_stride
+ x_shift, y_shift = y_shift, x_shift
+
+ pixels_per_byte = 8 // colorspace.depth
+
+ input_pixel = InputPixelStruct()
+ output_pixel = OutputPixelStruct()
+ for input_pixel.y in range(start_y, end_y):
+ row_start = (
+ start + (input_pixel.y - start_y + y_shift) * y_stride
+ ) # In Pixels
+ local_y = input_pixel.y // self._absolute_transform.scale
+ for input_pixel.x in range(start_x, end_x):
+ offset = (
+ row_start + (input_pixel.x - start_x + x_shift) * x_stride
+ ) # In Pixels
+
+ # Check the mask first to see if the pixel has already been set
+ if mask[offset // 32] & (1 << (offset % 32)):
+ continue
+ local_x = input_pixel.x // self._absolute_transform.scale
+ tile_location = (
+ (local_y // self._tile_height + self._top_left_y)
+ % self._height_in_tiles
+ ) * self._width_in_tiles + (
+ local_x // self._tile_width + self._top_left_x
+ ) % self._width_in_tiles
+ input_pixel.tile = tiles[tile_location]
+ input_pixel.tile_x = (
+ input_pixel.tile % self._bitmap_width_in_tiles
+ ) * self._tile_width + local_x % self._tile_width
+ input_pixel.tile_y = (
+ input_pixel.tile // self._bitmap_width_in_tiles
+ ) * self._tile_height + local_y % self._tile_height
+
+ input_pixel.pixel = self.bitmap[input_pixel.tile_x, input_pixel.tile_y]
+ output_pixel.opaque = True
+
+ if self._pixel_shader is None:
+ output_pixel.pixel = input_pixel.pixel
+ elif isinstance(self._pixel_shader, Palette):
+ self._pixel_shader._get_color( # pylint: disable=protected-access
+ colorspace, input_pixel, output_pixel
+ )
+ elif isinstance(self._pixel_shader, ColorConverter):
+ self._pixel_shader._convert( # pylint: disable=protected-access
+ colorspace, input_pixel, output_pixel
+ )
+
+ if not output_pixel.opaque:
+ full_coverage = False
+ else:
+ mask[offset // 32] |= 1 << (offset % 32)
+ if colorspace.depth == 16:
+ buffer = (
+ buffer[:offset]
+ + struct.pack("H", output_pixel.pixel)
+ + buffer[offset + 2 :]
+ )
+ elif colorspace.depth == 32:
+ buffer = (
+ buffer[:offset]
+ + struct.pack("I", output_pixel.pixel)
+ + buffer[offset + 4 :]
+ )
+ elif colorspace.depth == 8:
+ buffer[offset] = output_pixel.pixel & 0xFF
+ elif colorspace.depth < 8:
+ # Reorder the offsets to pack multiple rows into
+ # a byte (meaning they share a column).
+ if not colorspace.pixels_in_byte_share_row:
+ width = area.width()
+ row = offset // width
+ col = offset % width
+ # Dividing by pixels_per_byte does truncated division
+ # even if we multiply it back out
+ offset = (
+ col * pixels_per_byte
+ + (row // pixels_per_byte) * width
+ + (row % pixels_per_byte)
+ )
+ shift = (offset % pixels_per_byte) * colorspace.depth
+ if colorspace.reverse_pixels_in_byte:
+ # Reverse the shift by subtracting it from the leftmost shift
+ shift = (pixels_per_byte - 1) * colorspace.depth - shift
+ buffer[offset // pixels_per_byte] |= output_pixel.pixel << shift
+ return full_coverage