Created
February 10, 2025 21:14
-
-
Save FoamyGuy/3e2294b499214954d6b2f66c46537928 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
""" | |
Mirror a scaled copy of the framebuffer to 64x32 matrices, | |
The upper left corner of the framebuffer is displayed until the user hits ctrl-c. | |
Control scale, matrix size, and orientation with command line arguments. | |
python fbmirror_scaled.py [scale] [width] [height] [orientation] | |
scale int: How many times to scale down the display framebuffer. Default is 3. | |
width int: Total width of matrices in pixels. Default is 64. | |
height int: Total height of matrices in pixels. Default is 32. | |
orientation int: Orientation in degrees, must be 0, 90, 180, or 270. | |
Default is 0 or Normal orientation. | |
The `/dev/fb0` special file will exist if a monitor is plugged in at boot time, | |
or if `/boot/firmware/cmdline.txt` specifies a resolution such as | |
`... video=HDMI-A-1:640x480M@60D`. | |
""" | |
import sys | |
import adafruit_raspberry_pi5_piomatter as piomatter | |
import numpy as np | |
import PIL.Image as Image | |
import click | |
import piomatter_click | |
with open("/sys/class/graphics/fb0/virtual_size") as f: | |
screenx, screeny = [int(word) for word in f.read().split(",")] | |
with open("/sys/class/graphics/fb0/bits_per_pixel") as f: | |
bits_per_pixel = int(f.read()) | |
assert bits_per_pixel == 16 | |
bytes_per_pixel = bits_per_pixel // 8 | |
dtype = {2: np.uint16, 4: np.uint32}[bytes_per_pixel] | |
with open("/sys/class/graphics/fb0/stride") as f: | |
stride = int(f.read()) | |
linux_framebuffer = np.memmap('/dev/fb0',mode='r', shape=(screeny, stride // bytes_per_pixel), dtype=dtype) | |
@click.command | |
@click.option("--x-offset", "xoffset", type=int, help="The x offset of top left corner of the region to mirror", default=0) | |
@click.option("--y-offset", "yoffset", type=int, help="The y offset of top left corner of the region to mirror", default=0) | |
@click.option("--scale", "scale", type=int, help="The scale factor to reduce the display down by.", default=3) | |
@piomatter_click.standard_options | |
def main(xoffset, yoffset, scale, width, height, serpentine, rotation, colorspace, pinout, n_planes, n_addr_lines): | |
geometry = piomatter.Geometry(width=width, height=height, n_planes=n_planes, n_addr_lines=n_addr_lines, rotation=rotation) | |
matrix_framebuffer = np.zeros(shape=(geometry.height, geometry.width, 3), dtype=dtype) | |
matrix = piomatter.PioMatter(colorspace=colorspace, pinout=pinout, framebuffer=matrix_framebuffer, geometry=geometry) | |
while True: | |
tmp = linux_framebuffer[yoffset:yoffset + height * scale, xoffset:xoffset + width * scale] | |
# Convert the RGB565 framebuffer into RGB888Packed (so that we can use PIL image operations to rescale it) | |
r = (tmp & 0xf800) >> 8 | |
r = r | (r >> 5) | |
r = r.astype(np.uint8) | |
g = (tmp & 0x07e0) >> 3 | |
g = g | (g >> 6) | |
g = g.astype(np.uint8) | |
b = (tmp & 0x001f) << 3 | |
b = b | (b >> 5) | |
b = b.astype(np.uint8) | |
img = Image.fromarray(np.stack([r, g, b], -1)) | |
img = img.resize((width, height)) | |
print(img.mode) | |
#np_arr = np.asarray(img) | |
np_arr = np.array(img) | |
print(f"matrix fb: {matrix_framebuffer.shape} np_arr: {np_arr.shape}") | |
matrix_framebuffer[:, :] = np_arr | |
matrix.show() | |
if __name__ == '__main__': | |
main() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment