Files
waveform-draw/draw_12_rects_and_send.py
2025-12-12 22:56:30 +00:00

102 lines
4.0 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
draw_12_rects_and_send.py
* 800×600 framebuffer, 32bit ARGB (A,R,G,B each 1byte)
* 12 rectangles, aspect ratio width:height = 1:12 (tall, upright)
* rectangles are placed sidebyside, centred in the image
* the complete framebuffer is sent over a TCP connection to
a server listening on localhost:12345
"""
import socket
import sys
# ----------------------------------------------------------------------
# Framebuffer configuration
# ----------------------------------------------------------------------
FB_WIDTH = 800 # horizontal pixels
FB_HEIGHT = 600 # vertical pixels
BPP = 4 # bytes per pixel (A,R,G,B)
# ----------------------------------------------------------------------
# Geometry of the 12 rectangles
# ----------------------------------------------------------------------
# Height of a rectangle must fill the whole image (600 px)
# width = height / 12 → 600 / 12 = 50 px
RECT_HEIGHT = FB_HEIGHT // 2
RECT_WIDTH = RECT_HEIGHT // 12 # 50
SPACING = 20
TOTAL_RECT_W = (11 * SPACING) + (RECT_WIDTH * 12) # 600
X0_START = (FB_WIDTH - TOTAL_RECT_W) // 2 # centre the strip
# ----------------------------------------------------------------------
# Helper write a pixel into the bytearray (no bounds check for speed)
# ----------------------------------------------------------------------
def set_pixel(buf: bytearray, x: int, y: int, color: tuple):
"""Write an ARGB pixel at (x,y).
`color` is a 4tuple (A,R,G,B) with each component 0255.
"""
offset = (y * FB_WIDTH + x) * BPP
buf[offset:offset+4] = bytes(color) # A,R,G,B order
# ----------------------------------------------------------------------
# Build the framebuffer
# ----------------------------------------------------------------------
def build_framebuffer() -> bytearray:
"""Create an ARGB buffer, fill it black and draw the 12 rectangles."""
fb = bytearray(FB_WIDTH * FB_HEIGHT * BPP)
# ------------------------------------------------------------------
# 1) background = solid black, fully opaque
# ------------------------------------------------------------------
bg_color = (255, 0, 0, 0) # A,R,G,B
# Fill the whole buffer in one go (faster than perpixel loop)
fb[:] = bg_color * (FB_WIDTH * FB_HEIGHT)
# ------------------------------------------------------------------
# 2) draw the 12 rectangles
# ------------------------------------------------------------------
for idx in range(12):
rect_color = (255, 255, 255, 255) # opaque
x_start = X0_START + idx * (RECT_WIDTH + SPACING)
x_end = x_start + RECT_WIDTH # exclusive
for y in range(FB_HEIGHT):
# sliceassignment is faster than perpixel calls
row_offset = (y * FB_WIDTH + x_start) * BPP
fb[row_offset:row_offset + RECT_WIDTH * BPP] = rect_color * RECT_WIDTH
return fb
# ----------------------------------------------------------------------
# Send the buffer to the TCP server
# ----------------------------------------------------------------------
def send_framebuffer(buf: bytearray, host: str = "127.0.0.1", port: int = 12345):
"""Open a TCP socket, connect, and stream the whole framebuffer."""
try:
with socket.create_connection((host, port), timeout=5) as sock:
# Optional: prefix the payload with its length (bigendian uint32)
length_prefix = len(buf).to_bytes(4, byteorder="big")
sock.sendall(length_prefix + buf)
print(f"Sent {len(buf)} bytes to {host}:{port}")
except Exception as exc:
print(f"Could not send framebuffer: {exc}", file=sys.stderr)
# ----------------------------------------------------------------------
# Main entry point
# ----------------------------------------------------------------------
def main():
fb = build_framebuffer()
send_framebuffer(fb)
if __name__ == "__main__":
main()