Files
waveform-draw/draw_12_rects_and_send.py
Your Name 25c4054dbc wire
2025-12-12 23:15:50 +00:00

131 lines
5.3 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_thick_outline.py
800×600 ARGB framebuffer.
12 tall rectangles (aspect1:12) placed sidebyside with a gap.
Only the rectangle outline is drawn, the border thickness can be changed
with the constant LINE_THICKNESS (default = 3 pixels).
The complete framebuffer is streamed to a TCP server listening on
localhost:12345 (payload is prefixed with a 4byte bigendian length).
"""
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
# ----------------------------------------------------------------------
RECT_HEIGHT = 400 # fill the whole image vertically
RECT_WIDTH = RECT_HEIGHT // 12 # 600 / 12 = 50px (maintains 1:12)
SPACING = 10 # pixels between two neighbours
TOTAL_RECT_W = 12 * RECT_WIDTH + 11 * SPACING
X0_START = (FB_WIDTH - TOTAL_RECT_W) // 2 # centre the whole strip
# ----------------------------------------------------------------------
# Outline thickness (change this to whatever you need)
# ----------------------------------------------------------------------
LINE_THICKNESS = 4 # >=1 ; thicker than 1 pixel
# ----------------------------------------------------------------------
# Helper write a pixel into the bytearray (no bounds check for speed)
# ----------------------------------------------------------------------
def set_pixel(buf: bytearray, x: int, y: int, color: tuple) -> None:
"""Write an ARGB pixel at (x, y). `color` = (A,R,G,B)."""
offset = (y * FB_WIDTH + x) * BPP
buf[offset:offset + 4] = bytes(color) # A,R,G,B order
# ----------------------------------------------------------------------
# Fill a rectangular region (used for thick edges)
# ----------------------------------------------------------------------
def fill_rect(buf: bytearray, x0: int, y0: int, w: int, h: int, color: tuple) -> None:
"""Write a solid w×h block of `color` starting at (x0, y0)."""
# Clip to the frame buffer safety net for very thick lines at the border
x0 = max(0, x0)
y0 = max(0, y0)
w = min(w, FB_WIDTH - x0)
h = min(h, FB_HEIGHT - y0)
row_bytes = w * BPP
pixel_bytes = bytes(color)
for y in range(y0, y0 + h):
off = (y * FB_WIDTH + x0) * BPP
buf[off:off + row_bytes] = pixel_bytes * w
# ----------------------------------------------------------------------
# Build the framebuffer
# ----------------------------------------------------------------------
def build_framebuffer() -> bytearray:
"""Create an ARGB buffer, fill it black and draw the thickoutline rectangles."""
# 1⃣ background = opaque black (A,R,G,B)
fb = bytearray(FB_WIDTH * FB_HEIGHT * BPP)
bg_color = (255, 0, 0, 0) # opaque black
fb[:] = bg_color * (FB_WIDTH * FB_HEIGHT)
# 2⃣ draw each rectangle outline
for idx in range(12):
# ── colour palette (feel free to change) ───────────────────────
rect_color = (255, 255, 255, 255) # opaque
# leftmost X coordinate of the *inner* rectangle (the border belongs to it)
x0 = X0_START + idx * (RECT_WIDTH + SPACING)
y0 = 100
w = RECT_WIDTH
h = RECT_HEIGHT
# ── thick edges ──────────────────────────────────────────────────
# top edge
fill_rect(fb, x0, y0, w, LINE_THICKNESS, rect_color)
# bottom edge
fill_rect(fb, x0, y0 + h - LINE_THICKNESS, w, LINE_THICKNESS, rect_color)
# left edge
fill_rect(fb, x0, y0, LINE_THICKNESS, h, rect_color)
# right edge
fill_rect(fb, x0 + w - LINE_THICKNESS, y0, LINE_THICKNESS, h, rect_color)
return fb
# ----------------------------------------------------------------------
# Send the buffer to the TCP server
# ----------------------------------------------------------------------
def send_framebuffer(buf: bytearray,
host: str = "127.0.0.1",
port: int = 12345) -> None:
"""Open a TCP socket, connect, and stream the whole framebuffer."""
try:
with socket.create_connection((host, port), timeout=5) as sock:
# optional length prefix (many protocols expect it)
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() -> None:
fb = build_framebuffer()
send_framebuffer(fb)
if __name__ == "__main__":
main()