Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| # pygame_fixed_format.py - Fixed byte order | |
| import pygame,os | |
| import numpy as np | |
| import time | |
| import threading | |
| from flask import Flask, Response | |
| import io | |
| # Setup | |
| os.environ['SDL_VIDEODRIVER'] = 'dummy' | |
| WIDTH, HEIGHT = 400, 300 | |
| app = Flask(__name__) | |
| # Shared state | |
| frame_data = { | |
| "jpeg_bytes": None, # Store as JPEG for smaller size | |
| "frame_id": 0, | |
| "lock": threading.Lock() | |
| } | |
| def index(): | |
| return '''<!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>PyGame Stream</title> | |
| <meta http-equiv="refresh" content="0.1"> | |
| <style>body { margin: 0; padding: 20px; text-align: center; }</style> | |
| </head> | |
| <body> | |
| <h1>Auto-Refresh (10 FPS)</h1> | |
| <img src="/frame" width="400" height="300" style="border:3px solid blue;"> | |
| <p>Refreshing every 100ms...</p> | |
| </body> | |
| </html>''' | |
| def get_frame(): | |
| """Return frame as JPEG (smaller, faster)""" | |
| with frame_data["lock"]: | |
| if frame_data["jpeg_bytes"]: | |
| return Response( | |
| frame_data["jpeg_bytes"], | |
| mimetype='image/jpeg', | |
| headers={'Cache-Control': 'no-cache'} | |
| ) | |
| # Return loading image | |
| return create_loading_image() | |
| def create_loading_image(): | |
| """Create a simple loading image""" | |
| from PIL import Image, ImageDraw | |
| import io as imageio | |
| img = Image.new('RGB', (WIDTH, HEIGHT), color='blue') | |
| draw = ImageDraw.Draw(img) | |
| draw.text((150, 140), 'LOADING...', fill='white') | |
| buffer = imageio.BytesIO() | |
| img.save(buffer, 'JPEG') | |
| return Response(buffer.getvalue(), mimetype='image/jpeg') | |
| def pygame_render(): | |
| """PyGame render loop with FIXED format""" | |
| print("π¬ Starting PyGame with fixed format...") | |
| try: | |
| pygame.init() | |
| surface = pygame.Surface((WIDTH, HEIGHT)) | |
| print("β PyGame initialized") | |
| except Exception as e: | |
| print(f"β PyGame init failed: {e}") | |
| return | |
| # Simple bouncing balls (fewer for clarity) | |
| balls = [ | |
| {'x': 100, 'y': 150, 'dx': 3, 'dy': 2, 'r': 20, 'color': (255, 100, 100)}, | |
| {'x': 300, 'y': 100, 'dx': -2, 'dy': 3, 'r': 15, 'color': (100, 255, 100)}, | |
| {'x': 200, 'y': 200, 'dx': 4, 'dy': -1, 'r': 25, 'color': (100, 100, 255)}, | |
| ] | |
| print("β Created 3 bouncing balls") | |
| frame_id = 0 | |
| while True: | |
| # Clear | |
| surface.fill((30, 30, 50)) | |
| # Draw grid background | |
| for x in range(0, WIDTH, 40): | |
| pygame.draw.line(surface, (50, 50, 70), (x, 0), (x, HEIGHT), 1) | |
| for y in range(0, HEIGHT, 40): | |
| pygame.draw.line(surface, (50, 50, 70), (0, y), (WIDTH, y), 1) | |
| # Update and draw balls | |
| for ball in balls: | |
| ball['x'] += ball['dx'] | |
| ball['y'] += ball['dy'] | |
| if ball['x'] < ball['r'] or ball['x'] > WIDTH - ball['r']: | |
| ball['dx'] = -ball['dx'] | |
| if ball['y'] < ball['r'] or ball['y'] > HEIGHT - ball['r']: | |
| ball['dy'] = -ball['dy'] | |
| # Draw ball | |
| pygame.draw.circle(surface, ball['color'], | |
| (int(ball['x']), int(ball['y'])), ball['r']) | |
| # Draw outline | |
| pygame.draw.circle(surface, (255, 255, 255), | |
| (int(ball['x']), int(ball['y'])), ball['r'], 2) | |
| # Add text | |
| font = pygame.font.Font(None, 24) | |
| texts = [ | |
| f"Frame: {frame_id}", | |
| f"Balls: {len(balls)}", | |
| time.strftime("%H:%M:%S") | |
| ] | |
| for i, text in enumerate(texts): | |
| text_surface = font.render(text, True, (255, 255, 255)) | |
| surface.blit(text_surface, (10, 10 + i * 25)) | |
| # === FIX 1: Convert to JPEG (smaller, browser-friendly) === | |
| import io | |
| buffer = io.BytesIO() | |
| pygame.image.save(surface, buffer, 'JPEG') | |
| jpeg_bytes = buffer.getvalue() | |
| # Update shared state | |
| with frame_data["lock"]: | |
| frame_data["jpeg_bytes"] = jpeg_bytes | |
| frame_data["frame_id"] = frame_id | |
| frame_id += 1 | |
| if frame_id % 30 == 0: | |
| print(f"πΈ Frame {frame_id} ({len(jpeg_bytes)} bytes)") | |
| # Fixed 30 FPS | |
| time.sleep(1/30) | |
| # Start render thread | |
| threading.Thread(target=pygame_render, daemon=True).start() | |
| # Wait for initialization | |
| time.sleep(2) | |
| print("π Starting Flask...") | |
| app.run(host='0.0.0.0', port=7860, threaded=True, use_reloader=False) |