初始化奇妙小屏幕控制器项目
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
from PIL import Image
|
||||
|
||||
VALID_ORIENTATIONS = {0, 90, 180, 270}
|
||||
DEFAULT_ROW_BIT_ORDER = (0, 1, 2, 3, 4)
|
||||
|
||||
|
||||
def apply_orientation(image: Image.Image, orientation: int) -> Image.Image:
|
||||
if orientation not in VALID_ORIENTATIONS:
|
||||
raise ValueError("orientation must be one of 0, 90, 180, 270")
|
||||
|
||||
if orientation == 0:
|
||||
return image.copy()
|
||||
if orientation == 90:
|
||||
return image.transpose(Image.Transpose.ROTATE_270)
|
||||
if orientation == 180:
|
||||
return image.transpose(Image.Transpose.ROTATE_180)
|
||||
return image.transpose(Image.Transpose.ROTATE_90)
|
||||
|
||||
|
||||
def get_row_bit_order() -> tuple[int, int, int, int, int]:
|
||||
raw = os.environ.get("MATRIX_ROW_BIT_ORDER", "").strip()
|
||||
if not raw:
|
||||
return DEFAULT_ROW_BIT_ORDER
|
||||
|
||||
try:
|
||||
values = tuple(int(part.strip()) for part in raw.split(","))
|
||||
except ValueError as exc:
|
||||
raise ValueError("MATRIX_ROW_BIT_ORDER must be five comma-separated integers") from exc
|
||||
|
||||
if len(values) != 5 or sorted(values) != [0, 1, 2, 3, 4]:
|
||||
raise ValueError("MATRIX_ROW_BIT_ORDER must be a permutation of 0,1,2,3,4")
|
||||
return values
|
||||
|
||||
|
||||
def apply_row_bit_order(image: Image.Image, bit_order: tuple[int, int, int, int, int]) -> Image.Image:
|
||||
if bit_order == DEFAULT_ROW_BIT_ORDER:
|
||||
return image.copy()
|
||||
|
||||
width, height = image.size
|
||||
if height % 32 != 0:
|
||||
raise ValueError("row bit remap requires a display height divisible by 32")
|
||||
|
||||
remapped = Image.new("RGB", image.size)
|
||||
for y in range(height):
|
||||
scan_row = y & 31
|
||||
half_offset = y - scan_row
|
||||
physical_scan_row = _permute_low_five_bits(scan_row, bit_order)
|
||||
source_y = half_offset + physical_scan_row
|
||||
remapped.paste(image.crop((0, source_y, width, source_y + 1)), (0, y))
|
||||
return remapped
|
||||
|
||||
|
||||
def _permute_low_five_bits(value: int, bit_order: tuple[int, int, int, int, int]) -> int:
|
||||
result = 0
|
||||
for driver_bit, physical_bit in enumerate(bit_order):
|
||||
if value & (1 << driver_bit):
|
||||
result |= 1 << physical_bit
|
||||
return result
|
||||
Reference in New Issue
Block a user